diff --git a/addons/account/models/account_bank_statement.py b/addons/account/models/account_bank_statement.py
index 25797b50edf..0028be54c81 100644
--- a/addons/account/models/account_bank_statement.py
+++ b/addons/account/models/account_bank_statement.py
@@ -20,13 +20,14 @@ class AccountCashboxLine(models.Model):
@api.depends('coin_value', 'number')
def _sub_total(self):
""" Calculates Sub total"""
- for line in self:
- line.subtotal = line.coin_value * line.number
+ for cashbox_line in self:
+ cashbox_line.subtotal = cashbox_line.coin_value * cashbox_line.number
coin_value = fields.Float(string='Coin/Bill Value', required=True, digits=0)
- number = fields.Integer(string='Number of Coins/Bills', help='Opening Unit Numbers')
+ number = fields.Integer(string='#Coins/Bills', help='Opening Unit Numbers')
subtotal = fields.Float(compute='_sub_total', string='Subtotal', digits=0, readonly=True)
cashbox_id = fields.Many2one('account.bank.statement.cashbox', string="Cashbox")
+ currency_id = fields.Many2one('res.currency', related='cashbox_id.currency_id')
class AccountBankStmtCashWizard(models.Model):
@@ -37,20 +38,59 @@ class AccountBankStmtCashWizard(models.Model):
_description = 'Bank Statement Cashbox'
cashbox_lines_ids = fields.One2many('account.cashbox.line', 'cashbox_id', string='Cashbox Lines')
+ start_bank_stmt_ids = fields.One2many('account.bank.statement', 'cashbox_start_id')
+ end_bank_stmt_ids = fields.One2many('account.bank.statement', 'cashbox_end_id')
+ total = fields.Float(compute='_compute_total')
+ currency_id = fields.Many2one('res.currency', compute='_compute_currency')
- def validate(self):
- bnk_stmt_id = self.env.context.get('bank_statement_id', False) or self.env.context.get('active_id', False)
- bnk_stmt = self.env['account.bank.statement'].browse(bnk_stmt_id)
- total = 0.0
- for lines in self.cashbox_lines_ids:
- total += lines.subtotal
- if self.env.context.get('balance', False) == 'start':
- #starting balance
- bnk_stmt.write({'balance_start': total, 'cashbox_start_id': self.id})
- else:
- #closing balance
- bnk_stmt.write({'balance_end_real': total, 'cashbox_end_id': self.id})
- return {'type': 'ir.actions.act_window_close'}
+ @api.depends('start_bank_stmt_ids', 'end_bank_stmt_ids')
+ def _compute_currency(self):
+ for cashbox in self:
+ if cashbox.end_bank_stmt_ids:
+ cashbox.currency_id = cashbox.end_bank_stmt_ids[0].currency_id
+ if cashbox.start_bank_stmt_ids:
+ cashbox.currency_id = cashbox.start_bank_stmt_ids[0].currency_id
+
+ @api.depends('cashbox_lines_ids', 'cashbox_lines_ids.coin_value', 'cashbox_lines_ids.number')
+ def _compute_total(self):
+ for cashbox in self:
+ cashbox.total = sum([line.subtotal for line in cashbox.cashbox_lines_ids])
+
+ @api.model
+ def default_get(self, fields):
+ vals = super(AccountBankStmtCashWizard, self).default_get(fields)
+ balance = self.env.context.get('balance')
+ statement_id = self.env.context.get('statement_id')
+ if 'start_bank_stmt_ids' in fields and not vals.get('start_bank_stmt_ids') and statement_id and balance == 'start':
+ vals['start_bank_stmt_ids'] = [(6, 0, [statement_id])]
+ if 'end_bank_stmt_ids' in fields and not vals.get('end_bank_stmt_ids') and statement_id and balance == 'close':
+ vals['end_bank_stmt_ids'] = [(6, 0, [statement_id])]
+
+ return vals
+
+ def name_get(self):
+ result = []
+ for cashbox in self:
+ result.append((cashbox.id, _("%s")%(cashbox.total)))
+ return result
+
+ @api.model_create_multi
+ def create(self, vals):
+ cashboxes = super(AccountBankStmtCashWizard, self).create(vals)
+ cashboxes._validate_cashbox()
+ return cashboxes
+
+ def write(self, vals):
+ res = super(AccountBankStmtCashWizard, self).write(vals)
+ self._validate_cashbox()
+ return res
+
+ def _validate_cashbox(self):
+ for cashbox in self:
+ if self.start_bank_stmt_ids:
+ self.start_bank_stmt_ids.write({'balance_start': self.total})
+ if self.end_bank_stmt_ids:
+ self.end_bank_stmt_ids.write({'balance_end_real': self.total})
class AccountBankStmtCloseCheck(models.TransientModel):
@@ -176,7 +216,7 @@ class AccountBankStatement(models.Model):
account = stmt.journal_id.profit_account_id
name = _('Profit')
if not account:
- raise UserError(_('There is no account defined on the journal %s for %s involved in a cash difference.') % (stmt.journal_id.name, name))
+ raise UserError(_('Please go on the %s journal and define a %s Account. This account will be used to record cash difference.') % (stmt.journal_id.name, name))
values = {
'statement_id': stmt.id,
@@ -201,20 +241,30 @@ class AccountBankStatement(models.Model):
return super(AccountBankStatement, self).unlink()
def open_cashbox_id(self):
+ self.ensure_one()
context = dict(self.env.context or {})
- if context.get('cashbox_id'):
- context['active_id'] = self.id
- return {
+ if context.get('balance'):
+ context['statement_id'] = self.id
+ if context['balance'] == 'start':
+ cashbox_id = self.cashbox_start_id.id
+ elif context['balance'] == 'close':
+ cashbox_id = self.cashbox_end_id.id
+ else:
+ cashbox_id = False
+
+ action = {
'name': _('Cash Control'),
'view_mode': 'form',
'res_model': 'account.bank.statement.cashbox',
- 'view_id': self.env.ref('account.view_account_bnk_stmt_cashbox').id,
+ 'view_id': self.env.ref('account.view_account_bnk_stmt_cashbox_footer').id,
'type': 'ir.actions.act_window',
- 'res_id': self.env.context.get('cashbox_id'),
+ 'res_id': cashbox_id,
'context': context,
'target': 'new'
}
+ return action
+
def check_confirm_bank(self):
if self.journal_type == 'cash' and not self.currency_id.is_zero(self.difference):
action_rec = self.env['ir.model.data'].xmlid_to_object('account.action_view_account_bnk_stmt_check')
@@ -270,7 +320,7 @@ class AccountBankStatement(models.Model):
st_number = SequenceObj.with_context(**context).next_by_code('account.bank.statement')
statement.name = st_number
statement.state = 'open'
-
+
def action_bank_reconcile_bank_statements(self):
self.ensure_one()
bank_stmt_lines = self.mapped('line_ids')
diff --git a/addons/account/views/account_view.xml b/addons/account/views/account_view.xml
index 68e28bc6ec7..77e10a8529f 100644
--- a/addons/account/views/account_view.xml
+++ b/addons/account/views/account_view.xml
@@ -417,29 +417,46 @@ action = model.setting_init_bank_account_action()
account.bank.statement.cashbox
-
- Cash Control
- account.bank.statement.cashbox
- tree,form
-
- new
+
@@ -543,18 +560,12 @@ action = model.setting_init_bank_account_action()
-
-
+
-
-
+
diff --git a/addons/point_of_sale/models/pos_config.py b/addons/point_of_sale/models/pos_config.py
index 319fec28ab8..5ba9cd31983 100644
--- a/addons/point_of_sale/models/pos_config.py
+++ b/addons/point_of_sale/models/pos_config.py
@@ -8,32 +8,66 @@ from odoo import api, fields, models, _
from odoo.exceptions import ValidationError
-class AccountCashboxLine(models.Model):
- _inherit = 'account.cashbox.line'
-
- default_pos_id = fields.Many2one('pos.config', string='This cashbox line is used by default when opening or closing a balance for this point of sale')
-
- def name_get(self):
- result = []
- for cashbox_line in self:
- result.append((cashbox_line.id, "%s * %s"%(cashbox_line.coin_value, cashbox_line.number)))
- return result
-
class AccountBankStmtCashWizard(models.Model):
_inherit = 'account.bank.statement.cashbox'
+ @api.depends('pos_config_ids')
+ def _compute_currency(self):
+ super(AccountBankStmtCashWizard, self)._compute_currency()
+ for cashbox in self:
+ if cashbox.pos_config_ids:
+ cashbox.currency_id = cashbox.pos_config_ids[0].currency_id.id
+
+ pos_config_ids = fields.One2many('pos.config', 'default_cashbox_id')
+ is_a_template = fields.Boolean(default=False)
+
@api.model
def default_get(self, fields):
vals = super(AccountBankStmtCashWizard, self).default_get(fields)
+ if "is_a_template" in fields and self.env.context.get('default_is_a_template'):
+ vals['is_a_template'] = True
config_id = self.env.context.get('default_pos_id')
if config_id:
- lines = self.env['account.cashbox.line'].search([('default_pos_id', '=', config_id)])
+ config = self.env['pos.config'].browse(config_id)
+ if config.last_session_closing_cashbox.cashbox_lines_ids:
+ lines = config.last_session_closing_cashbox.cashbox_lines_ids
+ else:
+ lines = config.default_cashbox_id.cashbox_lines_ids
if self.env.context.get('balance', False) == 'start':
vals['cashbox_lines_ids'] = [[0, 0, {'coin_value': line.coin_value, 'number': line.number, 'subtotal': line.subtotal}] for line in lines]
else:
vals['cashbox_lines_ids'] = [[0, 0, {'coin_value': line.coin_value, 'number': 0, 'subtotal': 0.0}] for line in lines]
return vals
+ def _validate_cashbox(self):
+ super(AccountBankStmtCashWizard, self)._validate_cashbox()
+ session_id = self.env.context.get('pos_session_id')
+ if session_id:
+ current_session = self.env['pos.session'].browse(session_id)
+ if current_session.state == 'new_session':
+ current_session.write({'state': 'opening_control'})
+
+ def set_default_cashbox(self):
+ self.ensure_one()
+ current_session = self.env['pos.session'].browse(self.env.context['pos_session_id'])
+ lines = current_session.config_id.default_cashbox_id.cashbox_lines_ids
+ context = dict(self._context)
+ self.cashbox_lines_ids.unlink()
+ self.cashbox_lines_ids = [[0, 0, {'coin_value': line.coin_value, 'number': line.number, 'subtotal': line.subtotal}] for line in lines]
+
+ return {
+ 'name': _('Cash Control'),
+ 'view_type': 'form',
+ 'view_mode': 'form',
+ 'res_model': 'account.bank.statement.cashbox',
+ 'view_id': self.env.ref('point_of_sale.view_account_bnk_stmt_cashbox_footer').id,
+ 'type': 'ir.actions.act_window',
+ 'context': context,
+ 'target': 'new',
+ 'res_id': self.id,
+ }
+
+
class PosConfig(models.Model):
_name = 'pos.config'
_description = 'Point of Sale Configuration'
@@ -128,6 +162,7 @@ class PosConfig(models.Model):
current_session_state = fields.Char(compute='_compute_current_session')
last_session_closing_cash = fields.Float(compute='_compute_last_session')
last_session_closing_date = fields.Date(compute='_compute_last_session')
+ last_session_closing_cashbox = fields.Many2one('account.bank.statement.cashbox', compute='_compute_last_session')
pos_session_username = fields.Char(compute='_compute_current_session_user')
pos_session_state = fields.Char(compute='_compute_current_session_user')
pos_session_duration = fields.Char(compute='_compute_current_session_user')
@@ -150,7 +185,7 @@ class PosConfig(models.Model):
help="This product is used as reference on customer receipts.")
fiscal_position_ids = fields.Many2many('account.fiscal.position', string='Fiscal Positions', help='This is useful for restaurants with onsite and take-away services that imply specific tax rates.')
default_fiscal_position_id = fields.Many2one('account.fiscal.position', string='Default Fiscal Position')
- default_cashbox_lines_ids = fields.One2many('account.cashbox.line', 'default_pos_id', string='Default Balance')
+ default_cashbox_id = fields.Many2one('account.bank.statement.cashbox', string='Default Balance')
customer_facing_display_html = fields.Html(string='Customer facing display content', translate=True, default=_compute_default_customer_html)
use_pricelist = fields.Boolean("Use a pricelist.")
tax_regime = fields.Boolean("Tax Regime")
@@ -194,11 +229,16 @@ class PosConfig(models.Model):
for pos_config in self:
session = PosSession.search_read(
[('config_id', '=', pos_config.id), ('state', '=', 'closed')],
- ['cash_register_balance_end_real', 'stop_at'],
+ ['cash_register_balance_end_real', 'stop_at', 'cash_register_id'],
order="stop_at desc", limit=1)
if session:
- pos_config.last_session_closing_cash = session[0]['cash_register_balance_end_real']
pos_config.last_session_closing_date = session[0]['stop_at'].date()
+ if session[0]['cash_register_id']:
+ pos_config.last_session_closing_cash = session[0]['cash_register_balance_end_real']
+ pos_config.last_session_closing_cashbox = self.env['account.bank.statement'].browse(session[0]['cash_register_id'][0]).cashbox_end_id
+ else:
+ pos_config.last_session_closing_cash = 0
+ pos_config.last_session_closing_cashbox = False
else:
pos_config.last_session_closing_cash = 0
pos_config.last_session_closing_date = False
@@ -218,6 +258,12 @@ class PosConfig(models.Model):
pos_config.pos_session_state = False
pos_config.pos_session_duration = 0
+ @api.constrains('cash_control')
+ def _check_session_state(self):
+ open_session = self.env['pos.session'].search([('config_id', '=', self.id), ('state', '!=', 'closed')])
+ if open_session:
+ raise ValidationError(_("You are not allowed to change the cash control status while a session is already opened."))
+
@api.constrains('company_id', 'journal_id')
def _check_company_journal(self):
if self.journal_id and self.journal_id.company_id.id != self.company_id.id:
diff --git a/addons/point_of_sale/models/pos_session.py b/addons/point_of_sale/models/pos_session.py
index a84e1023c10..f7fcf871125 100644
--- a/addons/point_of_sale/models/pos_session.py
+++ b/addons/point_of_sale/models/pos_session.py
@@ -315,32 +315,12 @@ class PosSession(models.Model):
'url': '/pos/web/',
}
- def open_cashbox(self):
+ def open_cashbox_pos(self):
self.ensure_one()
- context = dict(self._context)
- balance_type = context.get('balance') or 'start'
- context['bank_statement_id'] = self.cash_register_id.id
- context['balance'] = balance_type
- context['default_pos_id'] = self.config_id.id
-
- action = {
- 'name': _('Cash Control'),
- 'view_mode': 'form',
- 'res_model': 'account.bank.statement.cashbox',
- 'view_id': self.env.ref('account.view_account_bnk_stmt_cashbox').id,
- 'type': 'ir.actions.act_window',
- 'context': context,
- 'target': 'new'
- }
-
- cashbox_id = None
- if balance_type == 'start':
- cashbox_id = self.cash_register_id.cashbox_start_id.id
- else:
- cashbox_id = self.cash_register_id.cashbox_end_id.id
- if cashbox_id:
- action['res_id'] = cashbox_id
-
+ action = self.cash_register_id.open_cashbox_id()
+ action['view_id'] = self.env.ref('point_of_sale.view_account_bnk_stmt_cashbox_footer').id
+ action['context']['pos_session_id'] = self.id
+ action['context']['default_pos_id'] = self.config_id.id
return action
def action_view_order(self):
diff --git a/addons/point_of_sale/security/ir.model.access.csv b/addons/point_of_sale/security/ir.model.access.csv
index 02587cd9c99..f92da922f39 100644
--- a/addons/point_of_sale/security/ir.model.access.csv
+++ b/addons/point_of_sale/security/ir.model.access.csv
@@ -35,5 +35,5 @@ access_barcode_nomenclature_pos_manager,barcode.nomenclature.pos.manager,barcode
access_barcode_rule_pos_user,barcode.rule.pos.user,barcodes.model_barcode_rule,group_pos_user,1,0,0,0
access_barcode_rule_pos_manager,barcode.rule.pos.manager,barcodes.model_barcode_rule,group_pos_manager,1,1,1,1
access_bank_statement_cashbox_user,account.bank.statement.cashbox user,account.model_account_bank_statement_cashbox,group_pos_user,1,1,1,0
-access_account_cashbox_line_user,account.cashbox.line user,account.model_account_cashbox_line,group_pos_user,1,1,1,0
+access_account_cashbox_line_user,account.cashbox.line user,account.model_account_cashbox_line,group_pos_user,1,1,1,1
access_decimal_precision_user,decimal.precision,base.model_decimal_precision,group_pos_user,1,0,0,0
diff --git a/addons/point_of_sale/tests/test_anglo_saxon.py b/addons/point_of_sale/tests/test_anglo_saxon.py
index c4b37211008..2020121cc45 100644
--- a/addons/point_of_sale/tests/test_anglo_saxon.py
+++ b/addons/point_of_sale/tests/test_anglo_saxon.py
@@ -101,7 +101,10 @@ class TestAngloSaxonFlow(TestAngloSaxonCommon):
self.assertEqual(self.pos_order_pos0.amount_paid, 450, 'Amount paid for the order should be updated.')
# I close the current session to generate the journal entries
- self.pos_config.current_session_id.action_pos_session_close()
+ current_session_id = self.pos_config.current_session_id
+ current_session_id._check_pos_session_balance()
+ current_session_id.action_pos_session_close()
+ self.assertEqual(current_session_id.state, 'closed', 'Check that session is closed')
# I test that the generated journal entries are correct.
account_output = self.category.property_stock_account_output_categ_id
diff --git a/addons/point_of_sale/views/account_statement_view.xml b/addons/point_of_sale/views/account_statement_view.xml
index 4efaf7bde0d..f6975b0cc64 100644
--- a/addons/point_of_sale/views/account_statement_view.xml
+++ b/addons/point_of_sale/views/account_statement_view.xml
@@ -1,33 +1,51 @@
-
- account.journal.pos.user.form.inherit
- account.journal
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+ view.bank.statement.pos.session
+ account.bank.statement
+ primary
+ 1000
+
+
+
+
+
-
- view.bank.statement.pos.session
- account.bank.statement
- primary
- 1000
-
-
-
-
-
+
+ account.bnk_stmt_cashbox.form
+ account.bank.statement.cashbox
+
+
+
+
+
+
+
+
+
+
+
+ account.journal.pos.user.form.inherit
+ account.journal
+
+
+
+
+
+
+
+
+
+
diff --git a/addons/point_of_sale/views/pos_config_view.xml b/addons/point_of_sale/views/pos_config_view.xml
index 3e3fda97db1..fcfdb6ef42b 100644
--- a/addons/point_of_sale/views/pos_config_view.xml
+++ b/addons/point_of_sale/views/pos_config_view.xml
@@ -342,10 +342,7 @@
diff --git a/addons/point_of_sale/views/pos_session_view.xml b/addons/point_of_sale/views/pos_session_view.xml
index 38a98259ca3..ca158b0b4a5 100644
--- a/addons/point_of_sale/views/pos_session_view.xml
+++ b/addons/point_of_sale/views/pos_session_view.xml
@@ -52,7 +52,7 @@
class="oe_stat_button"
attrs="{'invisible':['|', '|', ('cash_control', '=', False), ('state', '=', 'opening_control'), ('state', '=', 'closed')]}"
icon="fa-money"
- type="object" context="{'balance': 'end'}">
+ type="object" context="{'balance': 'close'}">
Set Closing Balance