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()