diff --git a/purchase_work_acceptance/models/account_move.py b/purchase_work_acceptance/models/account_move.py
index b35a09185ce..f9f832dbc33 100644
--- a/purchase_work_acceptance/models/account_move.py
+++ b/purchase_work_acceptance/models/account_move.py
@@ -1,8 +1,11 @@
# Copyright 2019 Ecosoft Co., Ltd. (http://ecosoft.co.th)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
+from collections import defaultdict
+
from odoo import _, api, fields, models
from odoo.exceptions import ValidationError
+from odoo.tools import float_compare
class AccountMove(models.Model):
@@ -29,38 +32,52 @@ def _compute_require_wa(self):
)
rec.require_wa = self.wa_id and enforce_wa
+ def _aggregate_qty_by_product(self, lines, qty_field, uom_field):
+ """Aggregate quantities by product, converted to the product's base UoM."""
+ result = defaultdict(float)
+ for line in lines:
+ uom = getattr(line, uom_field)
+ qty = uom._compute_quantity(
+ getattr(line, qty_field), line.product_id.uom_id
+ )
+ if qty > 0.0:
+ result[line.product_id.id] += qty
+ return dict(result)
+
+ def _check_quantity_wa(self):
+ self.ensure_one()
+ precision = self.env["decimal.precision"].precision_get(
+ "Product Unit of Measure"
+ )
+ wa_qty = self._aggregate_qty_by_product(
+ self.wa_id.wa_line_ids, "product_qty", "product_uom"
+ )
+ invoice_qty = self._aggregate_qty_by_product(
+ self.invoice_line_ids.filtered(lambda line: line.control_wa),
+ "quantity",
+ "product_uom_id",
+ )
+ all_products = set(wa_qty.keys()) | set(invoice_qty.keys())
+ for product_id in all_products:
+ wa = wa_qty.get(product_id, 0.0)
+ inv = invoice_qty.get(product_id, 0.0)
+ if float_compare(wa, inv, precision_digits=precision) != 0:
+ product = self.env["product.product"].browse(product_id)
+ raise ValidationError(
+ _(
+ "Quantity mismatch for product '%(product)s': "
+ "WA quantity = %(wa_qty)s, Invoice quantity = %(inv_qty)s",
+ product=product.display_name,
+ wa_qty=wa,
+ inv_qty=inv,
+ )
+ )
+
def action_post(self):
for rec in self:
- if rec.wa_id:
- wa_line = {}
- for line in rec.wa_id.wa_line_ids:
- qty = line.product_uom._compute_quantity(
- line.product_qty, line.product_id.uom_id
- )
- if qty > 0.0:
- if line.product_id.id in wa_line.keys():
- qty_old = wa_line[line.product_id.id]
- wa_line[line.product_id.id] = qty_old + qty
- else:
- wa_line[line.product_id.id] = qty
- invoice_line = {}
- for line in rec.invoice_line_ids:
- qty = line.product_uom_id._compute_quantity(
- line.quantity, line.product_id.uom_id
- )
- if qty > 0.0:
- if line.product_id.id in invoice_line.keys():
- qty_old = invoice_line[line.product_id.id]
- invoice_line[line.product_id.id] = qty_old + qty
- else:
- invoice_line[line.product_id.id] = qty
- if wa_line != invoice_line:
- raise ValidationError(
- _(
- "You cannot validate a bill if Quantity not equal "
- "accepted quantity"
- )
- )
+ if not rec.wa_id:
+ continue
+ rec._check_quantity_wa()
return super().action_post()
@api.model
@@ -71,3 +88,9 @@ def create(self, vals):
lines = filter(lambda l: len(l) == 3 and l[2].get("quantity") != 0, lines)
vals["invoice_line_ids"] = list(lines)
return super().create(vals)
+
+
+class AccountMoveLine(models.Model):
+ _inherit = "account.move.line"
+
+ control_wa = fields.Boolean(default=True, copy=False)
diff --git a/purchase_work_acceptance/views/account_move_views.xml b/purchase_work_acceptance/views/account_move_views.xml
index 1b2e2c51965..068dcaf4d98 100644
--- a/purchase_work_acceptance/views/account_move_views.xml
+++ b/purchase_work_acceptance/views/account_move_views.xml
@@ -14,6 +14,27 @@
attrs="{'required': [('require_wa','=', True)], 'invisible': [('wa_id', '=', False)]}"
/>
+
+
+
+
+
+
+
+
+
+
+
+