From 116c0b03bf8a05aaa9371cbed1d32c79afbb6c38 Mon Sep 17 00:00:00 2001 From: gsinghpal Date: Tue, 31 Mar 2026 20:41:04 -0400 Subject: [PATCH] feat: add cron jobs, sync engine scaffolding, log cleanup, and email templates Co-Authored-By: Claude Opus 4.6 (1M context) --- .../fusion_woocommerce/__manifest__.py | 2 + .../fusion_woocommerce/data/cron.xml | 57 ++++++++++++ .../fusion_woocommerce/data/mail_template.xml | 39 ++++++++ .../fusion_woocommerce/models/woo_instance.py | 91 +++++++++++++++++++ .../fusion_woocommerce/models/woo_sync_log.py | 13 ++- 5 files changed, 201 insertions(+), 1 deletion(-) create mode 100644 fusion-woo-odoo/fusion_woocommerce/data/cron.xml create mode 100644 fusion-woo-odoo/fusion_woocommerce/data/mail_template.xml diff --git a/fusion-woo-odoo/fusion_woocommerce/__manifest__.py b/fusion-woo-odoo/fusion_woocommerce/__manifest__.py index 2b6a9e65..f63dca40 100644 --- a/fusion-woo-odoo/fusion_woocommerce/__manifest__.py +++ b/fusion-woo-odoo/fusion_woocommerce/__manifest__.py @@ -12,6 +12,8 @@ 'security/woo_security.xml', 'security/ir.model.access.csv', 'data/shipping_carriers.xml', + 'data/cron.xml', + 'data/mail_template.xml', 'views/woo_instance_views.xml', 'views/woo_product_map_views.xml', 'views/woo_order_views.xml', diff --git a/fusion-woo-odoo/fusion_woocommerce/data/cron.xml b/fusion-woo-odoo/fusion_woocommerce/data/cron.xml new file mode 100644 index 00000000..30b3ee3d --- /dev/null +++ b/fusion-woo-odoo/fusion_woocommerce/data/cron.xml @@ -0,0 +1,57 @@ + + + + WooCommerce: Sync Products + + code + model._cron_sync_products() + 15 + minutes + -1 + True + + + + WooCommerce: Sync Orders + + code + model._cron_sync_orders() + 5 + minutes + -1 + True + + + + WooCommerce: Sync Inventory + + code + model._cron_sync_inventory() + 15 + minutes + -1 + True + + + + WooCommerce: Sync Customers + + code + model._cron_sync_customers() + 30 + minutes + -1 + True + + + + WooCommerce: Cleanup Old Sync Logs + + code + model._cron_cleanup_logs() + 1 + days + -1 + True + + diff --git a/fusion-woo-odoo/fusion_woocommerce/data/mail_template.xml b/fusion-woo-odoo/fusion_woocommerce/data/mail_template.xml new file mode 100644 index 00000000..95a4ff6b --- /dev/null +++ b/fusion-woo-odoo/fusion_woocommerce/data/mail_template.xml @@ -0,0 +1,39 @@ + + + + WooCommerce: Sync Failure Notification + + WooCommerce Sync Failed: ${object.name} + Hello,

+

A WooCommerce sync has failed for the following instance:

+
    +
  • Instance: ${object.name}
  • +
  • Sync Type: ${ctx.get('sync_type', 'Unknown')}
  • +
  • Error: ${ctx.get('error_message', 'No details available')}
  • +
  • Timestamp: ${object.last_sync or 'N/A'}
  • +
+

Please review your WooCommerce integration settings and resolve the issue.

+

— Fusion WooCommerce

+ ]]>
+ True +
+ + + WooCommerce: New Order Notification + + New WooCommerce Order: ${ctx.get('order_number', '')} + Hello,

+

A new WooCommerce order has been received:

+
    +
  • Order Number: ${ctx.get('order_number', 'N/A')}
  • +
  • Customer: ${ctx.get('customer_name', 'N/A')}
  • +
  • Total: $${ctx.get('order_total', '0.00')}
  • +
+

Log in to Odoo to review and process this order.

+

— Fusion WooCommerce

+ ]]>
+ True +
+
diff --git a/fusion-woo-odoo/fusion_woocommerce/models/woo_instance.py b/fusion-woo-odoo/fusion_woocommerce/models/woo_instance.py index 936f2de6..e94dfd70 100644 --- a/fusion-woo-odoo/fusion_woocommerce/models/woo_instance.py +++ b/fusion-woo-odoo/fusion_woocommerce/models/woo_instance.py @@ -115,3 +115,94 @@ class WooInstance(models.Model): 'message': message, 'company_id': self.company_id.id, }) + + # ------------------------------------------------------------------ + # Cron entry points + # ------------------------------------------------------------------ + + @api.model + def _cron_sync_products(self): + """Sync product prices and inventory for all connected instances.""" + instances = self.search([('state', '=', 'connected'), ('sync_products', '=', True)]) + for instance in instances: + try: + instance._sync_products() + except Exception as e: + _logger.error("Product sync failed for %s: %s", instance.name, str(e)) + instance._log_sync('product', 'woo_to_odoo', instance.name, 'failed', str(e)) + instance._notify_failure('product', str(e)) + + @api.model + def _cron_sync_orders(self): + """Fetch new orders from all connected WooCommerce instances.""" + instances = self.search([('state', '=', 'connected'), ('sync_orders', '=', True)]) + for instance in instances: + try: + instance._sync_orders() + except Exception as e: + _logger.error("Order sync failed for %s: %s", instance.name, str(e)) + instance._log_sync('order', 'woo_to_odoo', instance.name, 'failed', str(e)) + instance._notify_failure('order', str(e)) + + @api.model + def _cron_sync_inventory(self): + """Push inventory levels to WooCommerce for all connected instances.""" + instances = self.search([('state', '=', 'connected'), ('sync_inventory', '=', True)]) + for instance in instances: + try: + instance._sync_inventory() + except Exception as e: + _logger.error("Inventory sync failed for %s: %s", instance.name, str(e)) + instance._log_sync('inventory', 'odoo_to_woo', instance.name, 'failed', str(e)) + instance._notify_failure('inventory', str(e)) + + @api.model + def _cron_sync_customers(self): + """Sync customer address updates to WooCommerce.""" + instances = self.search([('state', '=', 'connected'), ('sync_customers', '=', True)]) + for instance in instances: + try: + instance._sync_customers() + except Exception as e: + _logger.error("Customer sync failed for %s: %s", instance.name, str(e)) + instance._log_sync('customer', 'odoo_to_woo', instance.name, 'failed', str(e)) + instance._notify_failure('customer', str(e)) + + # ------------------------------------------------------------------ + # Sync method placeholders (filled in during later tasks) + # ------------------------------------------------------------------ + + def _sync_products(self): + """Sync products — implemented in Task 22.""" + self.ensure_one() + _logger.info("Product sync for %s — not yet implemented", self.name) + + def _sync_orders(self): + """Sync orders — implemented in Task 20.""" + self.ensure_one() + _logger.info("Order sync for %s — not yet implemented", self.name) + + def _sync_inventory(self): + """Sync inventory — implemented in Task 22.""" + self.ensure_one() + _logger.info("Inventory sync for %s — not yet implemented", self.name) + + def _sync_customers(self): + """Sync customers — implemented in Task 25.""" + self.ensure_one() + _logger.info("Customer sync for %s — not yet implemented", self.name) + + def _notify_failure(self, sync_type, error_message): + """Send email notification on sync failure.""" + self.ensure_one() + if not self.notify_on_failure or not self.notify_user_ids: + return + template = self.env.ref( + 'fusion_woocommerce.woo_sync_failure_notification', raise_if_not_found=False, + ) + if template: + for user in self.notify_user_ids: + template.with_context( + sync_type=sync_type, + error_message=error_message, + ).send_mail(self.id, force_send=True, email_values={'email_to': user.email}) diff --git a/fusion-woo-odoo/fusion_woocommerce/models/woo_sync_log.py b/fusion-woo-odoo/fusion_woocommerce/models/woo_sync_log.py index 00614157..4ce09116 100644 --- a/fusion-woo-odoo/fusion_woocommerce/models/woo_sync_log.py +++ b/fusion-woo-odoo/fusion_woocommerce/models/woo_sync_log.py @@ -1,4 +1,4 @@ -from odoo import fields, models +from odoo import api, fields, models class WooSyncLog(models.Model): @@ -28,3 +28,14 @@ class WooSyncLog(models.Model): company_id = fields.Many2one( 'res.company', default=lambda self: self.env.company, ) + + @api.model + def _cron_cleanup_logs(self): + """Purge sync logs older than 90 days (180 for errors).""" + cutoff_success = fields.Datetime.subtract(fields.Datetime.now(), hours=90 * 24) + cutoff_error = fields.Datetime.subtract(fields.Datetime.now(), hours=180 * 24) + self.search([ + '|', + '&', ('state', '!=', 'failed'), ('create_date', '<', cutoff_success), + '&', ('state', '=', 'failed'), ('create_date', '<', cutoff_error), + ]).unlink()