diff options
| -rw-r--r-- | addons/point_of_sale/__manifest__.py | 1 | ||||
| -rw-r--r-- | addons/point_of_sale/models/pos_order.py | 56 | ||||
| -rw-r--r-- | addons/point_of_sale/static/src/js/models.js | 4 | ||||
| -rw-r--r-- | addons/point_of_sale/tests/test_anglo_saxon.py | 11 | ||||
| -rw-r--r-- | addons/point_of_sale/tests/test_point_of_sale_flow.py | 247 | ||||
| -rw-r--r-- | addons/point_of_sale/views/pos_order_view.xml | 18 | ||||
| -rw-r--r-- | addons/point_of_sale/wizard/__init__.py | 1 | ||||
| -rw-r--r-- | addons/point_of_sale/wizard/pos_discount.py | 17 | ||||
| -rw-r--r-- | addons/point_of_sale/wizard/pos_discount.xml | 27 |
9 files changed, 158 insertions, 224 deletions
diff --git a/addons/point_of_sale/__manifest__.py b/addons/point_of_sale/__manifest__.py index bdc5f4983ec..1cb4f10517e 100644 --- a/addons/point_of_sale/__manifest__.py +++ b/addons/point_of_sale/__manifest__.py @@ -16,7 +16,6 @@ 'data/digest_data.xml', 'wizard/pos_box.xml', 'wizard/pos_details.xml', - 'wizard/pos_discount.xml', 'wizard/pos_open_statement.xml', 'wizard/pos_payment.xml', 'views/pos_templates.xml', diff --git a/addons/point_of_sale/models/pos_order.py b/addons/point_of_sale/models/pos_order.py index 547fd76565e..4fa895bd939 100644 --- a/addons/point_of_sale/models/pos_order.py +++ b/addons/point_of_sale/models/pos_order.py @@ -43,6 +43,10 @@ class PosOrder(models.Model): 'date_order': ui_order['creation_date'], 'fiscal_position_id': ui_order['fiscal_position_id'], 'pricelist_id': ui_order['pricelist_id'], + 'amount_paid': ui_order['amount_paid'], + 'amount_total': ui_order['amount_total'], + 'amount_tax': ui_order['amount_tax'], + 'amount_return': ui_order['amount_return'], } def _payment_fields(self, ui_paymentline): @@ -463,10 +467,11 @@ class PosOrder(models.Model): default=lambda self: self.env.uid, states={'done': [('readonly', True)], 'invoiced': [('readonly', True)]}, ) - amount_tax = fields.Float(compute='_compute_amount_all', string='Taxes', digits=0) - amount_total = fields.Float(compute='_compute_amount_all', string='Total', digits=0) - amount_paid = fields.Float(compute='_compute_amount_all', string='Paid', states={'draft': [('readonly', False)]}, readonly=True, digits=0) - amount_return = fields.Float(compute='_compute_amount_all', string='Returned', digits=0) + amount_tax = fields.Float(string='Taxes', digits=0, readonly=True, required=True) + amount_total = fields.Float(string='Total', digits=0, readonly=True, required=True) + amount_paid = fields.Float(string='Paid', states={'draft': [('readonly', False)]}, + readonly=True, digits=0, required=True) + amount_return = fields.Float(string='Returned', digits=0, required=True, readonly=True) lines = fields.One2many('pos.order.line', 'order_id', string='Order Lines', states={'draft': [('readonly', False)]}, readonly=True, copy=True) statement_ids = fields.One2many('account.bank.statement.line', 'pos_statement_id', string='Payments', states={'draft': [('readonly', False)]}, readonly=True) pricelist_id = fields.Many2one('product.pricelist', string='Pricelist', required=True, states={ @@ -505,10 +510,9 @@ class PosOrder(models.Model): states={'draft': [('readonly', False)]}, ) - @api.depends('statement_ids', 'lines.price_subtotal_incl', 'lines.discount') - def _compute_amount_all(self): + @api.onchange('statement_ids', 'lines', 'lines') + def _onchange_amount_all(self): for order in self: - order.amount_paid = order.amount_return = order.amount_tax = 0.0 currency = order.pricelist_id.currency_id order.amount_paid = sum(payment.amount for payment in order.statement_ids) order.amount_return = sum(payment.amount < 0 and payment.amount or 0 for payment in order.statement_ids) @@ -861,10 +865,12 @@ class PosOrder(models.Model): def add_payment(self, data): """Create a new payment for the order""" + self.ensure_one() args = self._prepare_bank_statement_line_payment_values(data) context = dict(self.env.context) context.pop('pos_session_id', False) self.env['account.bank.statement.line'].with_context(context).create(args) + self.amount_paid = sum(payment.amount for payment in self.statement_ids) return args.get('statement_id', False) @api.multi @@ -882,6 +888,9 @@ class PosOrder(models.Model): 'date_order': fields.Datetime.now(), 'pos_reference': order.pos_reference, 'lines': False, + 'amount_tax': -order.amount_tax, + 'amount_total': -order.amount_total, + 'amount_paid': 0, }) for line in order.lines: clone_line = line.copy({ @@ -889,6 +898,8 @@ class PosOrder(models.Model): 'name': line.name + _(' REFUND'), 'order_id': clone.id, 'qty': -line.qty, + 'price_subtotal': -line.price_subtotal, + 'price_subtotal_incl': -line.price_subtotal_incl, }) PosOrder += clone @@ -931,8 +942,10 @@ class PosOrderLine(models.Model): product_id = fields.Many2one('product.product', string='Product', domain=[('sale_ok', '=', True)], required=True, change_default=True) price_unit = fields.Float(string='Unit Price', digits=0) qty = fields.Float('Quantity', digits=dp.get_precision('Product Unit of Measure'), default=1) - price_subtotal = fields.Float(compute='_compute_amount_line_all', digits=0, string='Subtotal w/o Tax') - price_subtotal_incl = fields.Float(compute='_compute_amount_line_all', digits=0, string='Subtotal') + price_subtotal = fields.Float(string='Subtotal w/o Tax', digits=0, + readonly=True, required=True) + price_subtotal_incl = fields.Float(string='Subtotal', digits=0, + readonly=True, required=True) discount = fields.Float(string='Discount (%)', digits=0, default=0.0) order_id = fields.Many2one('pos.order', string='Order Ref', ondelete='cascade') create_date = fields.Datetime(string='Creation Date', readonly=True) @@ -965,17 +978,22 @@ class PosOrderLine(models.Model): values['name'] = self.env['ir.sequence'].next_by_code('pos.order.line') return super(PosOrderLine, self).create(values) - @api.depends('price_unit', 'tax_ids', 'qty', 'discount', 'product_id') - def _compute_amount_line_all(self): + @api.onchange('price_unit', 'tax_ids', 'qty', 'discount', 'product_id') + def _onchange_amount_line_all(self): for line in self: - fpos = line.order_id.fiscal_position_id - tax_ids_after_fiscal_position = fpos.map_tax(line.tax_ids, line.product_id, line.order_id.partner_id) if fpos else line.tax_ids - price = line.price_unit * (1 - (line.discount or 0.0) / 100.0) - taxes = tax_ids_after_fiscal_position.compute_all(price, line.order_id.pricelist_id.currency_id, line.qty, product=line.product_id, partner=line.order_id.partner_id) - line.update({ - 'price_subtotal_incl': taxes['total_included'], - 'price_subtotal': taxes['total_excluded'], - }) + res = line._compute_amount_line_all() + line.update(res) + + def _compute_amount_line_all(self): + self.ensure_one() + fpos = self.order_id.fiscal_position_id + tax_ids_after_fiscal_position = fpos.map_tax(self.tax_ids, self.product_id, self.order_id.partner_id) if fpos else self.tax_ids + price = self.price_unit * (1 - (self.discount or 0.0) / 100.0) + taxes = tax_ids_after_fiscal_position.compute_all(price, self.order_id.pricelist_id.currency_id, self.qty, product=self.product_id, partner=self.order_id.partner_id) + return { + 'price_subtotal_incl': taxes['total_included'], + 'price_subtotal': taxes['total_excluded'], + } @api.onchange('product_id') def _onchange_product_id(self): diff --git a/addons/point_of_sale/static/src/js/models.js b/addons/point_of_sale/static/src/js/models.js index 91e234dafc5..b4a1e0ff6ae 100644 --- a/addons/point_of_sale/static/src/js/models.js +++ b/addons/point_of_sale/static/src/js/models.js @@ -1530,6 +1530,8 @@ exports.Orderline = Backbone.Model.extend({ return { qty: this.get_quantity(), price_unit: this.get_unit_price(), + price_subtotal: this.get_price_without_tax(), + price_subtotal_incl: this.get_price_with_tax(), discount: this.get_discount(), product_id: this.get_product().id, tax_ids: [[6, false, _.map(this.get_applicable_taxes(), function(tax){ return tax.id; })]], @@ -2049,7 +2051,7 @@ exports.Order = Backbone.Model.extend({ }, this)); return { name: this.get_name(), - amount_paid: this.get_total_paid(), + amount_paid: this.get_total_paid() - this.get_change(), amount_total: this.get_total_with_tax(), amount_tax: this.get_total_tax(), amount_return: this.get_change(), diff --git a/addons/point_of_sale/tests/test_anglo_saxon.py b/addons/point_of_sale/tests/test_anglo_saxon.py index b6d27af9505..7fae0de8b83 100644 --- a/addons/point_of_sale/tests/test_anglo_saxon.py +++ b/addons/point_of_sale/tests/test_anglo_saxon.py @@ -70,8 +70,14 @@ class TestAngloSaxonFlow(TestAngloSaxonCommon): 'product_id': self.product.id, 'price_unit': 450, 'discount': 0.0, - 'qty': 1.0 - })] + 'qty': 1.0, + 'price_subtotal': 450, + 'price_subtotal_incl': 450, + })], + 'amount_total': 450, + 'amount_tax': 0, + 'amount_paid': 0, + 'amount_return': 0, }) # I make a payment to fully pay the order @@ -87,6 +93,7 @@ class TestAngloSaxonFlow(TestAngloSaxonCommon): # I check that the order is marked as paid self.assertEqual(self.pos_order_pos0.state, 'paid', 'Order should be in paid state.') + 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() diff --git a/addons/point_of_sale/tests/test_point_of_sale_flow.py b/addons/point_of_sale/tests/test_point_of_sale_flow.py index 94db310f3e6..4f982486bf0 100644 --- a/addons/point_of_sale/tests/test_point_of_sale_flow.py +++ b/addons/point_of_sale/tests/test_point_of_sale_flow.py @@ -17,104 +17,6 @@ class TestPointOfSaleFlow(TestPointOfSaleCommon): # open all statements/cash registers self.env['pos.open.statement'].create({}).open_statement() - def test_order_to_payment(self): - """ - In order to test the Point of Sale in module, I will do a full flow from the sale to the payment and invoicing. - I will use two products, one with price including a 10% tax, the other one with 5% tax excluded from the price. - """ - # I click on create a new session button - self.pos_config.open_session_cb() - - # I create a PoS order with 2 units of PCSC234 at 450 EUR (Tax Incl) - # and 3 units of PCSC349 at 300 EUR. (Tax Excl) - self.pos_order_pos0 = self.PosOrder.create({ - 'company_id': self.company_id, - 'pricelist_id': self.partner1.property_product_pricelist.id, - 'partner_id': self.partner1.id, - 'lines': [(0, 0, { - 'name': "OL/0001", - 'product_id': self.product3.id, - 'price_unit': 450, - 'discount': 0.0, - 'qty': 2.0, - 'tax_ids': [(6, 0, self.product3.taxes_id.ids)], - }), (0, 0, { - 'name': "OL/0002", - 'product_id': self.product4.id, - 'price_unit': 300, - 'discount': 0.0, - 'qty': 3.0, - 'tax_ids': [(6, 0, self.product4.taxes_id.ids)], - })] - }) - - # I check that the total of the order is equal to 450*2 + 300*3*1.05 - # and the tax of the order is equal to 900 -(450 * 2 / 1.1) + - # 300*0.05*3 - self.assertLess( - abs(self.pos_order_pos0.amount_total - (450 * 2 + 300 * 3 * 1.05)), - 0.01, 'The order has a wrong amount, tax included.') - - self.assertLess( - abs(self.pos_order_pos0.amount_tax - (900 - (450 * 2 / 1.1) + 300 * 0.05 * 3)), - 0.01, 'The order has a wrong tax amount.') - - # I want to add a global discount of 5 percent using the wizard - - self.pos_discount_0 = self.env['pos.discount'].create({'discount': 5.0}) - - context = {"active_model": "pos.order", "active_ids": [self.pos_order_pos0.id], "active_id": self.pos_order_pos0.id} - - # I click the apply button to set the discount on all lines - self.pos_discount_0.with_context(context).apply_discount() - - # I check that the total of the order is now equal to (450*2 + - # 300*3*1.05)*0.95 - self.assertLess( - abs(self.pos_order_pos0.amount_total - (450 * 2 + 300 * 3 * 1.05) * 0.95), - 0.01, 'The order has a wrong total including tax and discounts') - - # I click on the "Make Payment" wizard to pay the PoS order with a - # partial amount of 100.0 EUR - context_make_payment = {"active_ids": [self.pos_order_pos0.id], "active_id": self.pos_order_pos0.id} - self.pos_make_payment_0 = self.PosMakePayment.with_context(context_make_payment).create({ - 'amount': 100.0 - }) - - # I click on the validate button to register the payment. - context_payment = {'active_id': self.pos_order_pos0.id} - self.pos_make_payment_0.with_context(context_payment).check() - - # I check that the order is not marked as paid yet - self.assertEqual(self.pos_order_pos0.state, 'draft', 'Order should be in draft state.') - - # On the second payment proposition, I check that it proposes me the - # remaining balance which is 1790.0 EUR - defs = self.pos_make_payment_0.with_context({'active_id': self.pos_order_pos0.id}).default_get(['amount']) - - self.assertLess( - abs(defs['amount'] - ((450 * 2 + 300 * 3 * 1.05) * 0.95 - 100.0)), 0.01, "The remaining balance is incorrect.") - - #'I pay the remaining balance. - context_make_payment = { - "active_ids": [self.pos_order_pos0.id], "active_id": self.pos_order_pos0.id} - - self.pos_make_payment_1 = self.PosMakePayment.with_context(context_make_payment).create({ - 'amount': (450 * 2 + 300 * 3 * 1.05) * 0.95 - 100.0 - }) - - # I click on the validate button to register the payment. - self.pos_make_payment_1.with_context(context_make_payment).check() - - # I check that the order is marked as paid - self.assertEqual(self.pos_order_pos0.state, 'paid', 'Order should be in paid state.') - - # I generate the journal entries - self.pos_order_pos0._create_account_move_line() - - # I test that the generated journal entry is attached to the PoS order - self.assertTrue(self.pos_order_pos0.account_move, "Journal entry has not been attached to Pos order.") - def test_order_refund(self): # I create a new PoS order with 2 lines order = self.PosOrder.create({ @@ -128,6 +30,8 @@ class TestPointOfSaleFlow(TestPointOfSaleCommon): 'discount': 5.0, 'qty': 2.0, 'tax_ids': [(6, 0, self.product3.taxes_id.ids)], + 'price_subtotal': 450 * (1 - 5/100.0) * 2, + 'price_subtotal_incl': 450 * (1 - 5/100.0) * 2, }), (0, 0, { 'name': "OL/0002", 'product_id': self.product4.id, @@ -135,7 +39,13 @@ class TestPointOfSaleFlow(TestPointOfSaleCommon): 'discount': 5.0, 'qty': 3.0, 'tax_ids': [(6, 0, self.product4.taxes_id.ids)], - })] + 'price_subtotal': 300 * (1 - 5/100.0) * 3, + 'price_subtotal_incl': 300 * (1 - 5/100.0) * 3, + })], + 'amount_total': 1710.0, + 'amount_tax': 0.0, + 'amount_paid': 1710.0, + 'amount_return': 0.0, }) # I create a refund @@ -163,11 +73,22 @@ class TestPointOfSaleFlow(TestPointOfSaleCommon): TODO: Check the negative picking after changing the picking relation to One2many (also for a mixed use case), check the quantity, the locations and return picking logic """ + + def compute_tax(product, price, qty=1, taxes=None): + if taxes is None: + taxes = product.taxes_id.filtered(lambda t: t.company_id.id == self.env.user.id) + currency = self.pos_config.pricelist_id.currency_id + res = taxes.compute_all(price, currency, qty, product=product) + untax = res['total_excluded'] + return untax, sum(tax.get('amount', 0.0) for tax in res['taxes']) + # I click on create a new session button self.pos_config.open_session_cb() # I create a PoS order with 2 units of PCSC234 at 450 EUR # and 3 units of PCSC349 at 300 EUR. + untax1, atax1 = compute_tax(self.product3, 450, 2) + untax2, atax2 = compute_tax(self.product4, 300, 3) self.pos_order_pos1 = self.PosOrder.create({ 'company_id': self.company_id, 'pricelist_id': self.partner1.property_product_pricelist.id, @@ -179,6 +100,8 @@ class TestPointOfSaleFlow(TestPointOfSaleCommon): 'discount': 0.0, 'qty': 2.0, 'tax_ids': [(6, 0, self.product3.taxes_id.ids)], + 'price_subtotal': untax1, + 'price_subtotal_incl': untax1 + atax1, }), (0, 0, { 'name': "OL/0002", 'product_id': self.product4.id, @@ -186,7 +109,13 @@ class TestPointOfSaleFlow(TestPointOfSaleCommon): 'discount': 0.0, 'qty': 3.0, 'tax_ids': [(6, 0, self.product4.taxes_id.ids)], - })] + 'price_subtotal': untax2, + 'price_subtotal_incl': untax2 + atax2, + })], + 'amount_tax': atax1 + atax2, + 'amount_total': untax1 + untax2 + atax1 + atax2, + 'amount_paid': 0, + 'amount_return': 0, }) context_make_payment = { @@ -194,13 +123,13 @@ class TestPointOfSaleFlow(TestPointOfSaleCommon): "active_id": self.pos_order_pos1.id } self.pos_make_payment_2 = self.PosMakePayment.with_context(context_make_payment).create({ - 'amount': 1845 + 'amount': untax1 + untax2 + atax1 + atax2 }) # I click on the validate button to register the payment. context_payment = {'active_id': self.pos_order_pos1.id} - self.pos_make_payment_2.with_context(context_payment).check() + self.pos_make_payment_2.with_context(context_payment).check() # I check that the order is marked as paid self.assertEqual( self.pos_order_pos1.state, @@ -208,18 +137,8 @@ class TestPointOfSaleFlow(TestPointOfSaleCommon): 'Order should be in paid state.' ) - # I generate the journal entries - self.pos_order_pos1._create_account_move_line() - - # I test that the generated journal entry is attached to the PoS order - self.assertTrue( - self.pos_order_pos1.account_move, - "Journal entry has not been attached to Pos order." - ) - - # I test that the pickings are created as expected + # I test that the pickings are created as expected during payment # One picking attached and having all the positive move lines in the correct state - self.pos_order_pos1.create_picking() self.assertEqual( self.pos_order_pos1.picking_id.state, 'done', @@ -231,6 +150,9 @@ class TestPointOfSaleFlow(TestPointOfSaleCommon): 'Move Lines should be in done state.' ) + # I create a second order + untax1, atax1 = compute_tax(self.product3, 450, -2) + untax2, atax2 = compute_tax(self.product4, 300, -3) self.pos_order_pos2 = self.PosOrder.create({ 'company_id': self.company_id, 'pricelist_id': self.partner1.property_product_pricelist.id, @@ -242,6 +164,8 @@ class TestPointOfSaleFlow(TestPointOfSaleCommon): 'discount': 0.0, 'qty': (-2.0), 'tax_ids': [(6, 0, self.product3.taxes_id.ids)], + 'price_subtotal': untax1, + 'price_subtotal_incl': untax1 + atax1, }), (0, 0, { 'name': "OL/0004", 'product_id': self.product4.id, @@ -249,7 +173,13 @@ class TestPointOfSaleFlow(TestPointOfSaleCommon): 'discount': 0.0, 'qty': (-3.0), 'tax_ids': [(6, 0, self.product4.taxes_id.ids)], - })] + 'price_subtotal': untax2, + 'price_subtotal_incl': untax2 + atax2, + })], + 'amount_tax': atax1 + atax2, + 'amount_total': untax1 + untax2 + atax1 + atax2, + 'amount_paid': 0, + 'amount_return': 0, }) context_make_payment = { @@ -257,7 +187,7 @@ class TestPointOfSaleFlow(TestPointOfSaleCommon): "active_id": self.pos_order_pos2.id } self.pos_make_payment_3 = self.PosMakePayment.with_context(context_make_payment).create({ - 'amount': (-1845) + 'amount': untax1 + untax2 + atax1 + atax2 }) # I click on the validate button to register the payment. @@ -271,15 +201,6 @@ class TestPointOfSaleFlow(TestPointOfSaleCommon): 'Order should be in paid state.' ) - # I generate the journal entries - self.pos_order_pos2._create_account_move_line() - - # I test that the generated journal entry is attached to the PoS order - self.assertTrue( - self.pos_order_pos2.account_move, - "Journal entry has not been attached to PoS order." - ) - # I test that the pickings are created as expected # One picking attached and having all the positive move lines in the correct state self.pos_order_pos2.create_picking() @@ -294,6 +215,8 @@ class TestPointOfSaleFlow(TestPointOfSaleCommon): 'Move Lines should be in done state.' ) + untax1, atax1 = compute_tax(self.product3, 450, -2) + untax2, atax2 = compute_tax(self.product4, 300, 3) self.pos_order_pos3 = self.PosOrder.create({ 'company_id': self.company_id, 'pricelist_id': self.partner1.property_product_pricelist.id, @@ -305,6 +228,8 @@ class TestPointOfSaleFlow(TestPointOfSaleCommon): 'discount': 0.0, 'qty': (-2.0), 'tax_ids': [(6, 0, self.product3.taxes_id.ids)], + 'price_subtotal': untax1, + 'price_subtotal_incl': untax1 + atax1, }), (0, 0, { 'name': "OL/0006", 'product_id': self.product4.id, @@ -312,7 +237,13 @@ class TestPointOfSaleFlow(TestPointOfSaleCommon): 'discount': 0.0, 'qty': 3.0, 'tax_ids': [(6, 0, self.product4.taxes_id.ids)], - })] + 'price_subtotal': untax2, + 'price_subtotal_incl': untax2 + atax2, + })], + 'amount_tax': atax1 + atax2, + 'amount_total': untax1 + untax2 + atax1 + atax2, + 'amount_paid': 0, + 'amount_return': 0, }) context_make_payment = { @@ -320,7 +251,7 @@ class TestPointOfSaleFlow(TestPointOfSaleCommon): "active_id": self.pos_order_pos3.id } self.pos_make_payment_4 = self.PosMakePayment.with_context(context_make_payment).create({ - 'amount': 45, + 'amount': untax1 + untax2 + atax1 + atax2, }) # I click on the validate button to register the payment. @@ -334,18 +265,8 @@ class TestPointOfSaleFlow(TestPointOfSaleCommon): 'Order should be in paid state.' ) - # I generate the journal entries - self.pos_order_pos3._create_account_move_line() - - # I test that the generated journal entry is attached to the PoS order - self.assertTrue( - self.pos_order_pos3.account_move, - "Journal entry has not been attached to PoS order." - ) - # I test that the pickings are created as expected # One picking attached and having all the positive move lines in the correct state - self.pos_order_pos3.create_picking() self.assertEqual( self.pos_order_pos3.picking_id.state, 'done', @@ -356,9 +277,22 @@ class TestPointOfSaleFlow(TestPointOfSaleCommon): ['done'], 'Move Lines should be in done state.' ) + # I close the session to generate the journal entries + self.pos_config.current_session_id.action_pos_session_closing_control() + def test_order_to_invoice(self): + def compute_tax(product, price, qty=1, taxes=None): + if taxes is None: + taxes = product.taxes_id.filtered(lambda t: t.company_id.id == self.env.user.id) + currency = self.pos_config.pricelist_id.currency_id + res = taxes.compute_all(price, currency, qty, product=product) + untax = res['total_excluded'] + return untax, sum(tax.get('amount', 0.0) for tax in res['taxes']) + + untax1, atax1 = compute_tax(self.product3, 450*0.95, 2) + untax2, atax2 = compute_tax(self.product4, 300*0.95, 3) # I create a new PoS order with 2 units of PC1 at 450 EUR (Tax Incl) and 3 units of PCSC349 at 300 EUR. (Tax Excl) self.pos_order_pos1 = self.PosOrder.create({ 'company_id': self.company_id, @@ -371,6 +305,8 @@ class TestPointOfSaleFlow(TestPointOfSaleCommon): 'discount': 5.0, 'qty': 2.0, 'tax_ids': [(6, 0, self.product3.taxes_id.ids)], + 'price_subtotal': untax1, + 'price_subtotal_incl': untax1 + atax1, }), (0, 0, { 'name': "OL/0002", 'product_id': self.product4.id, @@ -378,13 +314,19 @@ class TestPointOfSaleFlow(TestPointOfSaleCommon): 'discount': 5.0, 'qty': 3.0, 'tax_ids': [(6, 0, self.product4.taxes_id.ids)], - })] + 'price_subtotal': untax2, + 'price_subtotal_incl': untax2 + atax2, + })], + 'amount_tax': atax1 + atax2, + 'amount_total': untax1 + untax2 + atax1 + atax2, + 'amount_paid': 0.0, + 'amount_return': 0.0, }) # I click on the "Make Payment" wizard to pay the PoS order context_make_payment = {"active_ids": [self.pos_order_pos1.id], "active_id": self.pos_order_pos1.id} self.pos_make_payment = self.PosMakePayment.with_context(context_make_payment).create({ - 'amount': (450 * 2 + 300 * 3 * 1.05) * 0.95, + 'amount': untax1 + untax2 + atax1 + atax2, }) # I click on the validate button to register the payment. context_payment = {'active_id': self.pos_order_pos1.id} @@ -401,8 +343,8 @@ class TestPointOfSaleFlow(TestPointOfSaleCommon): # I test that the total of the attached invoice is correct invoice = self.env['account.invoice'].browse(res['res_id']) - self.assertEqual( - float_compare(invoice.amount_total, 1752.75, precision_digits=2), 0, "Invoice not correct") + self.assertAlmostEqual( + invoice.amount_total, self.pos_order_pos1.amount_total, places=2, msg="Invoice not correct") """In order to test the reports on Bank Statement defined in point_of_sale module, I create a bank statement line, confirm it and print the reports""" @@ -456,15 +398,14 @@ class TestPointOfSaleFlow(TestPointOfSaleCommon): """ Simulation of sales coming from the interface, even after closing the session """ - FROMPRODUCT = object() - def compute_tax(product, price, taxes=FROMPRODUCT, qty=1): - if taxes is FROMPRODUCT: - taxes = product.taxes_id + def compute_tax(product, price, qty=1, taxes=None): + if not taxes: + taxes = product.taxes_id.filtered(lambda t: t.company_id.id == self.env.user.id) currency = self.pos_config.pricelist_id.currency_id - taxes = taxes.compute_all(price, currency, qty, product=product)['taxes'] - untax = price * qty - return untax, sum(tax.get('amount', 0.0) for tax in taxes) + res = taxes.compute_all(price, currency, qty, product=product) + untax = res['total_excluded'] + return untax, sum(tax.get('amount', 0.0) for tax in res['taxes']) # I click on create a new session button self.pos_config.open_session_cb() @@ -478,7 +419,7 @@ class TestPointOfSaleFlow(TestPointOfSaleCommon): 'amount_return': 0, 'amount_tax': atax, 'amount_total': untax + atax, - 'creation_date': fields.Datetime.now(), + 'creation_date': fields.Datetime.to_string(fields.Datetime.now()), 'fiscal_position_id': False, 'pricelist_id': self.pos_config.available_pricelist_ids[0].id, 'lines': [[0, @@ -488,6 +429,8 @@ class TestPointOfSaleFlow(TestPointOfSaleCommon): 'pack_lot_ids': [], 'price_unit': 0.9, 'product_id': self.led_lamp.id, + 'price_subtotal': 0.9, + 'price_subtotal_incl': 1.04, 'qty': 1, 'tax_ids': [(6, 0, self.led_lamp.taxes_id.ids)]}]], 'name': 'Order 00042-003-0014', @@ -512,7 +455,7 @@ class TestPointOfSaleFlow(TestPointOfSaleCommon): 'amount_return': 0, 'amount_tax': atax, 'amount_total': untax + atax, - 'creation_date': fields.Datetime.now(), + 'creation_date': fields.Datetime.to_string(fields.Datetime.now()), 'fiscal_position_id': False, 'pricelist_id': self.pos_config.available_pricelist_ids[0].id, 'lines': [[0, @@ -522,6 +465,8 @@ class TestPointOfSaleFlow(TestPointOfSaleCommon): 'pack_lot_ids': [], 'price_unit': 1.2, 'product_id': self.whiteboard_pen.id, + 'price_subtotal': 1.2, + 'price_subtotal_incl': 1.38, 'qty': 1, 'tax_ids': [(6, 0, self.whiteboard_pen.taxes_id.ids)]}]], 'name': 'Order 00043-003-0014', @@ -546,7 +491,7 @@ class TestPointOfSaleFlow(TestPointOfSaleCommon): 'amount_return': 0, 'amount_tax': atax, 'amount_total': untax + atax, - 'creation_date': fields.Datetime.now(), + 'creation_date': fields.Datetime.to_string(fields.Datetime.now()), 'fiscal_position_id': False, 'pricelist_id': self.pos_config.available_pricelist_ids[0].id, 'lines': [[0, @@ -556,6 +501,8 @@ class TestPointOfSaleFlow(TestPointOfSaleCommon): 'pack_lot_ids': [], 'price_unit': 1.28, 'product_id': self.newspaper_rack.id, + 'price_subtotal': 1.28, + 'price_subtotal_incl': 1.47, 'qty': 1, 'tax_ids': [[6, False, self.newspaper_rack.taxes_id.ids]]}]], 'name': 'Order 00044-003-0014', diff --git a/addons/point_of_sale/views/pos_order_view.xml b/addons/point_of_sale/views/pos_order_view.xml index eaf712483a1..d5c61ec4049 100644 --- a/addons/point_of_sale/views/pos_order_view.xml +++ b/addons/point_of_sale/views/pos_order_view.xml @@ -41,8 +41,8 @@ <field name="discount" widget="monetary"/> <field name="tax_ids_after_fiscal_position" widget="many2many_tags" string="Taxes"/> <field name="tax_ids" widget="many2many_tags" invisible="1"/> - <field name="price_subtotal" widget="monetary"/> - <field name="price_subtotal_incl" widget="monetary"/> + <field name="price_subtotal" widget="monetary" force_save="1"/> + <field name="price_subtotal_incl" widget="monetary" force_save="1"/> </tree> <form string="Order lines"> <group col="4"> @@ -50,8 +50,8 @@ <field name="qty"/> <field name="discount" widget="monetary"/> <field name="price_unit" widget="monetary"/> - <field name="price_subtotal" invisible="1" widget="monetary"/> - <field name="price_subtotal_incl" invisible="1" widget="monetary"/> + <field name="price_subtotal" invisible="1" widget="monetary" force_save="1"/> + <field name="price_subtotal_incl" invisible="1" widget="monetary" force_save="1"/> <field name="tax_ids_after_fiscal_position" widget="many2many_tags" string="Taxes"/> <field name="tax_ids" widget="many2many_tags" invisible="1"/> <field name="notice"/> @@ -59,13 +59,19 @@ </form> </field> <group class="oe_subtotal_footer oe_right" colspan="2" name="order_total"> - <field name="amount_tax" widget="monetary"/> + <field name="amount_tax" + force_save="1" + widget="monetary"/> <div class="oe_subtotal_footer_separator oe_inline"> <label for="amount_total" /> <button name="button_dummy" states="draft" string="(update)" class="oe_edit_only oe_link"/> </div> - <field name="amount_total" nolabel="1" class="oe_subtotal_footer_separator" widget="monetary"/> + <field name="amount_total" + force_save="1" + nolabel="1" + class="oe_subtotal_footer_separator" + widget="monetary"/> </group> <div class="oe_clear"/> </page> diff --git a/addons/point_of_sale/wizard/__init__.py b/addons/point_of_sale/wizard/__init__.py index 5801aa23b37..d85d8a81c86 100644 --- a/addons/point_of_sale/wizard/__init__.py +++ b/addons/point_of_sale/wizard/__init__.py @@ -3,6 +3,5 @@ from . import pos_box from . import pos_details -from . import pos_discount from . import pos_open_statement from . import pos_payment diff --git a/addons/point_of_sale/wizard/pos_discount.py b/addons/point_of_sale/wizard/pos_discount.py deleted file mode 100644 index d45f81055b8..00000000000 --- a/addons/point_of_sale/wizard/pos_discount.py +++ /dev/null @@ -1,17 +0,0 @@ -# -*- coding: utf-8 -*- -# Part of Odoo. See LICENSE file for full copyright and licensing details. - -from odoo import api, fields, models - - -class PosDiscount(models.TransientModel): - _name = 'pos.discount' - _description = 'Add a Global Discount' - - discount = fields.Float(string='Discount (%)', required=True, digits=(16, 2), default=5) - - @api.multi - def apply_discount(self): - self.ensure_one() - for order in self.env['pos.order'].browse(self.env.context.get('active_id', False)): - order.lines.write({'discount': self.discount}) diff --git a/addons/point_of_sale/wizard/pos_discount.xml b/addons/point_of_sale/wizard/pos_discount.xml deleted file mode 100644 index ff466c2dadc..00000000000 --- a/addons/point_of_sale/wizard/pos_discount.xml +++ /dev/null @@ -1,27 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<odoo> - <record id="view_pos_discount" model="ir.ui.view"> - <field name="name">pos.discount.form</field> - <field name="model">pos.discount</field> - <field name="arch" type="xml"> - <form string="Apply Discount"> - <group> - <field name="discount"/> - </group> - <footer> - <button name="apply_discount" string="Apply Discount" type="object" class="btn-primary"/> - <button string="Cancel" class="btn-secondary" special="cancel" /> - </footer> - </form> - </field> - </record> - - <record id="action_pos_discount" model="ir.actions.act_window"> - <field name="name">Apply Discount</field> - <field name="type">ir.actions.act_window</field> - <field name="res_model">pos.discount</field> - <field name="view_type">form</field> - <field name="view_mode">form</field> - <field name="target">new</field> - </record> -</odoo> |
