# -*- coding: utf-8 -*- # Copyright 2026 Nexa Systems Inc. # License OPL-1 (Odoo Proprietary License v1.0) """Phase A — carrier field + outbound shipment link tests on fp.receiving. See docs/superpowers/specs/2026-05-18-phase-a-shipping-carrier-foundation-design.md. """ from odoo.tests.common import TransactionCase class TestCarrierFields(TransactionCase): @classmethod def setUpClass(cls): super().setUpClass() cls.partner = cls.env['res.partner'].create({'name': 'CarrierCust'}) cls.product = cls.env['product.product'].create({'name': 'Widget'}) cls.so = cls.env['sale.order'].create({ 'partner_id': cls.partner.id, 'order_line': [(0, 0, { 'product_id': cls.product.id, 'product_uom_qty': 1, })], }) # Carrier records seeded by data/delivery_carrier_seed_data.xml. cls.carrier_ups = cls.env.ref( 'fusion_plating_receiving.delivery_carrier_ups', ) cls.carrier_fedex = cls.env.ref( 'fusion_plating_receiving.delivery_carrier_fedex', ) def _make_receiving(self, **kw): vals = {'sale_order_id': self.so.id} vals.update(kw) return self.env['fp.receiving'].create(vals) # ---- Field existence ------------------------------------------------ def test_carrier_id_field_exists_on_receiving(self): recv = self._make_receiving() self.assertIn('x_fc_carrier_id', recv._fields) def test_outbound_shipment_id_field_exists_on_receiving(self): recv = self._make_receiving() self.assertIn('x_fc_outbound_shipment_id', recv._fields) # ---- action_create_outbound_shipment -------------------------------- def test_action_create_outbound_shipment_creates_draft(self): recv = self._make_receiving(x_fc_carrier_id=self.carrier_ups.id) self.assertFalse(recv.x_fc_outbound_shipment_id) recv.action_create_outbound_shipment() self.assertTrue(recv.x_fc_outbound_shipment_id) ship = recv.x_fc_outbound_shipment_id self.assertEqual(ship.status, 'draft') self.assertEqual(ship.carrier_id, self.carrier_ups) self.assertEqual(ship.sale_order_id, self.so) def test_action_create_outbound_shipment_idempotent(self): recv = self._make_receiving(x_fc_carrier_id=self.carrier_ups.id) recv.action_create_outbound_shipment() first_ship = recv.x_fc_outbound_shipment_id recv.action_create_outbound_shipment() # Second call must not create a new shipment. self.assertEqual(recv.x_fc_outbound_shipment_id, first_ship) count = self.env['fusion.shipment'].search_count([ ('sale_order_id', '=', self.so.id), ]) self.assertEqual(count, 1) # ---- onchange propagation ------------------------------------------- def test_carrier_id_change_propagates_to_draft_shipment(self): recv = self._make_receiving(x_fc_carrier_id=self.carrier_ups.id) recv.action_create_outbound_shipment() ship = recv.x_fc_outbound_shipment_id self.assertEqual(ship.carrier_id, self.carrier_ups) # Onchange triggers via the Form helper — we simulate by calling # the handler directly after writing. recv.x_fc_carrier_id = self.carrier_fedex.id recv._onchange_x_fc_carrier_id() self.assertEqual(ship.carrier_id, self.carrier_fedex) def test_carrier_id_change_does_not_propagate_to_confirmed_shipment(self): recv = self._make_receiving(x_fc_carrier_id=self.carrier_ups.id) recv.action_create_outbound_shipment() ship = recv.x_fc_outbound_shipment_id # Confirm the shipment — propagation must stop. ship.status = 'confirmed' recv.x_fc_carrier_id = self.carrier_fedex.id recv._onchange_x_fc_carrier_id() # Confirmed shipment retains the original carrier. self.assertEqual(ship.carrier_id, self.carrier_ups)