Initial commit
This commit is contained in:
116
fusion_inventory_sync/models/stock_move.py
Normal file
116
fusion_inventory_sync/models/stock_move.py
Normal file
@@ -0,0 +1,116 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
import logging
|
||||
from odoo import models, fields
|
||||
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class StockMove(models.Model):
|
||||
"""Extend stock moves to push changes to remote Odoo instance."""
|
||||
_inherit = 'stock.move'
|
||||
|
||||
def _action_done(self, cancel_backorder=False):
|
||||
"""Override to trigger remote sync after stock moves complete."""
|
||||
res = super()._action_done(cancel_backorder=cancel_backorder)
|
||||
|
||||
# After moves are done, queue a remote stock push for affected products
|
||||
try:
|
||||
self._push_stock_to_remote()
|
||||
except Exception as e:
|
||||
# Never block local operations due to sync failure
|
||||
_logger.warning(f'Remote stock push failed (non-blocking): {e}')
|
||||
|
||||
return res
|
||||
|
||||
def _push_stock_to_remote(self):
|
||||
"""Push stock level changes to the remote Odoo instance.
|
||||
|
||||
Only pushes for products that have a sync mapping.
|
||||
Runs async-safe: failures don't block local operations.
|
||||
"""
|
||||
if not self:
|
||||
return
|
||||
|
||||
# Get unique product templates from completed moves
|
||||
product_tmpls = self.mapped('product_id.product_tmpl_id')
|
||||
if not product_tmpls:
|
||||
return
|
||||
|
||||
# Find sync mappings for these products
|
||||
Mapping = self.env['fusion.product.sync.mapping']
|
||||
mappings = Mapping.search([
|
||||
('local_product_id', 'in', product_tmpls.ids),
|
||||
('config_id.active', '=', True),
|
||||
('config_id.state', '=', 'connected'),
|
||||
('remote_product_id', '!=', 0),
|
||||
])
|
||||
|
||||
if not mappings:
|
||||
return
|
||||
|
||||
# Group by config for efficient batch push
|
||||
configs = {}
|
||||
for mapping in mappings:
|
||||
config = mapping.config_id
|
||||
if config.id not in configs:
|
||||
configs[config.id] = {
|
||||
'config': config,
|
||||
'mappings': self.env['fusion.product.sync.mapping'],
|
||||
}
|
||||
configs[config.id]['mappings'] |= mapping
|
||||
|
||||
for config_data in configs.values():
|
||||
config = config_data['config']
|
||||
config_mappings = config_data['mappings']
|
||||
try:
|
||||
self._push_stock_levels(config, config_mappings)
|
||||
except Exception as e:
|
||||
_logger.warning(
|
||||
f'Failed to push stock to {config.name}: {e}'
|
||||
)
|
||||
|
||||
def _push_stock_levels(self, config, mappings):
|
||||
"""Push current local stock levels to the remote instance.
|
||||
|
||||
This updates the remote side with our current on-hand qty
|
||||
so the remote instance knows what we have available.
|
||||
"""
|
||||
uid, models_proxy = config._get_xmlrpc_connection()
|
||||
|
||||
for mapping in mappings:
|
||||
local_product = mapping.local_product_id
|
||||
if not local_product:
|
||||
continue
|
||||
|
||||
# Get current local stock for this product
|
||||
local_qty = local_product.qty_available
|
||||
local_forecast = local_product.virtual_available
|
||||
|
||||
# Update the mapping record with current local stock
|
||||
mapping.write({
|
||||
'last_stock_sync': fields.Datetime.now(),
|
||||
})
|
||||
|
||||
# Log the push for debugging
|
||||
_logger.info(
|
||||
f'Stock push: {local_product.name} -> {config.name} '
|
||||
f'(local_qty={local_qty}, remote_id={mapping.remote_product_id})'
|
||||
)
|
||||
|
||||
# Optionally update a custom field on the remote side
|
||||
# This writes to a field on the remote product to track
|
||||
# what the partner store has available
|
||||
try:
|
||||
models_proxy.execute_kw(
|
||||
config.db_name, uid, config.api_key,
|
||||
'product.template', 'write',
|
||||
[[mapping.remote_product_id], {
|
||||
'x_partner_qty_available': local_qty,
|
||||
}]
|
||||
)
|
||||
except Exception as e:
|
||||
# If the remote field doesn't exist yet, just log it
|
||||
_logger.debug(
|
||||
f'Could not update remote field x_partner_qty_available: {e}. '
|
||||
f'Create this field on the remote instance for full bi-directional sync.'
|
||||
)
|
||||
Reference in New Issue
Block a user