summaryrefslogtreecommitdiff
path: root/addons/point_of_sale/models
diff options
context:
space:
mode:
authorRobin Heinz <rhe@odoo.com>2021-04-20 09:23:57 +0000
committerPierre Masereel <pim@odoo.com>2021-04-21 09:48:23 +0000
commit00863f11d072c6b87bbda2719129c4c78815a72d (patch)
tree9b1b9d941b4c039c3e02909c644498d3f1033c62 /addons/point_of_sale/models
parente47f7db5ead8719d76f5fe1afd451f0ce113864b (diff)
[FIX] pos_cash_rounding: fix when multiple payment method
When a pos user combines payment methods with and without rounding, we must be sure that the rounding is made by payment method and not only on the total amount of the order. As the total may change depending on the combination of payment method used, we had to adapt the methods that checks that an order is paid, and also propagate the new rounding made on the invoice. We also don't allow anymore a user to validate an order with a payment badly rounded. closes odoo/odoo#69544 Signed-off-by: pimodoo <pimodoo@users.noreply.github.com>
Diffstat (limited to 'addons/point_of_sale/models')
-rw-r--r--addons/point_of_sale/models/pos_order.py85
1 files changed, 78 insertions, 7 deletions
diff --git a/addons/point_of_sale/models/pos_order.py b/addons/point_of_sale/models/pos_order.py
index 79f5b3a6df6..775d3dc12b7 100644
--- a/addons/point_of_sale/models/pos_order.py
+++ b/addons/point_of_sale/models/pos_order.py
@@ -367,6 +367,70 @@ class PosOrder(models.Model):
currency = self.currency_id
return currency.round(amount) if currency else amount
+ def _create_invoice(self, move_vals):
+ self.ensure_one()
+ new_move = self.env['account.move'].sudo().with_company(self.company_id).with_context(default_move_type=move_vals['move_type']).create(move_vals)
+ message = _("This invoice has been created from the point of sale session: <a href=# data-oe-model=pos.order data-oe-id=%d>%s</a>") % (self.id, self.name)
+ new_move.message_post(body=message)
+ if self.config_id.cash_rounding:
+ rounding_applied = float_round(self.amount_paid - self.amount_total,
+ precision_rounding=new_move.currency_id.rounding)
+ rounding_line = new_move.line_ids.filtered(lambda line: line.is_rounding_line)
+ if rounding_applied:
+ if rounding_applied > 0.0:
+ account_id = new_move.invoice_cash_rounding_id.loss_account_id.id
+ else:
+ account_id = new_move.invoice_cash_rounding_id.profit_account_id.id
+ if rounding_line:
+ if rounding_line.debit > 0:
+ rounding_line_difference = rounding_line.debit + rounding_applied
+ else:
+ rounding_line_difference = -rounding_line.credit + rounding_applied
+ if rounding_line_difference:
+ rounding_line.with_context(check_move_validity=False).write({
+ 'debit': rounding_applied < 0.0 and -rounding_applied or 0.0,
+ 'credit': rounding_applied > 0.0 and rounding_applied or 0.0,
+ 'account_id': account_id,
+ 'price_unit': rounding_applied,
+ })
+ existing_terms_line = new_move.line_ids.filtered(
+ lambda line: line.account_id.user_type_id.type in ('receivable', 'payable'))
+ if existing_terms_line.debit > 0:
+ existing_terms_line_new_val = float_round(
+ existing_terms_line.debit + rounding_line_difference,
+ precision_rounding=new_move.currency_id.rounding)
+ else:
+ existing_terms_line_new_val = float_round(
+ -existing_terms_line.credit + rounding_line_difference,
+ precision_rounding=new_move.currency_id.rounding)
+ existing_terms_line.write({
+ 'debit': existing_terms_line_new_val > 0.0 and existing_terms_line_new_val or 0.0,
+ 'credit': existing_terms_line_new_val < 0.0 and -existing_terms_line_new_val or 0.0,
+ })
+
+ new_move._recompute_payment_terms_lines()
+
+ else:
+ self.env['account.move.line'].create({
+ 'debit': rounding_applied < 0.0 and -rounding_applied or 0.0,
+ 'credit': rounding_applied > 0.0 and rounding_applied or 0.0,
+ 'quantity': 1.0,
+ 'amount_currency': rounding_applied,
+ 'partner_id': new_move.partner_id.id,
+ 'move_id': new_move.id,
+ 'currency_id': new_move.currency_id if new_move.currency_id != new_move.company_id.currency_id else False,
+ 'company_id': new_move.company_id.id,
+ 'company_currency_id': new_move.company_id.currency_id.id,
+ 'is_rounding_line': True,
+ 'sequence': 9999,
+ 'name': new_move.invoice_cash_rounding_id.name,
+ 'account_id': account_id,
+ })
+ else:
+ if rounding_line:
+ rounding_line.unlink()
+ return new_move
+
def action_pos_order_paid(self):
self.ensure_one()
@@ -378,8 +442,20 @@ class PosOrder(models.Model):
else:
total = float_round(self.amount_total, precision_rounding=self.config_id.rounding_method.rounding, rounding_method=self.config_id.rounding_method.rounding_method)
- if not float_is_zero(total - self.amount_paid, precision_rounding=self.currency_id.rounding):
+ isPaid = float_is_zero(total - self.amount_paid, precision_rounding=self.currency_id.rounding)
+
+ if not isPaid and not self.config_id.cash_rounding:
raise UserError(_("Order %s is not fully paid.", self.name))
+ elif not isPaid and self.config_id.cash_rounding:
+ currency = self.currency_id
+ if self.config_id.rounding_method.rounding_method == "HALF-UP":
+ maxDiff = currency.round(self.config_id.rounding_method.rounding / 2)
+ else:
+ maxDiff = currency.round(self.config_id.rounding_method.rounding)
+
+ diff = currency.round(self.amount_total - self.amount_paid)
+ if not abs(diff) < maxDiff:
+ raise UserError(_("Order %s is not fully paid.", self.name))
self.write({'state': 'paid'})
@@ -421,12 +497,7 @@ class PosOrder(models.Model):
raise UserError(_('Please provide a partner for the sale.'))
move_vals = order._prepare_invoice_vals()
- new_move = moves.sudo()\
- .with_company(order.company_id)\
- .with_context(default_move_type=move_vals['move_type'])\
- .create(move_vals)
- message = _("This invoice has been created from the point of sale session: <a href=# data-oe-model=pos.order data-oe-id=%d>%s</a>") % (order.id, order.name)
- new_move.message_post(body=message)
+ new_move = order._create_invoice(move_vals)
order.write({'account_move': new_move.id, 'state': 'invoiced'})
new_move.sudo().with_company(order.company_id)._post()
moves += new_move