| """ |
| B2B Data Push Service |
| Orchestrates the synchronization of B2B data (customers, draft orders) to external integrations like HubSpot and QuickBooks. |
| """ |
|
|
| import logging |
| from typing import Any, Dict, Optional |
| from ecommerce.models import EcommerceCustomer, EcommerceOrder, EcommerceOrderItem |
| from sqlalchemy.orm import Session |
|
|
| from integrations.atom_quickbooks_integration_service import AtomQuickBooksIntegrationService |
| from integrations.hubspot_service import hubspot_service |
|
|
| logger = logging.getLogger(__name__) |
|
|
| class B2BDataPushService: |
| def __init__(self, db: Session): |
| self.db = db |
| |
| self.qbo = AtomQuickBooksIntegrationService({ |
| "database": db, |
| "quickbooks_client_id": "MOCK", |
| "quickbooks_client_secret": "MOCK", |
| "quickbooks_company_id": "MOCK", |
| }) |
|
|
| async def push_b2b_customer(self, customer_id: str) -> Dict[str, Any]: |
| """ |
| Push a B2B customer profile to external CRM and Accounting integrations. |
| """ |
| customer = self.db.query(EcommerceCustomer).filter(EcommerceCustomer.id == customer_id).first() |
| if not customer: |
| return {"error": "Customer not found"} |
|
|
| results = {"hubspot": None, "quickbooks": None} |
|
|
| |
| try: |
| company_name = f"{customer.first_name} {customer.last_name}" or customer.email |
| domain = customer.email.split('@')[-1] if '@' in customer.email else None |
| |
| hs_company = await hubspot_service.create_company(name=company_name, domain=domain) |
| results["hubspot"] = hs_company.get("id") |
| customer.crm_contact_id = hs_company.get("id") |
| logger.info(f"Pushed B2B customer {customer_id} to HubSpot: {results['hubspot']}") |
| except Exception as e: |
| logger.error(f"Failed to push to HubSpot: {e}") |
| results["hubspot_error"] = str(e) |
|
|
| |
| try: |
| display_name = f"{customer.first_name} {customer.last_name}" or customer.email |
| qbo_res = await self.qbo.create_customer(display_name=display_name, email=customer.email) |
| if qbo_res["success"]: |
| results["quickbooks"] = qbo_res["customer_id"] |
| customer.accounting_entity_id = qbo_res["customer_id"] |
| logger.info(f"Pushed B2B customer {customer_id} to QuickBooks: {results['quickbooks']}") |
| else: |
| results["quickbooks_error"] = qbo_res.get("error") |
| except Exception as e: |
| logger.error(f"Failed to push to QuickBooks: {e}") |
| results["quickbooks_error"] = str(e) |
|
|
| self.db.commit() |
| return results |
|
|
| async def push_draft_order(self, order_id: str) -> Dict[str, Any]: |
| """ |
| Push a B2B draft order to HubSpot (as Deal) and QuickBooks (as Invoice/Draft). |
| """ |
| order = self.db.query(EcommerceOrder).filter(EcommerceOrder.id == order_id).first() |
| if not order: |
| return {"error": "Order not found"} |
|
|
| customer = order.customer |
| results = {"hubspot_deal": None, "quickbooks_invoice": None} |
|
|
| |
| try: |
| company_id = customer.crm_contact_id |
| deal_name = f"B2B Order {order.order_number}" |
| |
| hs_deal = await hubspot_service.create_deal( |
| name=deal_name, |
| amount=order.total_price, |
| company_id=company_id |
| ) |
| results["hubspot_deal"] = hs_deal.get("id") |
| logger.info(f"Pushed draft order {order_id} to HubSpot Deal: {results['hubspot_deal']}") |
| except Exception as e: |
| logger.error(f"Failed to push order to HubSpot Deal: {e}") |
| results["hubspot_deal_error"] = str(e) |
|
|
| |
| try: |
| line_items = [] |
| for item in order.items: |
| line_items.append({ |
| "Amount": item.price * item.quantity, |
| "Description": item.title, |
| "DetailType": "SalesItemLineDetail", |
| "SalesItemLineDetail": { |
| "ItemRef": {"value": item.product_id or "1"}, |
| "Qty": item.quantity, |
| "UnitPrice": item.price |
| } |
| }) |
|
|
| invoice_data = { |
| "customer_id": customer.accounting_entity_id, |
| "amount": order.total_price, |
| "line_items": line_items, |
| "notes": f"Generated from B2B Draft {order.order_number}" |
| } |
| |
| qbo_res = await self.qbo.create_invoice(invoice_data) |
| if qbo_res["success"]: |
| results["quickbooks_invoice"] = qbo_res["invoice_id"] |
| order.ledger_transaction_id = qbo_res["invoice_id"] |
| logger.info(f"Pushed draft order {order_id} to QuickBooks Invoice: {results['quickbooks_invoice']}") |
| else: |
| results["quickbooks_error"] = qbo_res.get("error") |
| except Exception as e: |
| logger.error(f"Failed to push order to QuickBooks: {e}") |
| results["quickbooks_error"] = str(e) |
|
|
| self.db.commit() |
| return results |
|
|