From c8bbeac919ea4539145e376374dd8a16979f4b63 Mon Sep 17 00:00:00 2001 From: Marc Durepos Date: Thu, 21 Nov 2024 16:33:18 -0500 Subject: [PATCH] [ENH] delivery_carrier_partner_account: Add ppc billing mode. Adds a Prepaid & Charge billing mode to carrier.account.mixin and overrides the stock.picking method that sets the shipping cost on sales orders after shipping. This modifies the behaviour of "invoicing policy" on delivery.carrier when a delivery billing mode is selected on the SO or picking. --- .../models/carrier_account_mixin.py | 10 +++++--- .../models/sales_order.py | 8 ++++-- .../models/stock_picking.py | 14 +++++++++++ .../tests/test_carrier_account_mixin.py | 25 +++++++++++++++++++ 4 files changed, 51 insertions(+), 6 deletions(-) diff --git a/delivery_carrier_partner_account/models/carrier_account_mixin.py b/delivery_carrier_partner_account/models/carrier_account_mixin.py index 5b43ce1..4ca287f 100644 --- a/delivery_carrier_partner_account/models/carrier_account_mixin.py +++ b/delivery_carrier_partner_account/models/carrier_account_mixin.py @@ -28,13 +28,15 @@ class CarrierAccountMixin(models.AbstractModel): delivery_billing_mode = fields.Selection( [ ("no charge", "No Charge"), + ("ppc", "Prepaid & Charge"), ("prepaid", "Prepaid"), ("collect", "Collect"), ("third party", "Third Party"), ], help=_( """ - Prepaid: The shipper will pay the carrier (and may bill the client). + Prepaid: The shipper will pay the carrier and the client pays the estimate. + Prepaid & Charge: The shipper will pay the carrier and bill the client based on the actual price paid. Collect: The recipient will be billed (account information needed) Third Party: A third party will be billed (account information needed) """ @@ -93,7 +95,7 @@ class CarrierAccountMixin(models.AbstractModel): ), ] ) - if rec.delivery_billing_mode == "prepaid": + if rec.delivery_billing_mode in ["prepaid", "ppc"]: rec.valid_carrier_account_ids = ( rec.sender_id.carrier_account_ids.filtered( lambda account: account.delivery_carrier_id == rec.carrier_id @@ -114,7 +116,7 @@ class CarrierAccountMixin(models.AbstractModel): When it is third party, any account matching the carrier_id is fine. - When it is prepaid, we select the company's account. + When it is prepaid or ppc, we select the company's account. """ for rec in self: if rec.delivery_billing_mode == "collect": @@ -135,7 +137,7 @@ class CarrierAccountMixin(models.AbstractModel): if rec.delivery_billing_mode == "third party": if rec.carrier_account_id not in rec.valid_carrier_account_ids: rec.carrier_account_id = False - if rec.delivery_billing_mode == "prepaid": + if rec.delivery_billing_mode in ["prepaid", "ppc"]: rec.carrier_account_id = ( self.env["delivery.carrier.account"] .search([("partner_id", "=", rec.sender_id.id)]) diff --git a/delivery_carrier_partner_account/models/sales_order.py b/delivery_carrier_partner_account/models/sales_order.py index b9813f8..949eba2 100644 --- a/delivery_carrier_partner_account/models/sales_order.py +++ b/delivery_carrier_partner_account/models/sales_order.py @@ -32,8 +32,12 @@ class SalesOrder(models.Model): def _create_delivery_line(self, carrier, price_unit): line = super()._create_delivery_line(carrier, price_unit) name = line.name - delivery_billing_mode = self.env.context.get("delivery_billing_mode", False) - carrier_account = self.env.context.get("carrier_account", False) + delivery_billing_mode = self.delivery_billing_mode or self.env.context.get( + "delivery_billing_mode", False + ) + carrier_account = self.carrier_account_id or self.env.context.get( + "carrier_account", False + ) if delivery_billing_mode: name = name + f" [{delivery_billing_mode.upper()}]" if delivery_billing_mode in ["collect", "third party"] and carrier_account: diff --git a/delivery_carrier_partner_account/models/stock_picking.py b/delivery_carrier_partner_account/models/stock_picking.py index 0c7dd62..d39e949 100644 --- a/delivery_carrier_partner_account/models/stock_picking.py +++ b/delivery_carrier_partner_account/models/stock_picking.py @@ -29,3 +29,17 @@ class Picking(models.Model): def _inverse_delivery_billing_mode(self): pass + + def _add_delivery_cost_to_so(self): + self.ensure_one() + if not self.delivery_billing_mode or self.delivery_billing_mode != "ppc": + super()._add_delivery_cost_to_so() + else: + sale_order = self.sale_id + delivery_lines = self._get_matching_delivery_lines() + if not delivery_lines: + delivery_lines = sale_order.with_context( + delivery_billing_mode="ppc", carrier_account=self.carrier_account_id + )._create_delivery_line(self.carrier_id, self.carrier_price) + vals = self._prepare_sale_delivery_line_vals() + delivery_lines[0].write(vals) diff --git a/delivery_carrier_partner_account/tests/test_carrier_account_mixin.py b/delivery_carrier_partner_account/tests/test_carrier_account_mixin.py index bbf6b2e..15593ce 100644 --- a/delivery_carrier_partner_account/tests/test_carrier_account_mixin.py +++ b/delivery_carrier_partner_account/tests/test_carrier_account_mixin.py @@ -22,6 +22,17 @@ class TestCarrierAccountMixin(TestCarrierAccountCommon): ) self.assertEqual(picking.carrier_account_id, self.sender_account_2) + def test_compute_account_ppc_order(self): + picking = self.env["stock.picking"].create( + { + "partner_id": self.client_partner.id, + "carrier_id": self.delivery_carrier_2.id, + "picking_type_id": self.env.ref("stock.warehouse0").out_type_id.id, + "delivery_billing_mode": "ppc", + } + ) + self.assertEqual(picking.carrier_account_id, self.sender_account_2) + def test_compute_account_third_party_order(self): picking = self.env["stock.picking"].create( { @@ -76,6 +87,20 @@ class TestCarrierAccountMixin(TestCarrierAccountCommon): self.third_party_account_1, ) + def test_incorrect_ppc_account(self): + with self.assertRaises(UserError): + self._create_sale_order( + "ppc", + self.delivery_carrier_1, + self.client_account_1, + ) + with self.assertRaises(UserError): + self._create_sale_order( + "ppc", + self.delivery_carrier_1, + self.third_party_account_1, + ) + def test_incorrect_third_party_account(self): with self.assertRaises(UserError): self._create_sale_order(