diff --git a/addons/account/models/account_journal.py b/addons/account/models/account_journal.py
index e61666d08c0..213e4726381 100644
--- a/addons/account/models/account_journal.py
+++ b/addons/account/models/account_journal.py
@@ -629,9 +629,9 @@ class AccountJournal(models.Model):
default_account_code = self.env['account.account']._search_new_account_code(company, digits, liquidity_account_prefix)
default_account_vals = self._prepare_liquidity_account_vals(company, default_account_code, vals)
vals['default_account_id'] = self.env['account.account'].create(default_account_vals).id
- if journal_type == 'cash' and not has_profit_account:
+ if journal_type in ('cash', 'bank') and not has_profit_account:
vals['profit_account_id'] = company.default_cash_difference_income_account_id.id
- if journal_type == 'cash' and not has_loss_account:
+ if journal_type in ('cash', 'bank') and not has_loss_account:
vals['loss_account_id'] = company.default_cash_difference_expense_account_id.id
# === Fill missing refund_sequence ===
diff --git a/addons/account/views/account_journal_views.xml b/addons/account/views/account_journal_views.xml
index 553dfd11753..4925f0a2bae 100644
--- a/addons/account/views/account_journal_views.xml
+++ b/addons/account/views/account_journal_views.xml
@@ -65,8 +65,8 @@
-
-
+
+
we redirect the user
@@ -443,16 +453,72 @@ class PosSession(models.Model):
return {'successful': True}
- def _cannot_close_session(self):
+ def _create_diff_account_move_for_split_payment_method(self, payment_method, diff_amount):
+ self.ensure_one()
+
+ get_diff_vals_result = self._get_diff_vals(payment_method.id, diff_amount)
+ if not get_diff_vals_result:
+ return
+
+ source_vals, dest_vals = get_diff_vals_result
+ diff_move = self.env['account.move'].create({
+ 'journal_id': payment_method.journal_id.id,
+ 'date': fields.Date.context_today(self),
+ 'ref': self._get_diff_account_move_ref(payment_method),
+ 'line_ids': [Command.create(source_vals), Command.create(dest_vals)]
+ })
+ diff_move._post()
+
+ def _get_diff_account_move_ref(self, payment_method):
+ return _('Closing difference in %s (%s)', payment_method.name, self.name)
+
+ def _get_diff_vals(self, payment_method_id, diff_amount):
+ payment_method = self.env['pos.payment.method'].browse(payment_method_id)
+ diff_compare_to_zero = self.currency_id.compare_amounts(diff_amount, 0)
+ source_account = payment_method.outstanding_account_id or self.company_id.account_journal_payment_debit_account_id
+ destination_account = self.env['account.account']
+
+ if (diff_compare_to_zero > 0):
+ destination_account = payment_method.journal_id.profit_account_id
+ elif (diff_compare_to_zero < 0):
+ destination_account = payment_method.journal_id.loss_account_id
+
+ if (diff_compare_to_zero == 0 or not source_account):
+ return False
+
+ amounts = self._update_amounts({'amount': 0, 'amount_converted': 0}, {'amount': diff_amount}, self.stop_at)
+ source_vals = self._debit_amounts({'account_id': source_account.id}, amounts['amount'], amounts['amount_converted'])
+ dest_vals = self._credit_amounts({'account_id': destination_account.id}, amounts['amount'], amounts['amount_converted'])
+ return [source_vals, dest_vals]
+
+ def _cannot_close_session(self, bank_payment_method_diffs=None):
"""
Add check in this method if you want to return or raise an error when trying to either post cash details
or close the session. Raising an error will always redirect the user to the back end.
It should return {'successful': False, 'message': str, 'redirect': bool} if we can't close the session
"""
+ bank_payment_method_diffs = bank_payment_method_diffs or {}
if any(order.state == 'draft' for order in self.order_ids):
return {'successful': False, 'message': _("You cannot close the POS when orders are still in draft"), 'redirect': False}
if self.state == 'closed':
return {'successful': False, 'message': _("This session is already closed."), 'redirect': True}
+ if bank_payment_method_diffs:
+ no_loss_account = self.env['account.journal']
+ no_profit_account = self.env['account.journal']
+ for payment_method in self.env['pos.payment.method'].browse(bank_payment_method_diffs.keys()):
+ journal = payment_method.journal_id
+ compare_to_zero = self.currency_id.compare_amounts(bank_payment_method_diffs.get(payment_method.id), 0)
+ if compare_to_zero == -1 and not journal.loss_account_id:
+ no_loss_account |= journal
+ elif compare_to_zero == 1 and not journal.profit_account_id:
+ no_profit_account |= journal
+ message = ''
+ if no_loss_account:
+ message += _("Need loss account for the following journals to post the lost amount: %s\n", ', '.join(no_loss_account.mapped('name')))
+ if no_profit_account:
+ message += _("Need profit account for the following journals to post the gained amount: %s", ', '.join(no_profit_account.mapped('name')))
+ if message:
+ return {'successful': False, 'message': message, 'redirect': False}
def get_closing_control_data(self):
self.ensure_one()
@@ -498,6 +564,7 @@ class PosSession(models.Model):
'other_payment_methods': [{
'name': pm.name,
'amount': sum(orders.payment_ids.filtered(lambda p: p.payment_method_id == pm).mapped('amount')),
+ 'number': len(orders.payment_ids.filtered(lambda p: p.payment_method_id == pm)),
'id': pm.id,
'type': pm.type,
} for pm in other_payment_method_ids],
@@ -554,7 +621,7 @@ class PosSession(models.Model):
propoerty_account = self.env['ir.property']._get('property_account_receivable_id', 'res.partner')
return self.company_id.account_default_pos_receivable_account_id or propoerty_account or self.env['account.account']
- def _create_account_move(self, balancing_account=False, amount_to_balance=0):
+ def _create_account_move(self, balancing_account=False, amount_to_balance=0, bank_payment_method_diffs=None):
""" Create account.move and account.move.line records for this session.
Side-effects include:
@@ -572,7 +639,7 @@ class PosSession(models.Model):
})
self.write({'move_id': account_move.id})
- data = {}
+ data = {'bank_payment_method_diffs': bank_payment_method_diffs or {}}
data = self._accumulate_amounts(data)
data = self._create_non_reconciliable_move_lines(data)
data = self._create_bank_payment_moves(data)
@@ -792,12 +859,13 @@ class PosSession(models.Model):
def _create_bank_payment_moves(self, data):
combine_receivables_bank = data.get('combine_receivables_bank')
split_receivables_bank = data.get('split_receivables_bank')
+ bank_payment_method_diffs = data.get('bank_payment_method_diffs')
MoveLine = data.get('MoveLine')
payment_method_to_receivable_lines = {}
payment_to_receivable_lines = {}
for payment_method, amounts in combine_receivables_bank.items():
combine_receivable_line = MoveLine.create(self._get_combine_receivable_vals(payment_method, amounts['amount'], amounts['amount_converted']))
- payment_receivable_line = self._create_combine_account_payment(payment_method, amounts)
+ payment_receivable_line = self._create_combine_account_payment(payment_method, amounts, diff_amount=bank_payment_method_diffs.get(payment_method.id) or 0)
payment_method_to_receivable_lines[payment_method] = combine_receivable_line | payment_receivable_line
for payment, amounts in split_receivables_bank.items():
@@ -805,6 +873,9 @@ class PosSession(models.Model):
payment_receivable_line = self._create_split_account_payment(payment, amounts)
payment_to_receivable_lines[payment] = split_receivable_line | payment_receivable_line
+ for bank_payment_method in self.payment_method_ids.filtered(lambda pm: pm.type == 'bank' and pm.split_transactions):
+ self._create_diff_account_move_for_split_payment_method(bank_payment_method, bank_payment_method_diffs.get(bank_payment_method.id) or 0)
+
data['payment_method_to_receivable_lines'] = payment_method_to_receivable_lines
data['payment_to_receivable_lines'] = payment_to_receivable_lines
return data
@@ -821,7 +892,7 @@ class PosSession(models.Model):
MoveLine.create(vals)
return data
- def _create_combine_account_payment(self, payment_method, amounts):
+ def _create_combine_account_payment(self, payment_method, amounts, diff_amount):
outstanding_account = payment_method.outstanding_account_id or self.company_id.account_journal_payment_debit_account_id
destination_account = self._get_receivable_account(payment_method)
@@ -838,9 +909,29 @@ class PosSession(models.Model):
'pos_payment_method_id': payment_method.id,
'pos_session_id': self.id,
})
+
+ diff_amount_compare_to_zero = self.currency_id.compare_amounts(diff_amount, 0)
+ if diff_amount_compare_to_zero != 0:
+ self._apply_diff_on_account_payment_move(account_payment, payment_method, diff_amount)
+
account_payment.action_post()
return account_payment.move_id.line_ids.filtered(lambda line: line.account_id == account_payment.destination_account_id)
+ def _apply_diff_on_account_payment_move(self, account_payment, payment_method, diff_amount):
+ source_vals, dest_vals = self._get_diff_vals(payment_method.id, diff_amount)
+ outstanding_line = account_payment.move_id.line_ids.filtered(lambda line: line.account_id.id == source_vals['account_id'])
+ new_balance = outstanding_line.balance + diff_amount
+ new_balance_compare_to_zero = self.currency_id.compare_amounts(new_balance, 0)
+ account_payment.move_id.write({
+ 'line_ids': [
+ Command.create(dest_vals),
+ Command.update(outstanding_line.id, {
+ 'debit': new_balance_compare_to_zero > 0 and new_balance or 0.0,
+ 'credit': new_balance_compare_to_zero < 0 and -new_balance or 0.0
+ })
+ ]
+ })
+
def _create_split_account_payment(self, payment, amounts):
payment_method = payment.payment_method_id
if not payment_method.journal_id:
@@ -1318,6 +1409,17 @@ class PosSession(models.Model):
},
}
+ def _get_other_related_moves(self):
+ # TODO This is not an ideal way to get the diff account.move's for
+ # the session. It would be better if there is a relation field where
+ # these moves are saved.
+
+ # Unfortunately, the 'ref' of account.move is not indexed, so
+ # we are querying over the account.move.line because its 'ref' is indexed.
+ # And yes, we are only concern for split bank payment methods.
+ diff_lines_ref = [self._get_diff_account_move_ref(pm) for pm in self.payment_method_ids if pm.type == 'bank' and pm.split_transactions]
+ return self.env['account.move.line'].search([('ref', 'in', diff_lines_ref)]).mapped('move_id')
+
def _get_related_account_moves(self):
pickings = self.picking_ids | self.order_ids.mapped('picking_ids')
invoices = self.mapped('order_ids.account_move')
@@ -1325,7 +1427,8 @@ class PosSession(models.Model):
stock_account_moves = pickings.mapped('move_lines.account_move_ids')
cash_moves = self.cash_register_id.line_ids.mapped('move_id')
bank_payment_moves = self.bank_payment_ids.mapped('move_id')
- return invoices | invoice_payments | self.move_id | stock_account_moves | cash_moves | bank_payment_moves
+ other_related_moves = self._get_other_related_moves()
+ return invoices | invoice_payments | self.move_id | stock_account_moves | cash_moves | bank_payment_moves | other_related_moves
def _get_receivable_account(self, payment_method):
"""Returns the default pos receivable account if no receivable_account_id is set on the payment method."""
diff --git a/addons/point_of_sale/static/src/js/Popups/ClosePosPopup.js b/addons/point_of_sale/static/src/js/Popups/ClosePosPopup.js
index e17e8406bb8..fa005a0ef16 100644
--- a/addons/point_of_sale/static/src/js/Popups/ClosePosPopup.js
+++ b/addons/point_of_sale/static/src/js/Popups/ClosePosPopup.js
@@ -39,12 +39,12 @@ odoo.define('point_of_sale.ClosePosPopup', function(require) {
// component state and refs definition
const state = {notes: '', acceptClosing: false, payments: {}};
if (this.cashControl) {
- state.payments[this.defaultCashDetails.id] = {counted: 0, difference: -this.defaultCashDetails.amount};
+ state.payments[this.defaultCashDetails.id] = {counted: 0, difference: -this.defaultCashDetails.amount, number: 0};
}
if (this.otherPaymentMethods.length > 0) {
this.otherPaymentMethods.forEach(pm => {
if (pm.type === 'bank') {
- state.payments[pm.id] = {counted: this.env.pos.round_decimals_currency(pm.amount), difference: 0}
+ state.payments[pm.id] = {counted: this.env.pos.round_decimals_currency(pm.amount), difference: 0, number: pm.number}
}
})
}
@@ -141,10 +141,13 @@ odoo.define('point_of_sale.ClosePosPopup', function(require) {
args: [this.env.pos.pos_session.id, this.state.notes]
})
try {
+ const bankPaymentMethodDiffPairs = this.otherPaymentMethods
+ .filter((pm) => pm.type == 'bank')
+ .map((pm) => [pm.id, this.state.payments[pm.id].difference]);
response = await this.rpc({
model: 'pos.session',
method: 'close_session_from_ui',
- args: [this.env.pos.pos_session.id],
+ args: [this.env.pos.pos_session.id, bankPaymentMethodDiffPairs],
});
if (!response.successful) {
return this.handleClosingError(response);
@@ -176,6 +179,9 @@ odoo.define('point_of_sale.ClosePosPopup', function(require) {
window.location = '/web#action=point_of_sale.action_client_pos_menu';
}
}
+ _getShowDiff(pm) {
+ return pm.type == 'bank' && pm.number !== 0;
+ }
}
ClosePosPopup.template = 'ClosePosPopup';
diff --git a/addons/point_of_sale/static/src/xml/Popups/ClosePosPopup.xml b/addons/point_of_sale/static/src/xml/Popups/ClosePosPopup.xml
index ee4b934e9fd..04f215cebed 100644
--- a/addons/point_of_sale/static/src/xml/Popups/ClosePosPopup.xml
+++ b/addons/point_of_sale/static/src/xml/Popups/ClosePosPopup.xml
@@ -78,8 +78,9 @@
|
|
- |
- |
+
+ |
+ |