Watch
1
0
Fork
You've already forked Seyyed_arc
0
forked from hesabix/arc
Seyyed_arc/hesabixAPI/app/services/tax_dead_letter_queue.py
2026-04-14 19:34:55 +03:30

188 lines
5.5 KiB
Python
Executable file

"""
Dead Letter Queue برای فاکتورهای failed
"""
from __future__ import annotations
import logging
from typing import Dict, Any, List, Optional
from datetime import datetime
from sqlalchemy.orm import Session
from adapters.db.models.tax_failed_invoice import TaxFailedInvoice
from adapters.db.models.document import Document
logger = logging.getLogger(__name__)
def add_to_dead_letter_queue(
db: Session,
business_id: int,
invoice_id: int,
error_code: str,
error_message: str,
error_details: Optional[Dict[str, Any]] = None,
tracking_code: Optional[str] = None,
invoice_data: Optional[Dict[str, Any]] = None,
) -> TaxFailedInvoice:
"""
افزودن فاکتور failed به Dead Letter Queue
Args:
db: Database session
business_id: شناسه کسب‌وکار
invoice_id: شناسه فاکتور
error_code: کد خطا
error_message: پیام خطا
error_details: جزئیات خطا
tracking_code: کد رهگیری (در صورت وجود)
invoice_data: داده‌های فاکتور برای retry
Returns:
رکورد ایجاد شده
"""
# بررسی وجود رکورد قبلی
existing = (
db.query(TaxFailedInvoice)
.filter(
TaxFailedInvoice.business_id == business_id,
TaxFailedInvoice.invoice_id == invoice_id,
TaxFailedInvoice.status.in_(["pending", "retrying"]),
)
.first()
)
if existing:
# به‌روزرسانی رکورد موجود
existing.error_code = error_code
existing.error_message = error_message
existing.error_details = error_details
existing.tracking_code = tracking_code
existing.attempt_count += 1
existing.last_attempt_at = datetime.utcnow()
existing.status = "pending"
if invoice_data:
existing.invoice_data = invoice_data
db.add(existing)
return existing
# ایجاد رکورد جدید
failed_invoice = TaxFailedInvoice(
business_id=business_id,
invoice_id=invoice_id,
tracking_code=tracking_code,
error_code=error_code,
error_message=error_message,
error_details=error_details,
invoice_data=invoice_data,
status="pending",
)
db.add(failed_invoice)
return failed_invoice
def get_failed_invoices(
db: Session,
business_id: int,
status: Optional[str] = None,
limit: int = 100,
offset: int = 0,
) -> List[TaxFailedInvoice]:
"""
دریافت لیست فاکتورهای failed
Args:
db: Database session
business_id: شناسه کسب‌وکار
status: وضعیت (pending, retrying, resolved, ignored)
limit: تعداد رکوردها
offset: offset
Returns:
لیست فاکتورهای failed
"""
query = db.query(TaxFailedInvoice).filter(
TaxFailedInvoice.business_id == business_id
)
if status:
query = query.filter(TaxFailedInvoice.status == status)
return query.order_by(TaxFailedInvoice.first_failed_at.desc()).offset(offset).limit(limit).all()
def retry_failed_invoice(
db: Session,
failed_invoice_id: int,
) -> Dict[str, Any]:
"""
تلاش مجدد برای ارسال فاکتور failed
Args:
db: Database session
failed_invoice_id: شناسه رکورد failed
Returns:
نتیجه retry
"""
failed_invoice = db.query(TaxFailedInvoice).filter(
TaxFailedInvoice.id == failed_invoice_id
).first()
if not failed_invoice:
raise ValueError("Failed invoice not found")
if failed_invoice.status not in ["pending", "retrying"]:
raise ValueError(f"Cannot retry invoice with status: {failed_invoice.status}")
# دریافت فاکتور
doc = db.query(Document).filter(
Document.id == failed_invoice.invoice_id,
Document.business_id == failed_invoice.business_id,
).first()
if not doc:
failed_invoice.status = "resolved"
failed_invoice.error_message = "فاکتور یافت نشد"
db.add(failed_invoice)
return {"success": False, "message": "فاکتور یافت نشد"}
# تلاش برای ارسال مجدد
failed_invoice.status = "retrying"
db.add(failed_invoice)
db.flush()
try:
from app.services.tax_submission_service import send_document_to_tax_system
result = send_document_to_tax_system(db, doc)
# در صورت موفقیت، حذف از dead letter queue
db.delete(failed_invoice)
return {"success": True, "result": result}
except Exception as e:
# در صورت خطا، به‌روزرسانی رکورد
failed_invoice.status = "pending"
failed_invoice.attempt_count += 1
failed_invoice.last_attempt_at = datetime.utcnow()
failed_invoice.error_message = str(e)
db.add(failed_invoice)
return {"success": False, "error": str(e)}
def mark_failed_invoice_resolved(
db: Session,
failed_invoice_id: int,
) -> None:
"""علامت‌گذاری فاکتور failed به عنوان resolved"""
failed_invoice = db.query(TaxFailedInvoice).filter(
TaxFailedInvoice.id == failed_invoice_id
).first()
if failed_invoice:
failed_invoice.status = "resolved"
db.add(failed_invoice)