diff --git a/fusion-woo-odoo/fusion_woocommerce/models/woo_category_map.py b/fusion-woo-odoo/fusion_woocommerce/models/woo_category_map.py
index 89530f5e..f2e411d5 100644
--- a/fusion-woo-odoo/fusion_woocommerce/models/woo_category_map.py
+++ b/fusion-woo-odoo/fusion_woocommerce/models/woo_category_map.py
@@ -5,6 +5,7 @@ class WooCategoryMap(models.Model):
_name = 'woo.category.map'
_description = 'WooCommerce Category Mapping'
_order = 'odoo_category_id'
+ _rec_name = 'woo_category_name'
instance_id = fields.Many2one('woo.instance', required=True, ondelete='cascade')
odoo_category_id = fields.Many2one('product.category', string='Odoo Category')
diff --git a/fusion-woo-odoo/fusion_woocommerce/models/woo_conflict.py b/fusion-woo-odoo/fusion_woocommerce/models/woo_conflict.py
index 2f1ce317..0d279e05 100644
--- a/fusion-woo-odoo/fusion_woocommerce/models/woo_conflict.py
+++ b/fusion-woo-odoo/fusion_woocommerce/models/woo_conflict.py
@@ -9,6 +9,7 @@ _logger = logging.getLogger(__name__)
class WooConflict(models.Model):
_name = 'woo.conflict'
_description = 'WooCommerce Sync Conflict'
+ _rec_name = 'field_name'
instance_id = fields.Many2one('woo.instance', required=True, ondelete='cascade')
conflict_type = fields.Selection([
diff --git a/fusion-woo-odoo/fusion_woocommerce/models/woo_customer.py b/fusion-woo-odoo/fusion_woocommerce/models/woo_customer.py
index f75b93b3..b7977a6c 100644
--- a/fusion-woo-odoo/fusion_woocommerce/models/woo_customer.py
+++ b/fusion-woo-odoo/fusion_woocommerce/models/woo_customer.py
@@ -8,6 +8,7 @@ _logger = logging.getLogger(__name__)
class WooCustomer(models.Model):
_name = 'woo.customer'
_description = 'WooCommerce Customer'
+ _rec_name = 'woo_email'
instance_id = fields.Many2one('woo.instance', required=True, ondelete='cascade')
partner_id = fields.Many2one('res.partner', required=True)
diff --git a/fusion-woo-odoo/fusion_woocommerce/models/woo_instance.py b/fusion-woo-odoo/fusion_woocommerce/models/woo_instance.py
index 75e7167a..ed76ffa1 100644
--- a/fusion-woo-odoo/fusion_woocommerce/models/woo_instance.py
+++ b/fusion-woo-odoo/fusion_woocommerce/models/woo_instance.py
@@ -686,13 +686,15 @@ class WooInstance(models.Model):
# Create woo.order tracking record FIRST to prevent infinite retries
# if action_confirm or invoicing fails later.
+ wc_status = wc_order.get('status', '')
+ odoo_state = self.env['woo.order'].WC_STATUS_TO_STATE.get(wc_status, 'confirmed')
woo_order = self.env['woo.order'].create({
'instance_id': self.id,
'sale_order_id': sale_order.id,
'woo_order_id': woo_order_id,
'woo_order_number': wc_order.get('number', str(woo_order_id)),
- 'woo_status': wc_order.get('status', ''),
- 'state': 'confirmed',
+ 'woo_status': wc_status if wc_status in dict(self.env['woo.order']._fields['woo_status'].selection) else False,
+ 'state': odoo_state,
'company_id': self.company_id.id,
})
diff --git a/fusion-woo-odoo/fusion_woocommerce/models/woo_order.py b/fusion-woo-odoo/fusion_woocommerce/models/woo_order.py
index 153433fb..778e9ada 100644
--- a/fusion-woo-odoo/fusion_woocommerce/models/woo_order.py
+++ b/fusion-woo-odoo/fusion_woocommerce/models/woo_order.py
@@ -1,7 +1,7 @@
import base64
import logging
-from odoo import fields, models
+from odoo import api, fields, models
from odoo.exceptions import UserError
_logger = logging.getLogger(__name__)
@@ -10,12 +10,25 @@ _logger = logging.getLogger(__name__)
class WooOrder(models.Model):
_name = 'woo.order'
_description = 'WooCommerce Order'
+ _inherit = ['mail.thread', 'mail.activity.mixin']
+ _rec_name = 'display_name'
+ _order = 'id desc'
+ display_name = fields.Char(compute='_compute_display_name', store=True)
instance_id = fields.Many2one('woo.instance', required=True, ondelete='cascade')
sale_order_id = fields.Many2one('sale.order')
woo_order_id = fields.Integer(index=True)
- woo_order_number = fields.Char()
- woo_status = fields.Char()
+ woo_order_number = fields.Char(string='WC Order #')
+ woo_status = fields.Selection([
+ ('pending', 'Pending Payment'),
+ ('processing', 'Processing'),
+ ('on-hold', 'On Hold'),
+ ('completed', 'Completed'),
+ ('cancelled', 'Cancelled'),
+ ('refunded', 'Refunded'),
+ ('failed', 'Failed'),
+ ('trash', 'Trashed'),
+ ], string='WC Status', tracking=True)
invoice_id = fields.Many2one('account.move')
invoice_synced = fields.Boolean()
company_id = fields.Many2one(
@@ -27,9 +40,123 @@ class WooOrder(models.Model):
('shipped', 'Shipped'),
('completed', 'Completed'),
('cancelled', 'Cancelled'),
- ], default='new')
+ ], default='new', tracking=True)
+
+ WC_STATUS_TO_STATE = {
+ 'pending': 'new',
+ 'on-hold': 'new',
+ 'processing': 'confirmed',
+ 'completed': 'completed',
+ 'cancelled': 'cancelled',
+ 'refunded': 'cancelled',
+ 'failed': 'cancelled',
+ 'trash': 'cancelled',
+ }
+
+ @api.onchange('woo_status')
+ def _onchange_woo_status(self):
+ if self.woo_status:
+ self.state = self.WC_STATUS_TO_STATE.get(self.woo_status, self.state)
+
+ def _set_woo_status(self, wc_status):
+ """Set woo_status and auto-map to Odoo state."""
+ vals = {}
+ if wc_status:
+ vals['woo_status'] = wc_status
+ mapped_state = self.WC_STATUS_TO_STATE.get(wc_status)
+ if mapped_state:
+ vals['state'] = mapped_state
+ if vals:
+ self.write(vals)
shipment_ids = fields.One2many('woo.shipment', 'order_id')
+ delivery_count = fields.Integer(compute='_compute_delivery_count')
+ invoice_count = fields.Integer(compute='_compute_invoice_count')
+
+ @api.depends('woo_order_number', 'sale_order_id', 'sale_order_id.name')
+ def _compute_display_name(self):
+ for rec in self:
+ parts = []
+ if rec.woo_order_number:
+ parts.append('WC#%s' % rec.woo_order_number)
+ if rec.sale_order_id:
+ parts.append(rec.sale_order_id.name)
+ rec.display_name = ' — '.join(parts) if parts else 'WC Order #%s' % rec.id
+
+ @api.depends('sale_order_id')
+ def _compute_delivery_count(self):
+ for rec in self:
+ if rec.sale_order_id:
+ rec.delivery_count = self.env['stock.picking'].search_count([
+ ('origin', '=', rec.sale_order_id.name),
+ ])
+ else:
+ rec.delivery_count = 0
+
+ @api.depends('sale_order_id')
+ def _compute_invoice_count(self):
+ for rec in self:
+ if rec.sale_order_id:
+ rec.invoice_count = self.env['account.move'].search_count([
+ ('invoice_origin', '=', rec.sale_order_id.name),
+ ('move_type', 'in', ['out_invoice', 'out_refund']),
+ ])
+ else:
+ rec.invoice_count = 0
+
+ def action_view_sale_order(self):
+ self.ensure_one()
+ if not self.sale_order_id:
+ return
+ return {
+ 'type': 'ir.actions.act_window',
+ 'res_model': 'sale.order',
+ 'res_id': self.sale_order_id.id,
+ 'views': [(False, 'form')],
+ }
+
+ def action_view_deliveries(self):
+ self.ensure_one()
+ pickings = self.env['stock.picking'].search([
+ ('origin', '=', self.sale_order_id.name),
+ ])
+ if len(pickings) == 1:
+ return {
+ 'type': 'ir.actions.act_window',
+ 'res_model': 'stock.picking',
+ 'res_id': pickings.id,
+ 'views': [(False, 'form')],
+ }
+ return {
+ 'type': 'ir.actions.act_window',
+ 'name': 'Deliveries',
+ 'res_model': 'stock.picking',
+ 'view_mode': 'list,form',
+ 'domain': [('origin', '=', self.sale_order_id.name)],
+ }
+
+ def action_view_invoices(self):
+ self.ensure_one()
+ invoices = self.env['account.move'].search([
+ ('invoice_origin', '=', self.sale_order_id.name),
+ ('move_type', 'in', ['out_invoice', 'out_refund']),
+ ])
+ if len(invoices) == 1:
+ return {
+ 'type': 'ir.actions.act_window',
+ 'res_model': 'account.move',
+ 'res_id': invoices.id,
+ 'views': [(False, 'form')],
+ }
+ return {
+ 'type': 'ir.actions.act_window',
+ 'name': 'Invoices',
+ 'res_model': 'account.move',
+ 'view_mode': 'list,form',
+ 'domain': [('invoice_origin', '=', self.sale_order_id.name),
+ ('move_type', 'in', ['out_invoice', 'out_refund'])],
+ }
+
# ------------------------------------------------------------------
# Push methods (Task 20)
# ------------------------------------------------------------------
@@ -58,7 +185,7 @@ class WooOrder(models.Model):
update_data['meta_data'] = meta
client.update_order(self.woo_order_id, update_data)
- self.woo_status = 'completed'
+ self._set_woo_status('completed')
self.state = 'shipped'
self.instance_id._log_sync(
@@ -71,8 +198,7 @@ class WooOrder(models.Model):
self.ensure_one()
client = self.instance_id._get_client()
client.update_order(self.woo_order_id, {'status': 'completed'})
- self.woo_status = 'completed'
- self.state = 'completed'
+ self._set_woo_status('completed')
self.instance_id._log_sync(
'order', 'odoo_to_woo', self.sale_order_id.name,
diff --git a/fusion-woo-odoo/fusion_woocommerce/models/woo_pricelist_map.py b/fusion-woo-odoo/fusion_woocommerce/models/woo_pricelist_map.py
index 0f033905..f483c4dd 100644
--- a/fusion-woo-odoo/fusion_woocommerce/models/woo_pricelist_map.py
+++ b/fusion-woo-odoo/fusion_woocommerce/models/woo_pricelist_map.py
@@ -4,6 +4,7 @@ from odoo import api, fields, models
class WooPricelistMap(models.Model):
_name = 'woo.pricelist.map'
_description = 'WooCommerce Pricelist Mapping'
+ _rec_name = 'woo_role_name'
instance_id = fields.Many2one('woo.instance', required=True, ondelete='cascade')
pricelist_id = fields.Many2one('product.pricelist', required=True)
diff --git a/fusion-woo-odoo/fusion_woocommerce/models/woo_product_map.py b/fusion-woo-odoo/fusion_woocommerce/models/woo_product_map.py
index 2df7c98d..6cd6375a 100644
--- a/fusion-woo-odoo/fusion_woocommerce/models/woo_product_map.py
+++ b/fusion-woo-odoo/fusion_woocommerce/models/woo_product_map.py
@@ -14,6 +14,7 @@ _logger = logging.getLogger(__name__)
class WooProductMap(models.Model):
_name = 'woo.product.map'
_description = 'WooCommerce Product Mapping'
+ _rec_name = 'woo_product_name'
instance_id = fields.Many2one('woo.instance', required=True, ondelete='cascade')
product_id = fields.Many2one('product.product')
diff --git a/fusion-woo-odoo/fusion_woocommerce/models/woo_return.py b/fusion-woo-odoo/fusion_woocommerce/models/woo_return.py
index 6b0feadb..53acf19c 100644
--- a/fusion-woo-odoo/fusion_woocommerce/models/woo_return.py
+++ b/fusion-woo-odoo/fusion_woocommerce/models/woo_return.py
@@ -9,6 +9,7 @@ _logger = logging.getLogger(__name__)
class WooReturn(models.Model):
_name = 'woo.return'
_description = 'WooCommerce Return'
+ _rec_name = 'order_id'
instance_id = fields.Many2one('woo.instance', required=True, ondelete='cascade')
order_id = fields.Many2one('woo.order', required=True)
diff --git a/fusion-woo-odoo/fusion_woocommerce/models/woo_shipment.py b/fusion-woo-odoo/fusion_woocommerce/models/woo_shipment.py
index 9a4d19cd..72f4e94a 100644
--- a/fusion-woo-odoo/fusion_woocommerce/models/woo_shipment.py
+++ b/fusion-woo-odoo/fusion_woocommerce/models/woo_shipment.py
@@ -4,6 +4,7 @@ from odoo import fields, models
class WooShipment(models.Model):
_name = 'woo.shipment'
_description = 'WooCommerce Shipment'
+ _rec_name = 'tracking_number'
order_id = fields.Many2one('woo.order', required=True, ondelete='cascade')
picking_id = fields.Many2one('stock.picking')
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 4ce09116..39ccadd8 100644
--- a/fusion-woo-odoo/fusion_woocommerce/models/woo_sync_log.py
+++ b/fusion-woo-odoo/fusion_woocommerce/models/woo_sync_log.py
@@ -5,6 +5,7 @@ class WooSyncLog(models.Model):
_name = 'woo.sync.log'
_description = 'WooCommerce Sync Log'
_order = 'create_date desc'
+ _rec_name = 'record_ref'
instance_id = fields.Many2one('woo.instance', ondelete='cascade')
sync_type = fields.Selection([
diff --git a/fusion-woo-odoo/fusion_woocommerce/models/woo_tax_map.py b/fusion-woo-odoo/fusion_woocommerce/models/woo_tax_map.py
index 78360edf..042cb65a 100644
--- a/fusion-woo-odoo/fusion_woocommerce/models/woo_tax_map.py
+++ b/fusion-woo-odoo/fusion_woocommerce/models/woo_tax_map.py
@@ -4,6 +4,7 @@ from odoo import api, fields, models
class WooTaxMap(models.Model):
_name = 'woo.tax.map'
_description = 'WooCommerce Tax Mapping'
+ _rec_name = 'woo_tax_class_name'
instance_id = fields.Many2one('woo.instance', required=True, ondelete='cascade')
tax_id = fields.Many2one('account.tax', string='Odoo Tax')
diff --git a/fusion-woo-odoo/fusion_woocommerce/views/woo_order_views.xml b/fusion-woo-odoo/fusion_woocommerce/views/woo_order_views.xml
index 24d39448..e8d07410 100644
--- a/fusion-woo-odoo/fusion_woocommerce/views/woo_order_views.xml
+++ b/fusion-woo-odoo/fusion_woocommerce/views/woo_order_views.xml
@@ -31,10 +31,32 @@
statusbar_visible="new,confirmed,shipped,completed"/>
+
+
+
+
+
+
-
-
@@ -60,6 +82,7 @@
+