# -*- coding: utf-8 -*- # Copyright 2026 Nexa Systems Inc. # License OPL-1 (Odoo Proprietary License v1.0) import logging from odoo import models, fields, api _logger = logging.getLogger(__name__) class FusionWarehouseInventory(models.Model): _name = 'fusion.warehouse.inventory' _description = 'Shared Warehouse Inventory Ownership' _rec_name = 'display_name' _order = 'product_id, owner_config_id' product_id = fields.Many2one( 'product.product', string='Product', required=True, ondelete='cascade', index=True) product_tmpl_id = fields.Many2one( related='product_id.product_tmpl_id', store=True) lot_id = fields.Many2one( 'stock.lot', string='Serial/Lot', help='Serial number or lot for tracked products') owner_config_id = fields.Many2one( 'fusion.sync.config', string='Owner Instance', required=True, ondelete='restrict', help='The Odoo instance that owns this inventory') quantity = fields.Float(string='Quantity', default=1.0) location_bin = fields.Char( string='Bin / Shelf', help='Physical location within the shared warehouse') warehouse_location_id = fields.Many2one( 'stock.location', string='Warehouse Location', related='owner_config_id.warehouse_location_id', store=True) state = fields.Selection([ ('available', 'Available'), ('reserved', 'Reserved'), ('in_transit', 'In Transit'), ('transferred', 'Transferred'), ], string='Status', default='available', required=True, index=True) notes = fields.Text(string='Notes') display_name = fields.Char(compute='_compute_display_name') @api.depends('product_id', 'owner_config_id', 'quantity') def _compute_display_name(self): for rec in self: owner = rec.owner_config_id.name or 'Unknown' rec.display_name = f'{rec.product_id.name} ({rec.quantity} - {owner})' @api.model def get_available_for_product(self, product_id, exclude_owner_id=None): """Get available warehouse inventory for a product, optionally excluding an owner.""" domain = [ ('product_id', '=', product_id), ('state', '=', 'available'), ('quantity', '>', 0), ] if exclude_owner_id: domain.append(('owner_config_id', '!=', exclude_owner_id)) return self.search(domain) def action_reserve(self): for rec in self.filtered(lambda r: r.state == 'available'): rec.state = 'reserved' def action_mark_in_transit(self): for rec in self.filtered(lambda r: r.state in ('available', 'reserved')): rec.state = 'in_transit' def action_mark_transferred(self): for rec in self.filtered(lambda r: r.state == 'in_transit'): rec.state = 'transferred' def action_release(self): for rec in self.filtered(lambda r: r.state == 'reserved'): rec.state = 'available'