from datetime import datetime, timedelta from celery import shared_task from sqlalchemy import select, and_ import logging logger = logging.getLogger(__name__) @shared_task def check_silent_customers(): from app.database import AsyncSessionLocal from app.models.customer import Customer async def _check(): async with AsyncSessionLocal() as db: now = datetime.utcnow() for days in [3, 7, 14]: cutoff = now - timedelta(days=days) result = await db.execute( select(Customer).where( and_( Customer.status.in_(["lead", "negotiating"]), Customer.last_contact_at.isnot(None), Customer.last_contact_at < cutoff, ) ) ) customers = result.scalars().all() for c in customers: if days == 3: logger.info(f"Customer {c.name} silent for 3 days") elif days == 7: logger.info(f"Customer {c.name} silent for 7 days - upgrade") else: logger.info(f"Customer {c.name} silent for 14 days - recommend new approach") import asyncio asyncio.run(_check()) return "Checked silent customers" @shared_task def batch_translate_texts(texts: list, target_lang: str, user_id: str): from app.services.translation import TranslationService async def _translate(): service = TranslationService() results = [] for text in texts: result = await service.translate(text, target_lang, user_id=user_id) results.append(result) return results import asyncio return asyncio.run(_translate()) @shared_task def generate_quotation_pdf(quotation_id: str): from app.database import AsyncSessionLocal from app.models.quotation import Quotation, QuotationItem async def _generate(): async with AsyncSessionLocal() as db: result = await db.execute( select(Quotation).where(Quotation.id == quotation_id) ) q = result.scalar_one_or_none() if not q: return {"error": "Quotation not found"} items_result = await db.execute( select(QuotationItem).where(QuotationItem.quotation_id == q.id) ) items = items_result.scalars().all() pdf_content = generate_pdf_text(q, items) return {"pdf_content": pdf_content, "quotation_id": str(q.id)} import asyncio return asyncio.run(_generate()) def generate_pdf_text(quotation, items): from datetime import datetime lines = [ "=" * 60, f"QUOTATION", f"#{str(quotation.id)[:8].upper()}", "=" * 60, f"Date: {datetime.utcnow().strftime('%Y-%m-%d')}", ] if quotation.valid_until: lines.append(f"Valid Until: {quotation.valid_until}") lines.append("") lines.append(f"{'Item':<30} {'Qty':<8} {'Unit Price':<12} {'Total':<12}") lines.append("-" * 62) for item in items: lines.append( f"{item.product_name:<30} {item.quantity:<8} ${item.unit_price:<10.2f} ${item.total_price:<10.2f}" ) lines.append("-" * 62) if quotation.subtotal: lines.append(f"{'Subtotal':>48} ${quotation.subtotal:<10.2f}") if quotation.discount: lines.append(f"{'Discount':>48} -${quotation.discount:<10.2f}") if quotation.shipping: lines.append(f"{'Shipping':>48} ${quotation.shipping:<10.2f}") lines.append(f"{'TOTAL':>48} ${quotation.total or quotation.subtotal or 0:<10.2f}") lines.append("") if quotation.payment_terms: lines.append(f"Payment Terms: {quotation.payment_terms}") if quotation.delivery_terms: lines.append(f"Delivery Terms: {quotation.delivery_terms}") if quotation.lead_time: lines.append(f"Lead Time: {quotation.lead_time}") if quotation.notes: lines.append(f"Notes: {quotation.notes}") lines.append("=" * 60) lines.append("Generated by TradeMate") return "\n".join(lines) @shared_task def process_corpus_quality(): from app.database import AsyncSessionLocal from app.models.corpus import CorpusEntry async def _process(): async with AsyncSessionLocal() as db: result = await db.execute( select(CorpusEntry).where( and_( CorpusEntry.quality_score < 0.5, CorpusEntry.usage_count > 5, ) ).limit(100) ) entries = result.scalars().all() for e in entries: e.quality_score = min(1.0, e.quality_score + 0.1) await db.commit() return f"Processed {len(entries)} entries" import asyncio return asyncio.run(_process()) @shared_task def cleanup_old_sessions(): import redis.asyncio as aioredis async def _cleanup(): r = await aioredis.from_url(settings.REDIS_URL) keys = await r.keys("session:*") if keys: await r.delete(*keys) return f"Cleaned up {len(keys)} sessions" import asyncio return asyncio.run(_cleanup()) @shared_task def send_followup_reminder(customer_id: str, user_id: str): from app.database import AsyncSessionLocal from app.models.customer import Customer from app.services.customer import CustomerService async def _send(): async with AsyncSessionLocal() as db: result = await db.execute( select(Customer).where( and_(Customer.id == customer_id, Customer.user_id == user_id) ) ) c = result.scalar_one_or_none() if c: logger.info(f"Sending followup reminder for customer {c.name}") return {"customer_id": str(c.id), "customer_name": c.name} return {"error": "Customer not found"} import asyncio return asyncio.run(_send())