attempt fix to delivery carrier account - selecting collect account raising error

This commit is contained in:
Marc Durepos 2025-02-26 12:14:15 -05:00
parent 1da36c1e1c
commit 31892a892a
3 changed files with 71 additions and 107 deletions

View file

@ -100,32 +100,24 @@ class CarrierAccountMixin(models.AbstractModel):
Returns: Returns:
Tuple containing: Tuple containing:
- partners: recordset of partners that can have valid accounts - partners: recordset of partners that can have valid accounts
- is_third_party: boolean indicating if this is a third party billing mode
- invalid_partners: for third party mode, partners that cannot own the account
""" """
self.ensure_one() self.ensure_one()
invalid_partners = self.env["res.partner"].browse() invalid_partners = self.env["res.partner"]
match self.delivery_billing_mode: match self.delivery_billing_mode:
case "collect": case "collect":
return ( return self.recipient_id | self.recipient_id.commercial_partner_id
self.recipient_id | self.recipient_id.commercial_partner_id,
False,
invalid_partners,
)
case "prepaid" | "ppc" | "no charge": case "prepaid" | "ppc" | "no charge":
return ( return self.sender_id | self.sender_id.commercial_partner_id
self.sender_id | self.sender_id.commercial_partner_id,
False,
invalid_partners,
)
case "third party": case "third party":
invalid_partners = ( invalid_partners = (
self.recipient_id | self.recipient_id.commercial_partner_id self.recipient_id | self.recipient_id.commercial_partner_id
) | (self.sender_id | self.sender_id.commercial_partner_id) ) | (self.sender_id | self.sender_id.commercial_partner_id)
return self.env["res.partner"].browse(), True, invalid_partners return self.env["res.partner"].search(
[("id", "not in", invalid_partners.ids)]
)
case _: case _:
return self.env["res.partner"].browse(), False, invalid_partners return self.env["res.partner"]
@api.depends( @api.depends(
"sender_id", "sender_id",
@ -134,40 +126,26 @@ class CarrierAccountMixin(models.AbstractModel):
) )
def _compute_carrier_id(self): def _compute_carrier_id(self):
for rec in self: for rec in self:
# Only set carrier if not already set
if not rec.carrier_id: if not rec.carrier_id:
rec.carrier_id = rec._get_default_carrier() rec.carrier_id = rec._get_default_carrier()
continue elif (
rec.delivery_billing_mode
and rec.carrier_id not in rec.valid_carrier_ids
and not rec._has_valid_account_for_carrier()
):
rec.carrier_id = rec._get_default_carrier()
# Don't reset carrier if we're changing billing mode and there's a valid account def _has_valid_account_for_carrier(self):
if rec.delivery_billing_mode: """Check if there's a valid account for the current carrier and billing mode."""
partners, is_third_party, invalid_partners = ( self.ensure_one()
rec._get_valid_carrier_partners() if not self.carrier_id or not self.delivery_billing_mode:
) return False
if is_third_party: partners = self._get_valid_carrier_partners()
# For third party, check if there's any account for this carrier valid_accounts = partners.mapped("carrier_account_ids").filtered(
# that doesn't belong to sender or recipient lambda account: account.delivery_carrier_id == self.carrier_id
has_valid_account = bool( )
self.env["delivery.carrier.account"].search_count( return bool(valid_accounts)
[
("delivery_carrier_id", "=", rec.carrier_id.id),
("partner_id", "not in", invalid_partners.ids),
]
)
)
if has_valid_account:
continue
else:
# Check if there's a valid account for this carrier
if any(
account.delivery_carrier_id == rec.carrier_id
for account in partners.mapped("carrier_account_ids")
):
continue
# If we get here, there's no valid account for this carrier
rec.carrier_id = rec._get_default_carrier()
def _get_default_carrier(self): def _get_default_carrier(self):
self.ensure_one() self.ensure_one()
@ -253,69 +231,25 @@ class CarrierAccountMixin(models.AbstractModel):
) )
def _compute_valid_carrier_account_ids(self): def _compute_valid_carrier_account_ids(self):
for rec in self: for rec in self:
match rec.delivery_billing_mode: partners = rec._get_valid_carrier_partners()
case "collect": if rec.carrier_id and partners:
rec.valid_carrier_account_ids = ( rec.valid_carrier_account_ids = partners.mapped(
(rec.recipient_id | rec.recipient_id.commercial_partner_id) "carrier_account_ids"
.mapped("carrier_account_ids") ).filtered(
.filtered( lambda account: account.delivery_carrier_id == rec.carrier_id
lambda account: account.delivery_carrier_id )
== rec.carrier_id else:
) rec.valid_carrier_account_ids = partners.mapped("carrier_account_ids")
)
case "third party":
rec.valid_carrier_account_ids = self.env[
"delivery.carrier.account"
].search(
[
("delivery_carrier_id", "=", rec.carrier_id.id),
(
"partner_id",
"not in",
[
rec.sender_id.id,
rec.sender_id.commercial_partner_id.id,
rec.recipient_id.id,
rec.recipient_id.commercial_partner_id.id,
],
),
]
)
case "prepaid" | "ppc" | "no charge":
rec.valid_carrier_account_ids = (
(rec.sender_id | rec.sender_id.commercial_partner_id)
.mapped("carrier_account_ids")
.filtered(
lambda account: account.delivery_carrier_id
== rec.carrier_id
)
)
case _:
rec.valid_carrier_account_ids = self.env[
"delivery.carrier.account"
].search([])
@api.depends("delivery_billing_mode", "sender_id", "recipient_id") @api.depends("delivery_billing_mode", "sender_id", "recipient_id")
def _compute_valid_carrier_ids(self): def _compute_valid_carrier_ids(self):
"""Compute all valid carriers for the current billing mode and partners.""" """Compute all valid carriers for the current billing mode and partners."""
for rec in self: for rec in self:
partners, is_third_party, invalid_partners = ( partners = rec._get_valid_carrier_partners()
rec._get_valid_carrier_partners() rec.valid_carrier_ids = partners.mapped(
"carrier_account_ids.delivery_carrier_id"
) )
if is_third_party:
# For third party, all carriers with accounts not belonging to sender/recipient are valid
accounts = self.env["delivery.carrier.account"].search(
[
("partner_id", "not in", invalid_partners.ids),
]
)
rec.valid_carrier_ids = accounts.mapped("delivery_carrier_id")
else:
rec.valid_carrier_ids = partners.mapped(
"carrier_account_ids.delivery_carrier_id"
)
def _on_carrier_fields_changed(self): def _on_carrier_fields_changed(self):
pass pass
@ -325,8 +259,20 @@ class CarrierAccountMixin(models.AbstractModel):
if ( if (
rec.carrier_account_id rec.carrier_account_id
and rec.delivery_billing_mode and rec.delivery_billing_mode
and rec.valid_carrier_account_ids # Use the computed field directly
and rec.carrier_account_id not in rec.valid_carrier_account_ids and rec.carrier_account_id not in rec.valid_carrier_account_ids
): ):
_logger.warning(
"Billing mode: %s, sender: %s (commercial: %s), recipient: %s (commercial: %s), account: %s, id: %s, valid: %s",
rec.delivery_billing_mode,
rec.sender_id.name,
rec.sender_id.commercial_partner_id.name,
rec.recipient_id.name,
rec.recipient_id.commercial_partner_id.name,
rec.carrier_account_id.partner_id.name,
rec.carrier_account_id.id,
rec.valid_carrier_account_ids.ids,
)
if rec.delivery_billing_mode == "collect": if rec.delivery_billing_mode == "collect":
raise UserError( raise UserError(

View file

@ -1,4 +1,5 @@
from .test_carrier_account_common import TestCarrierAccountCommon from .test_carrier_account_common import TestCarrierAccountCommon
from odoo.tests import Form
class TestSalesOrder(TestCarrierAccountCommon): class TestSalesOrder(TestCarrierAccountCommon):
@ -21,12 +22,13 @@ class TestSalesOrder(TestCarrierAccountCommon):
def test_prepaid_sale_order_line_gets_proper_name(self): def test_prepaid_sale_order_line_gets_proper_name(self):
order = self.env["sale.order"].create({"partner_id": self.client_partner.id}) order = self.env["sale.order"].create({"partner_id": self.client_partner.id})
wiz = self._get_shipping_wizard(order) wiz = self._get_shipping_wizard(order)
wiz.carrier_id = self.delivery_carrier_1 with Form(wiz) as form:
wiz.delivery_billing_mode = "prepaid" form.carrier_id = self.delivery_carrier_2
form.delivery_billing_mode = "prepaid"
wiz.button_confirm() wiz.button_confirm()
self.assertEqual( self.assertEqual(
order.order_line[0].name, order.order_line[0].name,
f"{self.delivery_carrier_1.name} [PREPAID]", f"{self.delivery_carrier_2.name} [PREPAID]",
) )
def test_third_party_sale_order_line_gets_proper_name(self): def test_third_party_sale_order_line_gets_proper_name(self):

View file

@ -15,9 +15,25 @@ class ChooseDeliveryCarrier(models.TransientModel):
if self.delivery_billing_mode: if self.delivery_billing_mode:
vals.update(delivery_billing_mode=self.delivery_billing_mode) vals.update(delivery_billing_mode=self.delivery_billing_mode)
if self.carrier_account_id: if self.carrier_account_id:
vals.update(carrier_account_id=self.carrier_account_id) vals.update(carrier_account_id=self.carrier_account_id.id)
if self.carrier_id: if self.carrier_id:
vals.update(carrier_id=self.carrier_id.id) vals.update(carrier_id=self.carrier_id.id)
self.order_id.with_context(no_carrier_update=True).write(vals)
# Ensure we have a valid carrier account
if (
self.carrier_id
and self.delivery_billing_mode
and not self.carrier_account_id
):
# Force recompute of valid carrier accounts
self._compute_valid_carrier_account_ids()
default_account = self._get_default_carrier_account()
if default_account:
vals.update(carrier_account_id=default_account.id)
# Write values to the order before calling super
if vals:
self.order_id.with_context(no_carrier_update=True).write(vals)
res = super().button_confirm() res = super().button_confirm()
return res return res