From 8e4f155a16f77c2602d20b549bf55a56a6d688a8 Mon Sep 17 00:00:00 2001 From: Ruben Fischer Date: Wed, 18 Feb 2026 19:59:14 +0100 Subject: [PATCH] Improved features, implemented moco integration --- Angebot.pdf | Bin 0 -> 102741 bytes src/config.py | 4 + src/database/client.py | 115 ++++++- src/database/models.py | 15 + src/services/email_service.py | 55 +-- src/services/moco_service.py | 272 +++++++++++++++ src/services/scheduler_service.py | 30 ++ src/web/admin/routes.py | 388 +++++----------------- src/web/templates/admin/license_keys.html | 256 +++++++++++--- src/web/templates/user/post_detail.html | 23 +- src/web/user/routes.py | 96 +++--- 11 files changed, 827 insertions(+), 427 deletions(-) create mode 100644 Angebot.pdf create mode 100644 src/services/moco_service.py diff --git a/Angebot.pdf b/Angebot.pdf new file mode 100644 index 0000000000000000000000000000000000000000..adeb329cb3420d7cfd21fa9e867647a0ad1c5bcc GIT binary patch literal 102741 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⩔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 literal 0 HcmV?d00001 diff --git a/src/config.py b/src/config.py index 4082f49..8bfb946 100644 --- a/src/config.py +++ b/src/config.py @@ -61,6 +61,10 @@ class Settings(BaseSettings): # Token Encryption encryption_key: str = "" # Generate with: python -c "from cryptography.fernet import Fernet; print(Fernet.generate_key().decode())" + # MOCO Integration + moco_api_key: str = "" # Token für Authorization-Header + moco_domain: str = "" # Subdomain: {domain}.mocoapp.com + model_config = SettingsConfigDict( env_file=".env", env_file_encoding="utf-8", diff --git a/src/database/client.py b/src/database/client.py index 15d0a84..0d438fc 100644 --- a/src/database/client.py +++ b/src/database/client.py @@ -11,7 +11,7 @@ from src.database.models import ( LinkedInProfile, LinkedInPost, Topic, ProfileAnalysis, ResearchResult, GeneratedPost, PostType, User, Profile, Company, Invitation, ExamplePost, ReferenceProfile, - ApiUsageLog, LicenseKey, CompanyDailyQuota + ApiUsageLog, LicenseKey, CompanyDailyQuota, LicenseKeyOffer ) @@ -1252,6 +1252,59 @@ class DatabaseClient: ) logger.info(f"Deleted license key: {key_id}") + # ==================== LICENSE KEY OFFERS ==================== + + async def create_license_key_offer( + self, + license_key_id: UUID, + moco_offer_id: int, + moco_offer_identifier: Optional[str], + moco_offer_url: Optional[str], + offer_title: Optional[str], + company_name: Optional[str], + price: Optional[float], + payment_frequency: Optional[str], + ) -> "LicenseKeyOffer": + """Save a MOCO offer linked to a license key.""" + data = { + "license_key_id": str(license_key_id), + "moco_offer_id": moco_offer_id, + "moco_offer_identifier": moco_offer_identifier, + "moco_offer_url": moco_offer_url, + "offer_title": offer_title, + "company_name": company_name, + "price": price, + "payment_frequency": payment_frequency, + "status": "draft", + } + result = await asyncio.to_thread( + lambda: self.client.table("license_key_offers").insert(data).execute() + ) + return LicenseKeyOffer(**result.data[0]) + + async def list_license_key_offers(self, license_key_id: UUID) -> list["LicenseKeyOffer"]: + """List all MOCO offers for a license key.""" + result = await asyncio.to_thread( + lambda: self.client.table("license_key_offers") + .select("*") + .eq("license_key_id", str(license_key_id)) + .order("created_at", desc=True) + .execute() + ) + return [LicenseKeyOffer(**row) for row in result.data] + + async def update_license_key_offer_status( + self, offer_id: UUID, status: str + ) -> "LicenseKeyOffer": + """Update the status of a stored offer.""" + result = await asyncio.to_thread( + lambda: self.client.table("license_key_offers") + .update({"status": status}) + .eq("id", str(offer_id)) + .execute() + ) + return LicenseKeyOffer(**result.data[0]) + # ==================== COMPANY QUOTAS ==================== async def get_company_daily_quota( @@ -1356,6 +1409,66 @@ class DatabaseClient: return True, "" + # ==================== EMAIL ACTION TOKENS ==================== + + async def create_email_token(self, token: str, post_id: UUID, action: str, expires_hours: int = 72) -> None: + """Store an email action token in the database.""" + from datetime import timedelta + expires_at = datetime.now(timezone.utc) + timedelta(hours=expires_hours) + data = { + "token": token, + "post_id": str(post_id), + "action": action, + "expires_at": expires_at.isoformat(), + "used": False, + } + await asyncio.to_thread( + lambda: self.client.table("email_action_tokens").insert(data).execute() + ) + logger.debug(f"Created email token for post {post_id} action={action}") + + async def get_email_token(self, token: str) -> Optional[Dict[str, Any]]: + """Retrieve email token data; returns None if not found.""" + result = await asyncio.to_thread( + lambda: self.client.table("email_action_tokens").select("*").eq("token", token).execute() + ) + if not result.data: + return None + return result.data[0] + + async def mark_email_token_used(self, token: str) -> None: + """Mark an email token as used.""" + await asyncio.to_thread( + lambda: self.client.table("email_action_tokens").update({"used": True}).eq("token", token).execute() + ) + + async def cleanup_expired_email_tokens(self) -> None: + """Delete expired email tokens from the database.""" + now = datetime.now(timezone.utc).isoformat() + result = await asyncio.to_thread( + lambda: self.client.table("email_action_tokens").delete().lt("expires_at", now).execute() + ) + count = len(result.data) if result.data else 0 + if count: + logger.info(f"Cleaned up {count} expired email tokens") + + # ==================== LINKEDIN TOKEN REFRESH ==================== + + async def get_expiring_linkedin_accounts(self, within_days: int = 7) -> list: + """Return active LinkedIn accounts whose tokens expire within within_days and have a refresh_token.""" + from src.database.models import LinkedInAccount + from datetime import timedelta + cutoff = (datetime.now(timezone.utc) + timedelta(days=within_days)).isoformat() + result = await asyncio.to_thread( + lambda: self.client.table("linkedin_accounts") + .select("*") + .eq("is_active", True) + .lt("token_expires_at", cutoff) + .not_.is_("refresh_token", "null") + .execute() + ) + return [LinkedInAccount(**row) for row in result.data] + # Global database client instance db = DatabaseClient() diff --git a/src/database/models.py b/src/database/models.py index 98e2fd1..dbfb755 100644 --- a/src/database/models.py +++ b/src/database/models.py @@ -376,6 +376,21 @@ class LicenseKey(DBModel): updated_at: Optional[datetime] = None +class LicenseKeyOffer(DBModel): + """MOCO offer created for a license key.""" + id: Optional[UUID] = None + license_key_id: UUID + moco_offer_id: int + moco_offer_identifier: Optional[str] = None + moco_offer_url: Optional[str] = None + offer_title: Optional[str] = None + company_name: Optional[str] = None + price: Optional[float] = None + payment_frequency: Optional[str] = None + status: str = "draft" + created_at: Optional[datetime] = None + + class CompanyDailyQuota(DBModel): """Daily usage quota for a company.""" id: Optional[UUID] = None diff --git a/src/services/email_service.py b/src/services/email_service.py index 3f9d505..72da2ec 100644 --- a/src/services/email_service.py +++ b/src/services/email_service.py @@ -6,48 +6,49 @@ from email.mime.multipart import MIMEMultipart from email.mime.base import MIMEBase from email import encoders from typing import Optional, Dict, Any -from datetime import datetime, timedelta +from datetime import datetime, timezone from uuid import UUID from loguru import logger from src.config import settings -# In-memory token store (in production, use Redis or database) -_email_tokens: Dict[str, Dict[str, Any]] = {} - -def generate_token(post_id: UUID, action: str, expires_hours: int = 72) -> str: - """Generate a unique token for email action.""" +async def generate_token(post_id: UUID, action: str, expires_hours: int = 72) -> str: + """Generate a unique token for email action and persist it to the database.""" + from src.database.client import db token = secrets.token_urlsafe(32) - _email_tokens[token] = { - "post_id": str(post_id), - "action": action, - "expires_at": datetime.utcnow() + timedelta(hours=expires_hours), - "used": False - } + await db.create_email_token(token, post_id, action, expires_hours) return token -def validate_token(token: str) -> Optional[Dict[str, Any]]: - """Validate and return token data if valid.""" - if token not in _email_tokens: +async def validate_token(token: str) -> Optional[Dict[str, Any]]: + """Validate and return token data if valid (checks DB).""" + from src.database.client import db + token_data = await db.get_email_token(token) + if not token_data: return None - token_data = _email_tokens[token] - - if token_data["used"]: + if token_data.get("used"): return None - if datetime.utcnow() > token_data["expires_at"]: - return None + expires_at_raw = token_data.get("expires_at") + if expires_at_raw: + if isinstance(expires_at_raw, str): + expires_at = datetime.fromisoformat(expires_at_raw.replace("Z", "+00:00")) + else: + expires_at = expires_at_raw + if not expires_at.tzinfo: + expires_at = expires_at.replace(tzinfo=timezone.utc) + if datetime.now(timezone.utc) > expires_at: + return None return token_data -def mark_token_used(token: str): - """Mark a token as used.""" - if token in _email_tokens: - _email_tokens[token]["used"] = True +async def mark_token_used(token: str) -> None: + """Mark a token as used in the database.""" + from src.database.client import db + await db.mark_email_token_used(token) def send_email(to_email: str, subject: str, html_content: str) -> bool: @@ -119,7 +120,7 @@ def send_email_with_attachment( return False -def send_approval_request_email( +async def send_approval_request_email( to_email: str, post_id: UUID, post_title: str, @@ -128,8 +129,8 @@ def send_approval_request_email( image_url: Optional[str] = None ) -> bool: """Send email to customer requesting approval of a post.""" - approve_token = generate_token(post_id, "approve") - reject_token = generate_token(post_id, "reject") + approve_token = await generate_token(post_id, "approve") + reject_token = await generate_token(post_id, "reject") approve_url = f"{base_url}/api/email-action/{approve_token}" reject_url = f"{base_url}/api/email-action/{reject_token}" diff --git a/src/services/moco_service.py b/src/services/moco_service.py new file mode 100644 index 0000000..e4b1168 --- /dev/null +++ b/src/services/moco_service.py @@ -0,0 +1,272 @@ +"""MOCO API integration for offer creation.""" +from datetime import datetime, timedelta +from typing import Optional + +import httpx +from loguru import logger + +from src.config import settings + + +def _headers() -> dict: + return { + "Authorization": f"Token token={settings.moco_api_key}", + "Content-Type": "application/json", + } + + +def _base_url() -> str: + return f"https://{settings.moco_domain}.mocoapp.com/api/v1" + + +async def search_moco_companies(term: str) -> list[dict]: + """Search MOCO companies by name term. + + Returns a list of dicts with keys: id, name. + """ + if not settings.moco_api_key or not settings.moco_domain: + logger.warning("MOCO not configured (moco_api_key / moco_domain missing)") + return [] + + params = {"type": "customer"} + if term: + params["term"] = term + + try: + async with httpx.AsyncClient(timeout=10.0) as client: + response = await client.get( + f"{_base_url()}/companies", + headers=_headers(), + params=params, + ) + response.raise_for_status() + companies = response.json() + return [{"id": c["id"], "name": c["name"]} for c in companies] + except httpx.HTTPStatusError as e: + logger.error(f"MOCO companies search failed ({e.response.status_code}): {e.response.text}") + raise + except Exception as e: + logger.error(f"MOCO companies search error: {e}") + raise + + +async def _get_company_details(company_id: int) -> Optional[dict]: + """Fetch a MOCO company by ID. Returns the company dict or None.""" + try: + async with httpx.AsyncClient(timeout=10.0) as client: + response = await client.get( + f"{_base_url()}/companies/{company_id}", + headers=_headers(), + ) + response.raise_for_status() + return response.json() + except Exception as e: + logger.warning(f"Could not fetch MOCO company {company_id}: {e}") + return None + + +async def _get_company_contact(company_id: int, company_name: str) -> Optional[dict]: + """Return the first contact person associated with the given MOCO company. + + MOCO's /contacts/people has no company_id filter, so we search by company + name and then filter client-side on company.id. + """ + try: + async with httpx.AsyncClient(timeout=10.0) as client: + response = await client.get( + f"{_base_url()}/contacts/people", + headers=_headers(), + params={"term": company_name}, + ) + response.raise_for_status() + people = response.json() + + # Filter to contacts whose company.id matches exactly + matched = [ + p for p in people + if (p.get("company") or {}).get("id") == company_id + ] + contact = matched[0] if matched else None + if contact: + logger.debug( + f"MOCO contact for company {company_id}: " + f"gender={contact.get('gender')!r} lastname={contact.get('lastname')!r}" + ) + else: + logger.debug(f"No contact found for MOCO company {company_id} ({company_name!r})") + return contact + except Exception as e: + logger.warning(f"Could not fetch MOCO contacts for company {company_id}: {e}") + return None + + +def _build_salutation_html(contact: Optional[dict]) -> str: + """Build an HTML salutation block from a MOCO contact dict.""" + if not contact: + greeting = "Sehr geehrte Damen und Herren" + else: + gender = (contact.get("gender") or "").strip().upper() + lastname = (contact.get("lastname") or "").strip() + logger.debug(f"MOCO contact gender={gender!r} lastname={lastname!r}") + + if gender == "M": + greeting = f"Sehr geehrter Herr {lastname}".strip() + elif gender == "F": + greeting = f"Sehr geehrte Frau {lastname}".strip() + else: + greeting = "Sehr geehrte Damen und Herren" + + return ( + f"

{greeting},

" + "

vielen Dank für Ihre Anfrage. Anbei finden Sie ein ausgearbeitetes Angebot " + "für die von Ihnen angefragten Leistungen.

" + ) + + +def _build_footer_html() -> str: + """Build the HTML footer using MOCO's native {customer_approval_link} variable. + + MOCO replaces {customer_approval_link} with a properly formatted and + clickable link at render/send time. Using a manual tag causes MOCO + to override the link text with its own '[identifier] Angebot' format. + """ + return ( + "

Wir freuen uns über Ihre Bestätigung per E-Mail oder direkt über diesen Link: " + "{customer_approval_link}

" + "

Freundliche Grüße,
" + "Olivia Kibele
" + "olivia.kibele@onyva.de
" + "0751 18523411

" + ) + + +async def create_moco_offer( + company_id: int, + company_name: str, + price: float, + payment_frequency: str, + plan_name: str, + max_employees: int, + daily_token_limit: Optional[int], +) -> dict: + """Create an offer in MOCO and return the full offer object.""" + today = datetime.utcnow().date() + due_date = today + timedelta(days=30) + + # Fetch company details for billing address + contact lookup + company = await _get_company_details(company_id) + recipient_address = ( + (company.get("address") or "").strip() or company_name + if company else company_name + ) + + contact = await _get_company_contact(company_id, company_name) + salutation_html = _build_salutation_html(contact) + + if daily_token_limit: + posts_per_month = int(daily_token_limit * 30 / 50_000) + token_detail = ( + f"{daily_token_limit:,}".replace(",", ".") + + f" Tokens/Tag (ca. {posts_per_month} Posts/Monat)" + ) + else: + token_detail = "Unbegrenzt" + + freq_label = payment_frequency.capitalize() + offer_title = f"LinkedIn Content Automation – {plan_name}" + + description_text = ( + f"LinkedIn Content Automation – {plan_name}\n\n" + f"Lizenzdetails:\n" + f"• Mitarbeiter: {max_employees} Nutzer\n" + f"• KI-Token-Limit: {token_detail}\n" + f"• Zahlungsweise: {freq_label}\n\n" + f"Enthaltene Funktionen:\n" + f"• LinkedIn-Profil-Analyse (KI-gestützt)\n" + f"• Post-Typen & Strategie mit Gewichtung\n" + f"• KI-Post-Erstellung (chat-basiert, iterativ)\n" + f"• Mitarbeiterverwaltung & Freigabe-Workflows\n" + f"• Research-Funktion & Posting-Kalender\n" + f"• E-Mail-Benachrichtigungen" + ) + + payload = { + "company_id": company_id, + "recipient_address": recipient_address, + "date": today.isoformat(), + "due_date": due_date.isoformat(), + "title": offer_title, + "tax": 19.0, + "currency": "EUR", + "discount": 0, + "salutation": salutation_html, + "footer": _build_footer_html(), + "items": [ + { + "type": "description", + "title": "Leistungsbeschreibung", + "description": description_text, + }, + { + "type": "item", + "title": f"Lizenz – {plan_name}", + "description": f"{max_employees} Nutzer · {token_detail} · {freq_label}", + "quantity": 1, + "unit": "Monat" if payment_frequency == "monatlich" else "Pauschal", + "unit_price": price, + "net_total": price, + }, + ], + } + + try: + async with httpx.AsyncClient(timeout=15.0) as client: + response = await client.post( + f"{_base_url()}/offers", + headers=_headers(), + json=payload, + ) + response.raise_for_status() + offer = response.json() + logger.info( + f"MOCO offer created: id={offer.get('id')}, identifier={offer.get('identifier')}" + ) + return offer + + except httpx.HTTPStatusError as e: + logger.error(f"MOCO offer creation failed ({e.response.status_code}): {e.response.text}") + raise + except Exception as e: + logger.error(f"MOCO offer creation error: {e}") + raise + + +async def send_moco_offer(moco_offer_id: int) -> None: + """Send a MOCO offer to its default recipients via email. + + Uses POST /offers/{id}/send_email with empty recipient lists so MOCO + falls back to the default recipients configured on the customer. + """ + payload = { + "subject": "Ihr Angebot – LinkedIn Content Automation", + "text": ( + "Anbei finden Sie unser Angebot für die LinkedIn Content Automation Plattform.\n\n" + "Bitte bestätigen Sie direkt über den Link im Angebot.\n\n" + "Freundliche Grüße,\nOlivia Kibele" + ), + } + try: + async with httpx.AsyncClient(timeout=15.0) as client: + response = await client.post( + f"{_base_url()}/offers/{moco_offer_id}/send_email", + headers=_headers(), + json=payload, + ) + response.raise_for_status() + logger.info(f"MOCO offer {moco_offer_id} sent via email") + except httpx.HTTPStatusError as e: + logger.error(f"MOCO send_email failed ({e.response.status_code}): {e.response.text}") + raise + except Exception as e: + logger.error(f"MOCO send_email error: {e}") + raise diff --git a/src/services/scheduler_service.py b/src/services/scheduler_service.py index 013346e..9f11e8e 100644 --- a/src/services/scheduler_service.py +++ b/src/services/scheduler_service.py @@ -54,14 +54,44 @@ class SchedulerService: async def _run_loop(self): """Main scheduler loop.""" + _tick = 0 while self._running: try: await self._process_due_posts() except Exception as e: logger.error(f"Scheduler error: {e}") + # Daily jobs (every 1440 ticks = 24h at 60s interval) + if _tick % 1440 == 0: + try: + await self._refresh_expiring_tokens() + except Exception as e: + logger.error(f"Token refresh job error: {e}") + try: + await self.db.cleanup_expired_email_tokens() + except Exception as e: + logger.error(f"Email token cleanup error: {e}") + + _tick += 1 await asyncio.sleep(self.check_interval) + async def _refresh_expiring_tokens(self): + """Proactively refresh LinkedIn tokens expiring within 7 days.""" + from src.services.linkedin_service import linkedin_service + accounts = await self.db.get_expiring_linkedin_accounts(within_days=7) + if not accounts: + return + logger.info(f"Refreshing {len(accounts)} expiring LinkedIn tokens") + for account in accounts: + try: + refreshed = await linkedin_service.refresh_access_token(account.id) + if refreshed: + logger.info(f"Token refresh ok: {account.id}") + else: + logger.warning(f"Token refresh failed: {account.id}") + except Exception as e: + logger.error(f"Token refresh error {account.id}: {e}") + async def _process_due_posts(self): """Process all posts that are due for publishing.""" due_posts = await self.db.get_scheduled_posts_due() diff --git a/src/web/admin/routes.py b/src/web/admin/routes.py index f5a4b47..2c60f7f 100644 --- a/src/web/admin/routes.py +++ b/src/web/admin/routes.py @@ -1,9 +1,9 @@ """Admin panel routes (password-protected) - User Management & Statistics.""" +import asyncio import re import secrets import math from datetime import datetime, timedelta -from io import BytesIO from pathlib import Path from typing import Optional from uuid import UUID @@ -14,19 +14,13 @@ from fastapi.templating import Jinja2Templates from fastapi.responses import HTMLResponse, RedirectResponse, JSONResponse from loguru import logger -from reportlab.platypus import SimpleDocTemplate, Paragraph, Spacer, Table, TableStyle, HRFlowable, Image -from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle -from reportlab.lib.units import cm -from reportlab.lib import colors -from reportlab.lib.pagesizes import A4 - from src.database import db from src.web.admin.auth import ( WEB_PASSWORD, AUTH_COOKIE_NAME, hash_password, verify_auth ) from src.web.user.auth import UserSession, set_user_session -from src.services.email_service import send_email_with_attachment from src.config import settings +from src.services import moco_service # Router with /admin prefix admin_router = APIRouter(prefix="/admin", tags=["admin"]) @@ -534,10 +528,20 @@ async def license_keys_page(request: Request): try: keys = await db.list_license_keys() + # Load offers for all keys in parallel + offers_lists = await asyncio.gather( + *[db.list_license_key_offers(k.id) for k in keys], + return_exceptions=True + ) + offers_by_key = { + str(k.id): (v if not isinstance(v, Exception) else []) + for k, v in zip(keys, offers_lists) + } return templates.TemplateResponse("license_keys.html", { "request": request, "page": "license_keys", "keys": keys, + "offers_by_key": offers_by_key, "total_keys": len(keys), "used_keys": len([k for k in keys if k.used]), "available_keys": len([k for k in keys if not k.used]) @@ -626,255 +630,33 @@ async def delete_license_key_route(request: Request, key_id: str): raise HTTPException(status_code=500, detail=str(e)) -# ==================== LICENSE KEY OFFER ==================== - -AVG_TOKENS_PER_POST = 50_000 -SERVER_COST_EUR = 16.0 -SERVER_SHARE_FRACTION = 0.10 # 10% of server costs per customer -API_COST_PER_1K_TOKENS_EUR = 0.003 # rough average API cost in EUR +# ==================== LICENSE KEY OFFER (MOCO) ==================== -def _fmt_eur(amount: float) -> str: - """Format a float as German EUR string, e.g. 1.250,00 €""" - return f"{amount:,.2f} €".replace(",", "X").replace(".", ",").replace("X", ".") +@admin_router.get("/api/moco/companies") +async def search_moco_companies_endpoint(request: Request, term: str = ""): + """Live-search MOCO companies by name.""" + if not verify_auth(request): + raise HTTPException(status_code=401) + + try: + companies = await moco_service.search_moco_companies(term) + return JSONResponse(companies) + except Exception as e: + logger.error(f"MOCO company search error: {e}") + raise HTTPException(status_code=500, detail=str(e)) -def _build_offer_pdf( - key_description: str, - max_employees: int, - daily_token_limit: Optional[int], - price: float, - payment_frequency: str, - recipient_email: str, -) -> bytes: - """Generate a professional, simple PDF offer with logo.""" - buffer = BytesIO() - - PAGE_W, PAGE_H = A4 - MARGIN = 1.8 * cm - - doc = SimpleDocTemplate( - buffer, - pagesize=A4, - rightMargin=MARGIN, - leftMargin=MARGIN, - topMargin=MARGIN, - bottomMargin=MARGIN, - ) - - # ── Colors ──────────────────────────────────────────────────────────────── - C_DARK = colors.HexColor("#2d3838") - C_HIGHLIGHT = colors.HexColor("#ffc700") - C_GRAY = colors.HexColor("#666666") - C_LGRAY = colors.HexColor("#f5f5f5") - C_RULE = colors.HexColor("#e0e0e0") - C_WHITE = colors.white - CONTENT_W = PAGE_W - 2 * MARGIN - HALF_W = (CONTENT_W - 0.3 * cm) / 2 # for 2-col feature grid - - # ── Styles ──────────────────────────────────────────────────────────────── - s = getSampleStyleSheet() - def ps(name, **kw): - return ParagraphStyle(name, parent=s["Normal"], **kw) - - s_body = ps("body", fontSize=9.5, textColor=C_DARK, leading=14) - s_small = ps("sml", fontSize=8, textColor=C_GRAY, leading=12) - s_label = ps("lbl", fontSize=8.5, textColor=C_GRAY, leading=13) - s_value = ps("val", fontSize=9.5, textColor=C_DARK, leading=13, fontName="Helvetica-Bold") - s_sec = ps("sec", fontSize=9, textColor=C_GRAY, leading=12, fontName="Helvetica-Bold", - spaceBefore=0, spaceAfter=0, letterSpacing=0.8) - s_price = ps("prc", fontSize=19, textColor=C_DARK, leading=24, fontName="Helvetica-Bold") - s_feat = ps("feat", fontSize=8.5, textColor=C_DARK, leading=12, fontName="Helvetica-Bold") - s_fdesc = ps("fdsc", fontSize=7.5, textColor=C_GRAY, leading=11) - - # ── Computed values ─────────────────────────────────────────────────────── - today = datetime.utcnow().strftime("%d.%m.%Y") - validity = (datetime.utcnow() + timedelta(days=30)).strftime("%d.%m.%Y") - offer_number = f"ANG-{datetime.utcnow().strftime('%Y%m%d-%H%M')}" - plan_name = key_description or "Standard Plan" - price_str = _fmt_eur(price) - freq_cap = payment_frequency.capitalize() - - if daily_token_limit: - posts_per_month = int(daily_token_limit * 30 / AVG_TOKENS_PER_POST) - token_str = ( - f"{daily_token_limit:,}".replace(",", ".") + - f" Tokens / Tag (ca. {posts_per_month} Posts / Monat)" - ) - else: - token_str = "Unbegrenzt" - - story = [] - - # ── Header: Logo + ANGEBOT ──────────────────────────────────────────────── - logo_path = Path(__file__).parent.parent / "static" / "logo.png" - logo = ( - Image(str(logo_path), width=2.8 * cm, height=2.8 * cm, kind="proportional") - if logo_path.exists() - else Paragraph("Onyva", ps("lt", fontSize=13, textColor=C_WHITE, fontName="Helvetica-Bold")) - ) - hdr = Table( - [[ - logo, - [ - Paragraph('ANGEBOT', - ps("ttl", fontSize=20, fontName="Helvetica-Bold", alignment=2, leading=25)), - Spacer(1, 0.1 * cm), - Paragraph(f'{offer_number}', - ps("anr", fontSize=8, textColor=C_GRAY, alignment=2, leading=12)), - ], - ]], - colWidths=[4.5 * cm, CONTENT_W - 4.5 * cm], - ) - hdr.setStyle(TableStyle([ - ("BACKGROUND", (0, 0), (-1, -1), C_DARK), - ("TOPPADDING", (0, 0), (-1, -1), 10), - ("BOTTOMPADDING", (0, 0), (-1, -1), 10), - ("LEFTPADDING", (0, 0), (0, -1), 14), - ("RIGHTPADDING", (-1, 0), (-1, -1), 14), - ("VALIGN", (0, 0), (-1, -1), "MIDDLE"), - ])) - story.append(hdr) - story.append(Spacer(1, 0.45 * cm)) - - # ── Meta block (recipient / date / validity) ────────────────────────────── - meta = Table( - [ - [Paragraph("Empfänger", s_label), Paragraph(recipient_email, s_value), - Paragraph("Datum", s_label), Paragraph(today, s_body)], - [Paragraph("Plan", s_label), Paragraph(plan_name, s_body), - Paragraph("Gültig bis",s_label), Paragraph(validity, s_body)], - ], - colWidths=[2.8 * cm, CONTENT_W / 2 - 2.8 * cm, 2.2 * cm, CONTENT_W / 2 - 2.2 * cm], - ) - meta.setStyle(TableStyle([ - ("TOPPADDING", (0, 0), (-1, -1), 2), - ("BOTTOMPADDING", (0, 0), (-1, -1), 2), - ("LEFTPADDING", (0, 0), (-1, -1), 0), - ("RIGHTPADDING", (0, 0), (-1, -1), 4), - ])) - story.append(meta) - story.append(Spacer(1, 0.3 * cm)) - story.append(HRFlowable(width="100%", thickness=1.5, color=C_HIGHLIGHT, spaceAfter=0.35 * cm)) - - # ── Intro (one compact line) ─────────────────────────────────────────────── - story.append(Paragraph( - "Sehr geehrte Damen und Herren, nachfolgend erhalten Sie unser Angebot für die Nutzung der " - "Onyva LinkedIn Content Automation Plattform.", - s_body, - )) - story.append(Spacer(1, 0.35 * cm)) - - # ── Section: Lizenzdetails ──────────────────────────────────────────────── - story.append(Paragraph("LIZENZDETAILS", s_sec)) - story.append(Spacer(1, 0.15 * cm)) - - # Compact limits bar (single row, two columns) - limits_bar = Table( - [[ - Paragraph(f"Mitarbeiter: {max_employees} Nutzer", s_body), - Paragraph(f"KI-Token-Limit: {token_str}", s_body), - ]], - colWidths=[CONTENT_W / 2, CONTENT_W / 2], - ) - limits_bar.setStyle(TableStyle([ - ("BACKGROUND", (0, 0), (-1, -1), C_WHITE), - ("TOPPADDING", (0, 0), (-1, -1), 6), - ("BOTTOMPADDING",(0, 0), (-1, -1), 6), - ("LEFTPADDING", (0, 0), (-1, -1), 10), - ("RIGHTPADDING", (0, 0), (-1, -1), 10), - ("GRID", (0, 0), (-1, -1), 0.5, C_RULE), - ("VALIGN", (0, 0), (-1, -1), "TOP"), - ])) - story.append(limits_bar) - story.append(Spacer(1, 0.25 * cm)) - - # Features: 2-column grid - FEATURES = [ - ("LinkedIn-Profil-Analyse", "KI-gestützt, einmalig pro Profil – Basis für individuelle Content-Strategie"), - ("Post-Typen & Strategie", "Definierbare Typen mit Gewichtung, KI-Analyse & Strategieanpassung"), - ("KI-Post-Erstellung", "Chat-basiert, iterativ, mit Qualitätsprüfung & Stilvalidierung"), - ("Mitarbeiterverwaltung", "Posts verwalten, kommentieren, freigeben oder ablehnen per UI"), - ("Research-Funktion", "Automatische Themenrecherche zu aktuellen Branchentrends"), - ("Posting-Kalender", "Planung & Terminierung von Posts über alle Mitarbeiter hinweg"), - ("E-Mail-Workflows", "Freigabe-Anfragen & Entscheidungsbenachrichtigungen per E-Mail"), - ] - - def feat_cell(name, desc): - return Paragraph( - f'✓ {name}
' - f' {desc}', - ps(f"fc_{name[:4]}", fontSize=8.5, leading=13), - ) - - # Pair features into rows of 2 - feat_rows = [] - for i in range(0, len(FEATURES), 2): - left = feat_cell(*FEATURES[i]) - right = feat_cell(*FEATURES[i + 1]) if i + 1 < len(FEATURES) else Paragraph("", s_small) - feat_rows.append([left, right]) - - feat_t = Table(feat_rows, colWidths=[HALF_W, HALF_W], hAlign="LEFT") - feat_t.setStyle(TableStyle([ - ("BACKGROUND", (0, 0), (-1, -1), C_WHITE), - ("GRID", (0, 0), (-1, -1), 0.4, C_RULE), - ("TOPPADDING", (0, 0), (-1, -1), 5), - ("BOTTOMPADDING", (0, 0), (-1, -1), 5), - ("LEFTPADDING", (0, 0), (-1, -1), 8), - ("RIGHTPADDING", (0, 0), (-1, -1), 8), - ("VALIGN", (0, 0), (-1, -1), "TOP"), - ])) - story.append(feat_t) - story.append(Spacer(1, 0.4 * cm)) - - # ── Section: Preisgestaltung ────────────────────────────────────────────── - story.append(Paragraph("PREISGESTALTUNG", s_sec)) - story.append(Spacer(1, 0.15 * cm)) - - price_rows = [ - [Paragraph("Preis", s_label), Paragraph(price_str, s_price)], - [Paragraph("Zahlungsweise", s_label), Paragraph(freq_cap, s_body)], - ] - if payment_frequency == "jährlich": - price_rows.append([Paragraph("Jahresbetrag", s_label), Paragraph(_fmt_eur(price * 12), s_body)]) - - price_t = Table(price_rows, colWidths=[4 * cm, CONTENT_W - 4 * cm]) - price_t.setStyle(TableStyle([ - ("BACKGROUND", (0, 0), (-1, -1), C_WHITE), - ("GRID", (0, 0), (-1, -1), 0.5, C_RULE), - ("TOPPADDING", (0, 0), (-1, -1), 6), - ("BOTTOMPADDING", (0, 0), (-1, -1), 6), - ("LEFTPADDING", (0, 0), (-1, -1), 10), - ("RIGHTPADDING", (0, 0), (-1, -1), 10), - ("VALIGN", (0, 0), (-1, -1), "MIDDLE"), - ])) - story.append(price_t) - story.append(Spacer(1, 0.2 * cm)) - story.append(Paragraph("Alle Preise zzgl. gesetzlicher Mehrwertsteuer.", s_small)) - story.append(Spacer(1, 0.5 * cm)) - - # ── Footer ──────────────────────────────────────────────────────────────── - story.append(HRFlowable(width="100%", thickness=0.5, color=C_RULE, spaceAfter=0.25 * cm)) - story.append(Paragraph( - "Bei Fragen stehen wir Ihnen gerne zur Verfügung – Kontakt: team@onyva.de", - s_small, - )) - story.append(Spacer(1, 0.35 * cm)) - story.append(Paragraph("Mit freundlichen Grüßen,
Onyva", s_body)) - - doc.build(story) - return buffer.getvalue() - - -@admin_router.post("/api/license-keys/{key_id}/send-offer") -async def send_license_offer( +@admin_router.post("/api/license-keys/{key_id}/create-offer") +async def create_moco_offer_endpoint( request: Request, key_id: str, - email: str = Form(...), + company_id: int = Form(...), + company_name: str = Form(...), price: float = Form(...), payment_frequency: str = Form(...), ): - """Generate a PDF offer and send it via email.""" + """Create an offer in MOCO for the given license key.""" if not verify_auth(request): raise HTTPException(status_code=401) @@ -883,74 +665,66 @@ async def send_license_offer( if not key: raise HTTPException(status_code=404, detail="Lizenzschlüssel nicht gefunden") - pdf_bytes = _build_offer_pdf( - key_description=key.description or "", - max_employees=key.max_employees, - daily_token_limit=key.daily_token_limit, + plan_name = key.description or "Standard Plan" + offer = await moco_service.create_moco_offer( + company_id=company_id, + company_name=company_name, price=price, payment_frequency=payment_frequency, - recipient_email=email, + plan_name=plan_name, + max_employees=key.max_employees, + daily_token_limit=key.daily_token_limit, ) - posts_note = "" - if key.daily_token_limit: - posts_per_month = int(key.daily_token_limit * 30 / AVG_TOKENS_PER_POST) - token_str = f"{key.daily_token_limit:,}".replace(",", ".") + f" Tokens/Tag (ca. {posts_per_month} Posts/Monat)" - else: - token_str = "Unbegrenzt" + offer_url = offer.get("web_url") or offer.get("url") or f"https://{settings.moco_domain}.mocoapp.com/offers/{offer.get('id', '')}" - price_str = f"{price:,.2f} €".replace(",", "X").replace(".", ",").replace("X", ".") - plan_name = key.description or "Standard Plan" - - html_body = f""" -
-
-

LinkedIn Content Automation

-

Ihr persönliches Angebot

-
-
-

Sehr geehrte Damen und Herren,

-

- vielen Dank für Ihr Interesse an unserer LinkedIn Content Automation Lösung.
- Im Anhang finden Sie Ihr persönliches Angebot als PDF-Dokument. -

-
-

Angebotsübersicht

- - - - - - -
Plan{plan_name}
Mitarbeiter{key.max_employees} Nutzer
Token-Limit{token_str}
Preis{price_str}
Zahlungsweise{payment_frequency.capitalize()}
-
-

Alle Preise zzgl. gesetzlicher MwSt. Das Angebot ist 30 Tage gültig.

-

Bei Fragen stehen wir Ihnen gerne zur Verfügung.

-

Mit freundlichen Grüßen,
Onyva

-
-
-

Onyva • team@onyva.de

-
-
- """ - - offer_number = datetime.utcnow().strftime('%Y%m%d%H%M') - filename = f"Angebot_{offer_number}.pdf" - success = send_email_with_attachment( - to_email=email, - subject=f"Ihr Angebot – LinkedIn Content Automation ({plan_name})", - html_content=html_body, - attachment_bytes=pdf_bytes, - attachment_filename=filename, + # Persist offer in DB + await db.create_license_key_offer( + license_key_id=UUID(key_id), + moco_offer_id=offer["id"], + moco_offer_identifier=offer.get("identifier"), + moco_offer_url=offer_url, + offer_title=offer.get("title") or f"LinkedIn Content Automation – {plan_name}", + company_name=company_name, + price=price, + payment_frequency=payment_frequency, ) - if not success: - raise HTTPException(status_code=500, detail="E-Mail konnte nicht gesendet werden. SMTP prüfen.") - - return JSONResponse({"success": True, "message": f"Angebot erfolgreich an {email} gesendet."}) + return JSONResponse({"success": True, "offer_url": offer_url}) except HTTPException: raise except Exception as e: - logger.error(f"Error sending license offer: {e}") + logger.error(f"Error creating MOCO offer: {e}") raise HTTPException(status_code=500, detail=str(e)) + + +@admin_router.post("/api/license-key-offers/{offer_id}/send") +async def send_license_key_offer(request: Request, offer_id: str): + """Send a stored MOCO offer via email and mark it as sent.""" + if not verify_auth(request): + raise HTTPException(status_code=401) + + try: + from src.database.models import LicenseKeyOffer + result = await asyncio.to_thread( + lambda: db.client.table("license_key_offers") + .select("*") + .eq("id", offer_id) + .execute() + ) + if not result.data: + raise HTTPException(status_code=404, detail="Angebot nicht gefunden") + + stored = LicenseKeyOffer(**result.data[0]) + await moco_service.send_moco_offer(stored.moco_offer_id) + await db.update_license_key_offer_status(UUID(offer_id), "sent") + + return JSONResponse({"success": True}) + except HTTPException: + raise + except Exception as e: + logger.error(f"Error sending offer {offer_id}: {e}") + raise HTTPException(status_code=500, detail=str(e)) + + diff --git a/src/web/templates/admin/license_keys.html b/src/web/templates/admin/license_keys.html index 566d87a..7cbe20c 100644 --- a/src/web/templates/admin/license_keys.html +++ b/src/web/templates/admin/license_keys.html @@ -52,6 +52,7 @@ {% for key in keys %} + {% set key_offers = offers_by_key.get(key.id | string, []) %}
{{ key.key }}
@@ -67,44 +68,42 @@ {% if key.used %} - - Verwendet - + Verwendet {% else %} - - Verfügbar - + Verfügbar {% endif %} {{ key.created_at.strftime('%d.%m.%Y') if key.created_at else '-' }} + {% if key_offers %} + + {% endif %} {% if not key.used %}
+ {% endif %} + + + {% endfor %} + + + + {% endif %} {% endfor %} @@ -166,13 +200,14 @@