[IMP] point_of_sale: warning with cash payment methods
Currently, it is possible to assign the same "Cash" payment method to multiple PoS. At the moment, when creating a new PoS, Odoo tends to assign it by default. Although this is highly not recommended as it can only lead to incorrect cash control (two PoS devices rarely share the same till and therefore needs their own cash payment method). This commit makes sure payment methods of type Cash aren't set by default when creating new PoS. it also blocks the user from setting the same Cash payment method to multiple PoS configs. closes odoo/odoo#92664 Task-id: 2857417 Signed-off-by: Trinh Jacky (trj) <trj@odoo.com>
This commit is contained in:
@@ -142,7 +142,7 @@ class PosConfig(models.Model):
|
||||
help="This field depicts the maximum difference allowed between the ending balance and the theoretical cash when "
|
||||
"closing a session, for non-POS managers. If this maximum is reached, the user will have an error message at "
|
||||
"the closing of his session saying that he needs to contact his manager.")
|
||||
payment_method_ids = fields.Many2many('pos.payment.method', string='Payment Methods', default=lambda self: self._default_payment_methods())
|
||||
payment_method_ids = fields.Many2many('pos.payment.method', string='Payment Methods', default=lambda self: self._default_payment_methods(), copy=False)
|
||||
company_has_template = fields.Boolean(string="Company has chart of accounts", compute="_compute_company_has_template")
|
||||
current_user_id = fields.Many2one('res.users', string='Current Session Responsible', compute='_compute_current_session_user')
|
||||
other_devices = fields.Boolean(string="Other Devices", help="Connect devices to your PoS without an IoT Box.")
|
||||
@@ -352,6 +352,18 @@ class PosConfig(models.Model):
|
||||
raise ValidationError(_("No chart of account configured, go to the \"configuration / settings\" menu, and "
|
||||
"install one from the Invoicing tab."))
|
||||
|
||||
@api.constrains('payment_method_ids')
|
||||
def _check_payment_method_ids_journal(self):
|
||||
cash_journal = self.env['account.journal'].search(
|
||||
[('company_id', '=', self.env.company.id), ('type', '=', 'cash')])
|
||||
|
||||
for cash_method in self.payment_method_ids.filtered(lambda s: s.journal_id.id in cash_journal.ids):
|
||||
if self.env['pos.config'].search([('id', '!=', self.id), ('payment_method_ids', 'in', cash_method.ids)]):
|
||||
raise ValidationError(_("This cash payment method is already used in another Point of Sale.\n"
|
||||
"A new cash payment method should be created for this Point of Sale."))
|
||||
if len(cash_method.journal_id.pos_payment_method_ids) > 1:
|
||||
raise ValidationError(_("You cannot use the same journal on multiples cash payment methods."))
|
||||
|
||||
def name_get(self):
|
||||
result = []
|
||||
for config in self:
|
||||
@@ -586,7 +598,11 @@ class PosConfig(models.Model):
|
||||
if cash_journal:
|
||||
payment_methods |= payment_methods.create({
|
||||
'name': _('Cash'),
|
||||
'journal_id': cash_journal.id,
|
||||
'journal_id': self.env['account.journal'].create({
|
||||
'name': "Cash",
|
||||
'code': "CSH %s" % pos_config.id,
|
||||
'type': 'cash',
|
||||
}).id,
|
||||
'company_id': company.id,
|
||||
})
|
||||
if bank_journal:
|
||||
|
||||
@@ -25,7 +25,7 @@ class PosPaymentMethod(models.Model):
|
||||
is_cash_count = fields.Boolean(string='Cash', compute="_compute_is_cash_count", store=True)
|
||||
journal_id = fields.Many2one('account.journal',
|
||||
string='Journal',
|
||||
domain=[('type', 'in', ('cash', 'bank'))],
|
||||
domain=['|', '&', ('type', '=', 'cash'), ('pos_payment_method_ids', '=', False), ('type', '=', 'bank')],
|
||||
ondelete='restrict',
|
||||
help='Leave empty to use the receivable account of customer.\n'
|
||||
'Defines the journal where to book the accumulated payments (or individual payment if Identify Customer is true) after closing the session.\n'
|
||||
|
||||
@@ -263,6 +263,11 @@ class TestPoSCommon(ValuationReconciliationTestCommon):
|
||||
cls.cash_split_pm1 = cls.cash_pm1.copy(default={
|
||||
'name': 'Split (Cash) PM',
|
||||
'split_transactions': True,
|
||||
'journal_id': cls.env['account.journal'].create({
|
||||
'name': "Cash",
|
||||
'code': "CSH %s" % config.id,
|
||||
'type': 'cash',
|
||||
}).id
|
||||
})
|
||||
cls.bank_split_pm1 = cls.bank_pm1.copy(default={
|
||||
'name': 'Split (Bank) PM',
|
||||
|
||||
@@ -31,7 +31,13 @@ class TestAngloSaxonCommon(common.TransactionCase):
|
||||
self.category.property_stock_valuation_account_id = account_valuation
|
||||
self.category.property_stock_journal = self.env['account.journal'].create({'name': 'Stock journal', 'type': 'sale', 'code': 'STK00'})
|
||||
self.pos_config = self.env.ref('point_of_sale.pos_config_main')
|
||||
self.pos_config = self.pos_config.copy({'name': 'New POS config'})
|
||||
self.cash_journal = self.env['account.journal'].create(
|
||||
{'name': 'CASH journal', 'type': 'cash', 'code': 'CSH02'})
|
||||
self.cash_payment_method = self.env['pos.payment.method'].create({
|
||||
'name': 'Cash Test',
|
||||
'journal_id': self.cash_journal.id,
|
||||
})
|
||||
self.pos_config = self.pos_config.copy({'name': 'New POS config', 'payment_method_ids': self.cash_payment_method})
|
||||
self.product = self.env['product.product'].create({
|
||||
'name': 'New product',
|
||||
'standard_price': 100,
|
||||
|
||||
@@ -845,7 +845,17 @@ class TestPoSBasicConfig(TestPoSCommon):
|
||||
self.assertEqual(session.cash_register_balance_start, pos_data['amount_paid'])
|
||||
|
||||
pos01_config = self.config
|
||||
pos02_config = pos01_config.copy()
|
||||
self.cash_journal = self.env['account.journal'].create(
|
||||
{'name': 'CASH journal', 'type': 'cash', 'code': 'CSH00'})
|
||||
self.cash_payment_method = self.env['pos.payment.method'].create({
|
||||
'name': 'Cash Test',
|
||||
'journal_id': self.cash_journal.id,
|
||||
'receivable_account_id': pos01_config.payment_method_ids.filtered(lambda s: s.is_cash_count)[
|
||||
1].receivable_account_id.id
|
||||
})
|
||||
pos02_config = pos01_config.copy({
|
||||
'payment_method_ids': self.cash_payment_method
|
||||
})
|
||||
pos01_data = {'config': pos01_config, 'p_qty': 1, 'amount_paid': 0}
|
||||
pos02_data = {'config': pos02_config, 'p_qty': 3, 'amount_paid': 0}
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
<div class="oe_title">
|
||||
<label for="name"/>
|
||||
<h1><field name="name" placeholder="e.g. Cash" class="oe_inline"/></h1>
|
||||
<field name="image" class="oe_avatar" widget='image'/>
|
||||
</div>
|
||||
<group name="Payment methods">
|
||||
<field name="hide_use_payment_terminal" invisible="1"/>
|
||||
@@ -21,7 +22,6 @@
|
||||
<field name="outstanding_account_id" groups="account.group_account_readonly" attrs="{'invisible': [('type', '!=', 'bank')]}" placeholder="Leave empty to use the default account from the company setting" />
|
||||
<field name="receivable_account_id" groups="account.group_account_readonly" attrs="{'invisible': [('split_transactions', '=', True)]}" placeholder="Leave empty to use the default account from the company setting" />
|
||||
<field name="company_id" readonly="1" groups="base.group_multi_company" />
|
||||
<field name="image"/>
|
||||
</group>
|
||||
<group attrs="{'invisible': ['|', ('hide_use_payment_terminal', '=', False), ('type', 'in', ['cash', 'pay_later'])]}">
|
||||
<div colspan="2">
|
||||
@@ -54,6 +54,7 @@
|
||||
<field name="outstanding_account_id" groups="account.group_account_readonly" optional="hide" attrs="{'invisible': [('type', '!=', 'bank')]}" />
|
||||
<field name="receivable_account_id" groups="account.group_account_readonly" optional="hide" attrs="{'invisible': [('split_transactions', '=', True)]}" />
|
||||
<field name="company_id" groups="base.group_multi_company" />
|
||||
<field name="config_ids" widget="many2many_tags"/>
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
@@ -67,6 +68,9 @@
|
||||
<field name="receivable_account_id" groups="account.group_account_readonly" />
|
||||
<group expand="1" string="Group By">
|
||||
<filter name="group_by_receivable_account" string="Account" domain="[]" context="{'group_by':'receivable_account_id'}"/>
|
||||
<filter name="group_by_pos_config" string="Point of Sale" domain="[]" context="{'group_by':'config_ids'}"/>
|
||||
<filter name="group_by_method_name" string="Method Name" domain="[]" context="{'group_by':'name'}"/>
|
||||
<filter name="group_by_journal_id" string="Journal" domain="[]" context="{'group_by':'journal_id'}"/>
|
||||
</group>
|
||||
<filter string="Archived" name="active" domain="[('active', '=', False)]"/>
|
||||
</search>
|
||||
|
||||
@@ -629,7 +629,17 @@ class TestUi(TestPointOfSaleHttpCommon):
|
||||
]
|
||||
})
|
||||
|
||||
self.main_pos_config2 = self.main_pos_config.copy()
|
||||
self.cash_journal = self.env['account.journal'].create(
|
||||
{'name': 'CASH journal', 'type': 'cash', 'code': 'CSH00'})
|
||||
self.cash_payment_method = self.env['pos.payment.method'].create({
|
||||
'name': 'Cash Test',
|
||||
'journal_id': self.cash_journal.id,
|
||||
'receivable_account_id': self.main_pos_config.payment_method_ids.filtered(lambda s: s.is_cash_count).receivable_account_id.id
|
||||
})
|
||||
|
||||
self.main_pos_config2 = self.main_pos_config.copy({
|
||||
'payment_method_ids': self.cash_payment_method
|
||||
})
|
||||
|
||||
loyalty_program = self.env['loyalty.program'].create({
|
||||
'name': 'Coupon Program - Pricelist',
|
||||
@@ -699,7 +709,18 @@ class TestUi(TestPointOfSaleHttpCommon):
|
||||
}
|
||||
)
|
||||
|
||||
self.main_pos_config2 = self.main_pos_config.copy()
|
||||
self.cash_journal = self.env['account.journal'].create(
|
||||
{'name': 'CASH journal', 'type': 'cash', 'code': 'CSHDI'})
|
||||
self.cash_payment_method = self.env['pos.payment.method'].create({
|
||||
'name': 'Cash Test',
|
||||
'journal_id': self.cash_journal.id,
|
||||
'receivable_account_id': self.main_pos_config.payment_method_ids.filtered(
|
||||
lambda s: s.is_cash_count).receivable_account_id.id
|
||||
})
|
||||
|
||||
self.main_pos_config2 = self.main_pos_config.copy({
|
||||
'payment_method_ids': self.cash_payment_method
|
||||
})
|
||||
self.main_pos_config2.write({
|
||||
'module_pos_discount' : True,
|
||||
'discount_product_id': self.discount_product.id,
|
||||
|
||||
@@ -123,8 +123,8 @@ class TestFrontend(odoo.tests.HttpCase):
|
||||
'journal_id': test_sale_journal.id,
|
||||
'invoice_journal_id': test_sale_journal.id,
|
||||
'payment_method_ids': [(0, 0, {
|
||||
'name': 'Cash restaurant',
|
||||
'split_transactions': True,
|
||||
'name': 'Cash',
|
||||
'split_transactions': False,
|
||||
'receivable_account_id': account_receivable.id,
|
||||
'journal_id': cash_journal.id,
|
||||
})],
|
||||
|
||||
Reference in New Issue
Block a user