diff --git a/rma_account/models/rma_operation.py b/rma_account/models/rma_operation.py
index bf21ab55..14d7b279 100644
--- a/rma_account/models/rma_operation.py
+++ b/rma_account/models/rma_operation.py
@@ -28,6 +28,16 @@ class RmaOperation(models.Model):
comodel_name="account.journal",
compute="_compute_domain_valid_journal",
)
+ automated_refund = fields.Boolean(
+ help="In the scenario where a company uses anglo-saxon accounting, if "
+ "you receive products from a customer and don't expect to refund the customer "
+ "but send a replacement unit, mark this flag to be accounting consistent"
+ )
+ refund_free_of_charge = fields.Boolean(
+ help="In case of automated refund you should mark this option as long automated"
+ "refunds mean to compensate Stock Interim accounts only without hitting"
+ "Accounts receivable"
+ )
@api.onchange("type")
def _compute_domain_valid_journal(self):
@@ -40,3 +50,9 @@ class RmaOperation(models.Model):
rec.valid_refund_journal_ids = self.env["account.journal"].search(
[("type", "=", "purchase")]
)
+
+ @api.onchange("automated_refund")
+ def _onchange_automated_refund(self):
+ for rec in self:
+ if rec.automated_refund:
+ rec.refund_free_of_charge = True
diff --git a/rma_account/models/rma_order_line.py b/rma_account/models/rma_order_line.py
index 8c43711b..01535fe8 100644
--- a/rma_account/models/rma_order_line.py
+++ b/rma_account/models/rma_order_line.py
@@ -360,3 +360,39 @@ class RmaOrderLine(models.Model):
# We get the cost from the original invoice line
price_unit = self.account_move_line_id.price_unit
return price_unit
+
+ def _refund_at_zero_cost(self):
+ make_refund = (
+ self.env["rma.refund"]
+ .with_context(
+ {
+ "customer": True,
+ "active_ids": self.ids,
+ "active_model": "rma.order.line",
+ }
+ )
+ .create({"description": "RMA Anglosaxon Regularisation"})
+ )
+ for item in make_refund.item_ids:
+ item.qty_to_refund = item.line_id.qty_received - item.line_id.qty_refunded
+ action_refund = make_refund.invoice_refund()
+ refund_id = action_refund.get("res_id", False)
+ if refund_id:
+ refund = self.env["account.move"].browse(refund_id)
+ refund._post()
+
+ def _check_refund_zero_cost(self):
+ """
+ In the scenario where a company uses anglo-saxon accounting, if you receive
+ products from a customer and don't expect to refund the customer but send a
+ replacement unit you still need to create a debit entry on the
+ Stock Interim (Delivered) account. In order to do this the best approach is
+ to create a customer refund from the RMA, but set as free of charge
+ (price unit = 0). The refund will be 0, but the Stock Interim (Delivered)
+ account will be posted anyways.
+ """
+ # For some reason api.depends on qty_received is not working. Using the
+ # _account_entry_move method in stock move as trigger then
+ for rec in self.filtered(lambda l: l.operation_id.automated_refund):
+ if rec.qty_received > rec.qty_refunded:
+ rec._refund_at_zero_cost()
diff --git a/rma_account/models/stock_move.py b/rma_account/models/stock_move.py
index 639468fb..18d8e29e 100644
--- a/rma_account/models/stock_move.py
+++ b/rma_account/models/stock_move.py
@@ -13,4 +13,5 @@ class StockMove(models.Model):
# Eventually reconcile together the invoice and valuation accounting
# entries on the stock interim accounts
self.rma_line_id._stock_account_anglo_saxon_reconcile_valuation()
+ self.rma_line_id._check_refund_zero_cost()
return res
diff --git a/rma_account/tests/test_rma_stock_account.py b/rma_account/tests/test_rma_stock_account.py
index 6b4d92f1..65b2f302 100644
--- a/rma_account/tests/test_rma_stock_account.py
+++ b/rma_account/tests/test_rma_stock_account.py
@@ -324,3 +324,26 @@ class TestRmaStockAccount(TestRma):
self.assertEqual(gdni_balance, 0.0)
# The GDNI entries should be now reconciled
self.assertEqual(all(gdni_amls.mapped("reconciled")), True)
+
+ def test_05_reconcile_grni_when_no_refund(self):
+ """
+ Test that receive and send a replacement order leaves GDNI reconciled
+ """
+ self.product_fifo_1.standard_price = 15
+ rma_line = Form(self.rma_line)
+ rma_line.partner_id = self.partner_id
+ rma_line.product_id = self.product_fifo_1
+ rma_line.operation_id.automated_refund = True
+ rma_line = rma_line.save()
+ rma_line.action_rma_to_approve()
+ # receiving should trigger the refund at zero cost
+ self._receive_rma(rma_line)
+ gdni_amls = self.env["account.move.line"].search(
+ [
+ ("rma_line_id", "in", rma_line.ids),
+ ("account_id", "=", self.account_gdni.id),
+ ]
+ ) + rma_line.refund_line_ids.filtered(
+ lambda l: l.account_id == self.account_gdni
+ )
+ self.assertEqual(all(gdni_amls.mapped("reconciled")), True)
diff --git a/rma_account/views/rma_operation_view.xml b/rma_account/views/rma_operation_view.xml
index 6d2cdbb0..922f52aa 100644
--- a/rma_account/views/rma_operation_view.xml
+++ b/rma_account/views/rma_operation_view.xml
@@ -21,6 +21,10 @@
+
+
+
+
diff --git a/rma_account/wizards/rma_refund.py b/rma_account/wizards/rma_refund.py
index b0b86d98..909a833f 100644
--- a/rma_account/wizards/rma_refund.py
+++ b/rma_account/wizards/rma_refund.py
@@ -92,10 +92,6 @@ class RmaRefund(models.TransientModel):
def invoice_refund(self):
rma_line_ids = self.env["rma.order.line"].browse(self.env.context["active_ids"])
for line in rma_line_ids:
- if line.refund_policy == "no":
- raise ValidationError(
- _("The operation is not refund for at least one line")
- )
if line.state != "approved":
raise ValidationError(_("RMA %s is not approved") % line.name)
new_invoice = self.compute_refund()
@@ -111,6 +107,8 @@ class RmaRefund(models.TransientModel):
return result
def _get_refund_price_unit(self, rma):
+ if rma.operation_id.refund_free_of_charge:
+ return 0.0
price_unit = rma.price_unit
# If this references a previous invoice/bill, use the same unit price
if rma.account_move_line_id:
diff --git a/rma_sale/wizards/rma_refund.py b/rma_sale/wizards/rma_refund.py
index 0f789ec7..cc8ea048 100644
--- a/rma_sale/wizards/rma_refund.py
+++ b/rma_sale/wizards/rma_refund.py
@@ -14,6 +14,8 @@ class RmaRefund(models.TransientModel):
def _get_refund_price_unit(self, rma):
price_unit = super(RmaRefund, self)._get_refund_price_unit(rma)
+ if rma.operation_id.refund_free_of_charge:
+ return price_unit
if rma.type == "customer":
if rma.account_move_line_id:
price_unit = rma.account_move_line_id.price_unit