1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807 |
- # -*- coding: utf-8 -*-
- # Part of Odoo. See LICENSE file for full copyright and licensing details.
- import time
- from freezegun import freeze_time
- from datetime import datetime
- import odoo
- from odoo import fields, tools
- from odoo.tools import float_compare, mute_logger, test_reports
- from odoo.tests.common import Form
- from odoo.addons.point_of_sale.tests.common import TestPointOfSaleCommon
- @odoo.tests.tagged('post_install', '-at_install')
- class TestPointOfSaleFlow(TestPointOfSaleCommon):
- def compute_tax(self, product, price, qty=1, taxes=None):
- if not taxes:
- taxes = product.taxes_id.filtered(lambda t: t.company_id.id == self.env.company.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'])
- def test_order_refund(self):
- self.pos_config.open_ui()
- current_session = self.pos_config.current_session_id
- # I create a new PoS order with 2 lines
- order = self.PosOrder.create({
- 'company_id': self.env.company.id,
- 'session_id': current_session.id,
- 'partner_id': self.partner1.id,
- 'pricelist_id': self.partner1.property_product_pricelist.id,
- 'lines': [(0, 0, {
- 'name': "OL/0001",
- 'product_id': self.product3.id,
- 'price_unit': 450,
- '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,
- 'price_unit': 300,
- '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': 0.0,
- 'amount_return': 0.0,
- })
- payment_context = {"active_ids": order.ids, "active_id": order.id}
- order_payment = self.PosMakePayment.with_context(**payment_context).create({
- 'amount': order.amount_total,
- 'payment_method_id': self.cash_payment_method.id
- })
- order_payment.with_context(**payment_context).check()
- self.assertAlmostEqual(order.amount_total, order.amount_paid, msg='Order should be fully paid.')
- # I create a refund
- refund_action = order.refund()
- refund = self.PosOrder.browse(refund_action['res_id'])
- self.assertEqual(order.amount_total, -1*refund.amount_total,
- "The refund does not cancel the order (%s and %s)" % (order.amount_total, refund.amount_total))
- payment_context = {"active_ids": refund.ids, "active_id": refund.id}
- refund_payment = self.PosMakePayment.with_context(**payment_context).create({
- 'amount': refund.amount_total,
- 'payment_method_id': self.cash_payment_method.id,
- })
- # I click on the validate button to register the payment.
- refund_payment.with_context(**payment_context).check()
- self.assertEqual(refund.state, 'paid', "The refund is not marked as paid")
- self.assertTrue(refund.payment_ids.payment_method_id.is_cash_count, msg='There should only be one payment and paid in cash.')
- total_cash_payment = sum(current_session.mapped('order_ids.payment_ids').filtered(lambda payment: payment.payment_method_id.type == 'cash').mapped('amount'))
- current_session.post_closing_cash_details(total_cash_payment)
- current_session.close_session_from_ui()
- self.assertEqual(current_session.state, 'closed', msg='State of current session should be closed.')
- def test_order_refund_lots(self):
- # open pos session
- self.pos_config.open_ui()
- current_session = self.pos_config.current_session_id
- # set up product iwith SN tracing and create two lots (1001, 1002)
- self.stock_location = self.company_data['default_warehouse'].lot_stock_id
- self.product2 = self.env['product.product'].create({
- 'name': 'Product A',
- 'type': 'product',
- 'tracking': 'serial',
- 'categ_id': self.env.ref('product.product_category_all').id,
- })
- lot1 = self.env['stock.lot'].create({
- 'name': '1001',
- 'product_id': self.product2.id,
- 'company_id': self.env.company.id,
- })
- lot2 = self.env['stock.lot'].create({
- 'name': '1002',
- 'product_id': self.product2.id,
- 'company_id': self.env.company.id,
- })
- self.env['stock.quant'].with_context(inventory_mode=True).create({
- 'product_id': self.product2.id,
- 'inventory_quantity': 1,
- 'location_id': self.stock_location.id,
- 'lot_id': lot1.id
- }).action_apply_inventory()
- self.env['stock.quant'].with_context(inventory_mode=True).create({
- 'product_id': self.product2.id,
- 'inventory_quantity': 1,
- 'location_id': self.stock_location.id,
- 'lot_id': lot2.id
- }).action_apply_inventory()
- # create pos order with the two SN created before
- order = self.PosOrder.create({
- 'company_id': self.env.company.id,
- 'session_id': current_session.id,
- 'partner_id': self.partner1.id,
- 'lines': [(0, 0, {
- 'name': "OL/0001",
- 'product_id': self.product2.id,
- 'price_unit': 6,
- 'discount': 0,
- 'qty': 2,
- 'tax_ids': [[6, False, []]],
- 'price_subtotal': 12,
- 'price_subtotal_incl': 12,
- 'pack_lot_ids': [
- [0, 0, {'lot_name': '1001'}],
- [0, 0, {'lot_name': '1002'}],
- ]
- })],
- 'pricelist_id': self.pos_config.pricelist_id.id,
- 'amount_paid': 12.0,
- 'amount_total': 12.0,
- 'amount_tax': 0.0,
- 'amount_return': 0.0,
- 'to_invoice': False,
- })
- payment_context = {"active_ids": order.ids, "active_id": order.id}
- order_payment = self.PosMakePayment.with_context(**payment_context).create({
- 'amount': order.amount_total,
- 'payment_method_id': self.cash_payment_method.id
- })
- order_payment.with_context(**payment_context).check()
- # I create a refund
- refund_action = order.refund()
- refund = self.PosOrder.browse(refund_action['res_id'])
- order_lot_id = [lot_id.lot_name for lot_id in order.lines.pack_lot_ids]
- refund_lot_id = [lot_id.lot_name for lot_id in refund.lines.pack_lot_ids]
- self.assertEqual(
- order_lot_id,
- refund_lot_id,
- "In the refund we should find the same lot as in the original order")
- payment_context = {"active_ids": refund.ids, "active_id": refund.id}
- refund_payment = self.PosMakePayment.with_context(**payment_context).create({
- 'amount': refund.amount_total,
- 'payment_method_id': self.cash_payment_method.id,
- })
- # I click on the validate button to register the payment.
- refund_payment.with_context(**payment_context).check()
- self.assertEqual(refund.state, 'paid', "The refund is not marked as paid")
- current_session.action_pos_session_closing_control()
- def test_order_to_picking(self):
- """
- In order to test the Point of Sale in module, I will do three orders from the sale to the payment,
- invoicing + picking, but will only check the picking consistency in the end.
- 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
- """
- # I click on create a new session button
- self.pos_config.open_ui()
- current_session = self.pos_config.current_session_id
- # I create a PoS order with 2 units of PCSC234 at 450 EUR
- # and 3 units of PCSC349 at 300 EUR.
- untax1, atax1 = self.compute_tax(self.product3, 450, 2)
- untax2, atax2 = self.compute_tax(self.product4, 300, 3)
- self.pos_order_pos1 = self.PosOrder.create({
- 'company_id': self.env.company.id,
- 'session_id': current_session.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)],
- 'price_subtotal': untax1,
- 'price_subtotal_incl': untax1 + atax1,
- }), (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)],
- '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 = {
- "active_ids": [self.pos_order_pos1.id],
- "active_id": self.pos_order_pos1.id
- }
- self.pos_make_payment_2 = self.PosMakePayment.with_context(context_make_payment).create({
- '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()
- # I check that the order is marked as paid
- self.assertEqual(
- self.pos_order_pos1.state,
- 'paid',
- 'Order should be in paid state.'
- )
- # 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.assertEqual(
- self.pos_order_pos1.picking_ids[0].state,
- 'done',
- 'Picking should be in done state.'
- )
- self.assertEqual(
- self.pos_order_pos1.picking_ids[0].move_ids.mapped('state'),
- ['done', 'done'],
- 'Move Lines should be in done state.'
- )
- # I create a second order
- untax1, atax1 = self.compute_tax(self.product3, 450, -2)
- untax2, atax2 = self.compute_tax(self.product4, 300, -3)
- self.pos_order_pos2 = self.PosOrder.create({
- 'company_id': self.env.company.id,
- 'session_id': current_session.id,
- 'pricelist_id': self.partner1.property_product_pricelist.id,
- 'partner_id': self.partner1.id,
- 'lines': [(0, 0, {
- 'name': "OL/0003",
- 'product_id': self.product3.id,
- 'price_unit': 450,
- '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,
- 'price_unit': 300,
- '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 = {
- "active_ids": [self.pos_order_pos2.id],
- "active_id": self.pos_order_pos2.id
- }
- self.pos_make_payment_3 = self.PosMakePayment.with_context(context_make_payment).create({
- 'amount': untax1 + untax2 + atax1 + atax2
- })
- # I click on the validate button to register the payment.
- context_payment = {'active_id': self.pos_order_pos2.id}
- self.pos_make_payment_3.with_context(context_payment).check()
- # I check that the order is marked as paid
- self.assertEqual(
- self.pos_order_pos2.state,
- 'paid',
- 'Order should be in paid state.'
- )
- # I test that the pickings are created as expected
- # One picking attached and having all the positive move lines in the correct state
- self.assertEqual(
- self.pos_order_pos2.picking_ids[0].state,
- 'done',
- 'Picking should be in done state.'
- )
- self.assertEqual(
- self.pos_order_pos2.picking_ids[0].move_ids.mapped('state'),
- ['done', 'done'],
- 'Move Lines should be in done state.'
- )
- untax1, atax1 = self.compute_tax(self.product3, 450, -2)
- untax2, atax2 = self.compute_tax(self.product4, 300, 3)
- self.pos_order_pos3 = self.PosOrder.create({
- 'company_id': self.env.company.id,
- 'session_id': current_session.id,
- 'pricelist_id': self.partner1.property_product_pricelist.id,
- 'partner_id': self.partner1.id,
- 'lines': [(0, 0, {
- 'name': "OL/0005",
- 'product_id': self.product3.id,
- 'price_unit': 450,
- '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,
- 'price_unit': 300,
- '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 = {
- "active_ids": [self.pos_order_pos3.id],
- "active_id": self.pos_order_pos3.id
- }
- self.pos_make_payment_4 = self.PosMakePayment.with_context(context_make_payment).create({
- 'amount': untax1 + untax2 + atax1 + atax2,
- })
- # I click on the validate button to register the payment.
- context_payment = {'active_id': self.pos_order_pos3.id}
- self.pos_make_payment_4.with_context(context_payment).check()
- # I check that the order is marked as paid
- self.assertEqual(
- self.pos_order_pos3.state,
- 'paid',
- 'Order should be in paid state.'
- )
- # I test that the pickings are created as expected
- # One picking attached and having all the positive move lines in the correct state
- self.assertEqual(
- self.pos_order_pos3.picking_ids[0].state,
- 'done',
- 'Picking should be in done state.'
- )
- self.assertEqual(
- self.pos_order_pos3.picking_ids[0].move_ids.mapped('state'),
- ['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_picking02(self):
- """ This test is similar to test_order_to_picking except that this time, there are two products:
- - One tracked by lot
- - One untracked
- - Both are in a sublocation of the main warehouse
- """
- tracked_product, untracked_product = self.env['product.product'].create([{
- 'name': 'SuperProduct Tracked',
- 'type': 'product',
- 'tracking': 'lot',
- 'available_in_pos': True,
- }, {
- 'name': 'SuperProduct Untracked',
- 'type': 'product',
- 'available_in_pos': True,
- }])
- wh_location = self.company_data['default_warehouse'].lot_stock_id
- shelf1_location = self.env['stock.location'].create({
- 'name': 'shelf1',
- 'usage': 'internal',
- 'location_id': wh_location.id,
- })
- lot = self.env['stock.lot'].create({
- 'name': 'SuperLot',
- 'product_id': tracked_product.id,
- 'company_id': self.env.company.id,
- })
- qty = 2
- self.env['stock.quant']._update_available_quantity(tracked_product, shelf1_location, qty, lot_id=lot)
- self.env['stock.quant']._update_available_quantity(untracked_product, shelf1_location, qty)
- self.pos_config.open_ui()
- self.pos_config.current_session_id.update_stock_at_closing = False
- untax, atax = self.compute_tax(tracked_product, 1.15, 1)
- for dummy in range(qty):
- pos_order = self.PosOrder.create({
- 'company_id': self.env.company.id,
- 'session_id': self.pos_config.current_session_id.id,
- 'pricelist_id': self.partner1.property_product_pricelist.id,
- 'partner_id': self.partner1.id,
- 'lines': [(0, 0, {
- 'name': "OL/0001",
- 'product_id': tracked_product.id,
- 'price_unit': 1.15,
- 'discount': 0.0,
- 'qty': 1.0,
- 'tax_ids': [(6, 0, tracked_product.taxes_id.ids)],
- 'price_subtotal': untax,
- 'price_subtotal_incl': untax + atax,
- 'pack_lot_ids': [[0, 0, {'lot_name': lot.name}]],
- }), (0, 0, {
- 'name': "OL/0002",
- 'product_id': untracked_product.id,
- 'price_unit': 1.15,
- 'discount': 0.0,
- 'qty': 1.0,
- 'tax_ids': [(6, 0, untracked_product.taxes_id.ids)],
- 'price_subtotal': untax,
- 'price_subtotal_incl': untax + atax,
- })],
- 'amount_tax': 2 * atax,
- 'amount_total': 2 * (untax + atax),
- 'amount_paid': 0,
- 'amount_return': 0,
- })
- context_make_payment = {
- "active_ids": [pos_order.id],
- "active_id": pos_order.id,
- }
- pos_make_payment = self.PosMakePayment.with_context(context_make_payment).create({
- 'amount': 2 * (untax + atax),
- })
- context_payment = {'active_id': pos_order.id}
- pos_make_payment.with_context(context_payment).check()
- self.assertEqual(pos_order.state, 'paid')
- tracked_line = pos_order.picking_ids.move_line_ids.filtered(lambda ml: ml.product_id.id == tracked_product.id)
- untracked_line = pos_order.picking_ids.move_line_ids - tracked_line
- self.assertEqual(tracked_line.lot_id, lot)
- self.assertFalse(untracked_line.lot_id)
- self.assertEqual(tracked_line.location_id, shelf1_location)
- self.assertEqual(untracked_line.location_id, shelf1_location)
- self.pos_config.current_session_id.action_pos_session_closing_control()
- def test_order_to_invoice(self):
- self.pos_config.open_ui()
- current_session = self.pos_config.current_session_id
- untax1, atax1 = self.compute_tax(self.product3, 450*0.95, 2)
- untax2, atax2 = self.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.env.company.id,
- 'session_id': current_session.id,
- 'partner_id': self.partner1.id,
- 'pricelist_id': self.partner1.property_product_pricelist.id,
- 'lines': [(0, 0, {
- 'name': "OL/0001",
- 'product_id': self.product3.id,
- 'price_unit': 450,
- 'discount': 5.0,
- 'qty': 2.0,
- 'tax_ids': [(6, 0, self.product3.taxes_id.filtered(lambda t: t.company_id.id == self.env.company.id).ids)],
- 'price_subtotal': untax1,
- 'price_subtotal_incl': untax1 + atax1,
- }), (0, 0, {
- 'name': "OL/0002",
- 'product_id': self.product4.id,
- 'price_unit': 300,
- 'discount': 5.0,
- 'qty': 3.0,
- 'tax_ids': [(6, 0, self.product4.taxes_id.filtered(lambda t: t.company_id.id == self.env.company.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': 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.with_context(context_payment).check()
- # I check that the order is marked as paid and there is no invoice
- # attached to it
- self.assertEqual(self.pos_order_pos1.state, 'paid', "Order should be in paid state.")
- self.assertFalse(self.pos_order_pos1.account_move, 'Invoice should not be attached to order.')
- # I generate an invoice from the order
- res = self.pos_order_pos1.action_pos_order_invoice()
- self.assertIn('res_id', res, "Invoice should be created")
- # I test that the total of the attached invoice is correct
- invoice = self.env['account.move'].browse(res['res_id'])
- if invoice.state != 'posted':
- invoice.action_post()
- self.assertAlmostEqual(
- invoice.amount_total, self.pos_order_pos1.amount_total, places=2, msg="Invoice not correct")
- # I close the session to generate the journal entries
- current_session.action_pos_session_closing_control()
- def test_create_from_ui(self):
- """
- Simulation of sales coming from the interface, even after closing the session
- """
- # I click on create a new session button
- self.pos_config.open_ui()
- current_session = self.pos_config.current_session_id
- num_starting_orders = len(current_session.order_ids)
- current_session.set_cashbox_pos(0, None)
- untax, atax = self.compute_tax(self.led_lamp, 0.9)
- carrot_order = {'data':
- {'amount_paid': untax + atax,
- 'amount_return': 0,
- 'amount_tax': atax,
- 'amount_total': untax + atax,
- '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,
- 0,
- {'discount': 0,
- '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',
- 'partner_id': False,
- 'pos_session_id': current_session.id,
- 'sequence_number': 2,
- 'statement_ids': [[0,
- 0,
- {'amount': untax + atax,
- 'name': fields.Datetime.now(),
- 'payment_method_id': self.cash_payment_method.id}]],
- 'uid': '00042-003-0014',
- 'user_id': self.env.uid},
- 'to_invoice': False}
- untax, atax = self.compute_tax(self.whiteboard_pen, 1.2)
- zucchini_order = {'data':
- {'amount_paid': untax + atax,
- 'amount_return': 0,
- 'amount_tax': atax,
- 'amount_total': untax + atax,
- '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,
- 0,
- {'discount': 0,
- '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',
- 'partner_id': self.partner1.id,
- 'pos_session_id': current_session.id,
- 'sequence_number': self.pos_config.journal_id.id,
- 'statement_ids': [[0,
- 0,
- {'amount': untax + atax,
- 'name': fields.Datetime.now(),
- 'payment_method_id': self.credit_payment_method.id}]],
- 'uid': '00043-003-0014',
- 'user_id': self.env.uid},
- 'to_invoice': False}
- untax, atax = self.compute_tax(self.newspaper_rack, 1.28)
- newspaper_rack_order = {'data':
- {'amount_paid': untax + atax,
- 'amount_return': 0,
- 'amount_tax': atax,
- 'amount_total': untax + atax,
- '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,
- 0,
- {'discount': 0,
- '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',
- 'partner_id': False,
- 'pos_session_id': current_session.id,
- 'sequence_number': self.pos_config.journal_id.id,
- 'statement_ids': [[0,
- 0,
- {'amount': untax + atax,
- 'name': fields.Datetime.now(),
- 'payment_method_id': self.bank_payment_method.id}]],
- 'uid': '00044-003-0014',
- 'user_id': self.env.uid},
- 'to_invoice': False}
- # I create an order on an open session
- self.PosOrder.create_from_ui([carrot_order])
- self.assertEqual(num_starting_orders + 1, len(current_session.order_ids), "Submitted order not encoded")
- # I close the session
- total_cash_payment = sum(current_session.mapped('order_ids.payment_ids').filtered(lambda payment: payment.payment_method_id.type == 'cash').mapped('amount'))
- current_session.post_closing_cash_details(total_cash_payment)
- current_session.close_session_from_ui()
- self.assertEqual(current_session.state, 'closed', "Session was not properly closed")
- self.assertFalse(self.pos_config.current_session_id, "Current session not properly recomputed")
- # I keep selling after the session is closed
- with mute_logger('odoo.addons.point_of_sale.models.pos_order'):
- self.PosOrder.create_from_ui([zucchini_order, newspaper_rack_order])
- rescue_session = self.PosSession.search([
- ('config_id', '=', self.pos_config.id),
- ('state', '=', 'opened'),
- ('rescue', '=', True)
- ])
- self.assertEqual(len(rescue_session), 1, "One (and only one) rescue session should be created for orphan orders")
- self.assertIn("(RESCUE FOR %s)" % current_session.name, rescue_session.name, "Rescue session is not linked to the previous one")
- self.assertEqual(len(rescue_session.order_ids), 2, "Rescue session does not contain both orders")
- # I close the rescue session
- total_cash_payment = sum(rescue_session.mapped('order_ids.payment_ids').filtered(lambda payment: payment.payment_method_id.type == 'cash').mapped('amount'))
- rescue_session.post_closing_cash_details(total_cash_payment)
- rescue_session.close_session_from_ui()
- self.assertEqual(rescue_session.state, 'closed', "Rescue session was not properly closed")
- self.assertEqual(rescue_session.cash_register_balance_start, current_session.cash_register_balance_end_real, "Rescue session does not start with the same amount as the previous session")
- def test_order_to_payment_currency(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.
- The order will be in a different currency than the company currency.
- """
- # Make sure the company is in USD
- self.env.ref('base.USD').active = True
- self.env.ref('base.EUR').active = True
- self.env.cr.execute(
- "UPDATE res_company SET currency_id = %s WHERE id = %s",
- [self.env.ref('base.USD').id, self.env.company.id])
- # Demo data are crappy, clean-up the rates
- self.env['res.currency.rate'].search([]).unlink()
- self.env['res.currency.rate'].create({
- 'name': '2010-01-01',
- 'rate': 2.0,
- 'currency_id': self.env.ref('base.EUR').id,
- })
- # make a config that has currency different from the company
- eur_pricelist = self.partner1.property_product_pricelist.copy(default={'currency_id': self.env.ref('base.EUR').id})
- sale_journal = self.env['account.journal'].create({
- 'name': 'PoS Sale EUR',
- 'type': 'sale',
- 'code': 'POSE',
- 'company_id': self.company.id,
- 'sequence': 12,
- 'currency_id': self.env.ref('base.EUR').id
- })
- eur_config = self.pos_config.create({
- 'name': 'Shop EUR Test',
- 'journal_id': sale_journal.id,
- 'use_pricelist': True,
- 'available_pricelist_ids': [(6, 0, eur_pricelist.ids)],
- 'pricelist_id': eur_pricelist.id,
- 'payment_method_ids': [(6, 0, self.bank_payment_method.ids)]
- })
- # I click on create a new session button
- eur_config.open_ui()
- current_session = eur_config.current_session_id
- # 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)
- untax1, atax1 = self.compute_tax(self.product3, 450, 2)
- untax2, atax2 = self.compute_tax(self.product4, 300, 3)
- self.pos_order_pos0 = self.PosOrder.create({
- 'company_id': self.env.company.id,
- 'session_id': current_session.id,
- 'pricelist_id': eur_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.filtered(lambda t: t.company_id == self.env.company).ids)],
- 'price_subtotal': untax1,
- 'price_subtotal_incl': untax1 + atax1,
- }), (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.filtered(lambda t: t.company_id == self.env.company).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 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.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,
- 'payment_method_id': self.bank_payment_method.id,
- })
- # 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) - 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) - 100.0,
- 'payment_method_id': self.bank_payment_method.id,
- })
- # 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
- current_session.action_pos_session_validate()
- # I test that the generated journal entry is attached to the PoS order
- self.assertTrue(current_session.move_id, "Journal entry should have been attached to the session.")
- # Check the amounts
- debit_lines = current_session.move_id.mapped('line_ids.debit')
- credit_lines = current_session.move_id.mapped('line_ids.credit')
- amount_currency_lines = current_session.move_id.mapped('line_ids.amount_currency')
- for a, b in zip(sorted(debit_lines), [0.0, 0.0, 0.0, 0.0, 922.5]):
- self.assertAlmostEqual(a, b)
- for a, b in zip(sorted(credit_lines), [0.0, 22.5, 40.91, 409.09, 450]):
- self.assertAlmostEqual(a, b)
- for a, b in zip(sorted(amount_currency_lines), [-900, -818.18, -81.82, -45, 1845]):
- self.assertAlmostEqual(a, b)
- def test_order_to_invoice_no_tax(self):
- self.pos_config.open_ui()
- current_session = self.pos_config.current_session_id
- # 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.env.company.id,
- 'session_id': current_session.id,
- 'partner_id': self.partner1.id,
- 'pricelist_id': self.partner1.property_product_pricelist.id,
- 'lines': [(0, 0, {
- 'name': "OL/0001",
- 'product_id': self.product3.id,
- 'price_unit': 450,
- 'discount': 5.0,
- 'qty': 2.0,
- 'price_subtotal': 855,
- 'price_subtotal_incl': 855,
- }), (0, 0, {
- 'name': "OL/0002",
- 'product_id': self.product4.id,
- 'price_unit': 300,
- 'discount': 5.0,
- 'qty': 3.0,
- 'price_subtotal': 855,
- 'price_subtotal_incl': 855,
- })],
- 'amount_tax': 855 * 2,
- 'amount_total': 855 * 2,
- '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': 855 * 2,
- })
- # I click on the validate button to register the payment.
- context_payment = {'active_id': self.pos_order_pos1.id}
- self.pos_make_payment.with_context(context_payment).check()
- # I check that the order is marked as paid and there is no invoice
- # attached to it
- self.assertEqual(self.pos_order_pos1.state, 'paid', "Order should be in paid state.")
- self.assertFalse(self.pos_order_pos1.account_move, 'Invoice should not be attached to order yet.')
- # I generate an invoice from the order
- res = self.pos_order_pos1.action_pos_order_invoice()
- self.assertIn('res_id', res, "No invoice created")
- # I test that the total of the attached invoice is correct
- invoice = self.env['account.move'].browse(res['res_id'])
- if invoice.state != 'posted':
- invoice.action_post()
- self.assertAlmostEqual(
- invoice.amount_total, self.pos_order_pos1.amount_total, places=2, msg="Invoice not correct")
- for iline in invoice.invoice_line_ids:
- self.assertFalse(iline.tax_ids)
- self.pos_config.current_session_id.action_pos_session_closing_control()
- def test_order_with_deleted_tax(self):
- # create tax
- dummy_50_perc_tax = self.env['account.tax'].create({
- 'name': 'Tax 50%',
- 'amount_type': 'percent',
- 'amount': 50.0,
- 'price_include': 0
- })
- # set tax to product
- product5 = self.env['product.product'].create({
- 'name': 'product5',
- 'type': 'product',
- 'categ_id': self.env.ref('product.product_category_all').id,
- 'taxes_id': dummy_50_perc_tax.ids
- })
- # sell product thru pos
- self.pos_config.open_ui()
- pos_session = self.pos_config.current_session_id
- untax, atax = self.compute_tax(product5, 10.0)
- product5_order = {'data':
- {'amount_paid': untax + atax,
- 'amount_return': 0,
- 'amount_tax': atax,
- 'amount_total': untax + atax,
- '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,
- 0,
- {'discount': 0,
- 'pack_lot_ids': [],
- 'price_unit': 10.0,
- 'product_id': product5.id,
- 'price_subtotal': 10.0,
- 'price_subtotal_incl': 15.0,
- 'qty': 1,
- 'tax_ids': [(6, 0, product5.taxes_id.ids)]}]],
- 'name': 'Order 12345-123-1234',
- 'partner_id': False,
- 'pos_session_id': pos_session.id,
- 'sequence_number': 2,
- 'statement_ids': [[0,
- 0,
- {'amount': untax + atax,
- 'name': fields.Datetime.now(),
- 'payment_method_id': self.cash_payment_method.id}]],
- 'uid': '12345-123-1234',
- 'user_id': self.env.uid},
- 'to_invoice': False}
- self.PosOrder.create_from_ui([product5_order])
- # delete tax
- dummy_50_perc_tax.unlink()
- total_cash_payment = sum(pos_session.mapped('order_ids.payment_ids').filtered(lambda payment: payment.payment_method_id.type == 'cash').mapped('amount'))
- pos_session.post_closing_cash_details(total_cash_payment)
- # close session (should not fail here)
- # We don't call `action_pos_session_closing_control` to force the failed
- # closing which will return the action because the internal rollback call messes
- # with the rollback of the test runner. So instead, we directly call the method
- # that returns the action by specifying the imbalance amount.
- action = pos_session._close_session_action(5.0)
- wizard = self.env['pos.close.session.wizard'].browse(action['res_id'])
- wizard.with_context(action['context']).close_session()
- # check the difference line
- diff_line = pos_session.move_id.line_ids.filtered(lambda line: line.name == 'Difference at closing PoS session')
- self.assertAlmostEqual(diff_line.credit, 5.0, msg="Missing amount of 5.0")
- def test_order_multi_step_route(self):
- """ Test that orders in sessions with "Ship Later" enabled and "Specific Route" set to a
- multi-step (2/3) route can be validated. This config implies multiple picking types
- and multiple move_lines.
- """
- tracked_product = self.env['product.product'].create({
- 'name': 'SuperProduct Tracked',
- 'type': 'product',
- 'tracking': 'lot',
- 'available_in_pos': True
- })
- tracked_product_2 = self.env['product.product'].create({
- 'name': 'SuperProduct Tracked 2',
- 'type': 'product',
- 'tracking': 'lot',
- 'available_in_pos': True
- })
- tracked_product_2_lot = self.env['stock.lot'].create({
- 'name': '80085',
- 'product_id': tracked_product_2.id,
- 'company_id': self.env.company.id,
- })
- stock_location = self.company_data['default_warehouse'].lot_stock_id
- self.env['stock.quant'].with_context(inventory_mode=True).create({
- 'product_id': tracked_product_2.id,
- 'inventory_quantity': 1,
- 'location_id': stock_location.id,
- 'lot_id': tracked_product_2_lot.id
- }).action_apply_inventory()
- warehouse_id = self.company_data['default_warehouse']
- warehouse_id.delivery_steps = 'pick_ship'
- self.pos_config.ship_later = True
- self.pos_config.warehouse_id = warehouse_id
- self.pos_config.route_id = warehouse_id.route_ids[-1]
- self.pos_config.open_ui()
- self.pos_config.current_session_id.update_stock_at_closing = False
- untax, tax = self.compute_tax(tracked_product, 1.15, 1)
- pos_order = self.PosOrder.create({
- 'company_id': self.env.company.id,
- 'session_id': self.pos_config.current_session_id.id,
- 'pricelist_id': self.partner1.property_product_pricelist.id,
- 'partner_id': self.partner1.id,
- 'lines': [(0, 0, {
- 'name': "OL/0001",
- 'product_id': tracked_product.id,
- 'price_unit': 1.15,
- 'qty': 1.0,
- 'price_subtotal': untax,
- 'price_subtotal_incl': untax + tax,
- 'pack_lot_ids': [
- [0, 0, {'lot_name': '80085'}],
- ]
- }),
- (0, 0, {
- 'name': "OL/0002",
- 'product_id': tracked_product_2.id,
- 'price_unit': 1.15,
- 'qty': 1.0,
- 'price_subtotal': untax,
- 'price_subtotal_incl': untax + tax,
- 'pack_lot_ids': [
- [0, 0, {'lot_name': '80085'}],
- ]
- })],
- 'amount_tax': tax,
- 'amount_total': untax+tax,
- 'amount_paid': 0,
- 'amount_return': 0,
- 'to_ship': True,
- })
- context_make_payment = {
- "active_ids": [pos_order.id],
- "active_id": pos_order.id,
- }
- pos_make_payment = self.PosMakePayment.with_context(context_make_payment).create({
- 'amount': untax+tax,
- })
- context_payment = {'active_id': pos_order.id}
- pos_make_payment.with_context(context_payment).check()
- pickings = pos_order.picking_ids
- picking_mls_no_stock = pickings.move_line_ids.filtered(lambda l: l.product_id.id == tracked_product.id)
- picking_mls_stock = pickings.move_line_ids.filtered(lambda l: l.product_id.id == tracked_product_2.id)
- self.assertEqual(pos_order.state, 'paid')
- self.assertEqual(len(picking_mls_no_stock), 0)
- self.assertEqual(len(picking_mls_stock), 1)
- self.assertEqual(len(pickings.picking_type_id), 2)
- def test_order_refund_picking(self):
- self.pos_config.open_ui()
- current_session = self.pos_config.current_session_id
- current_session.update_stock_at_closing = True
- # I create a new PoS order with 1 line
- order = self.PosOrder.create({
- 'company_id': self.env.company.id,
- 'session_id': current_session.id,
- 'partner_id': self.partner1.id,
- 'pricelist_id': self.partner1.property_product_pricelist.id,
- 'lines': [(0, 0, {
- 'name': "OL/0001",
- 'product_id': self.product3.id,
- 'price_unit': 450,
- '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,
- })],
- 'amount_total': 1710.0,
- 'amount_tax': 0.0,
- 'amount_paid': 0.0,
- 'amount_return': 0.0,
- 'to_invoice': True
- })
- payment_context = {"active_ids": order.ids, "active_id": order.id}
- order_payment = self.PosMakePayment.with_context(**payment_context).create({
- 'amount': order.amount_total,
- 'payment_method_id': self.cash_payment_method.id
- })
- order_payment.with_context(**payment_context).check()
- # I create a refund
- refund_action = order.refund()
- refund = self.PosOrder.browse(refund_action['res_id'])
- payment_context = {"active_ids": refund.ids, "active_id": refund.id}
- refund_payment = self.PosMakePayment.with_context(**payment_context).create({
- 'amount': refund.amount_total,
- 'payment_method_id': self.cash_payment_method.id,
- })
- # I click on the validate button to register the payment.
- refund_payment.with_context(**payment_context).check()
- refund.action_pos_order_invoice()
- self.assertEqual(refund.picking_count, 1)
- def test_order_with_different_payments_and_refund(self):
- """
- Test that all the payments are correctly taken into account when the order contains multiple payments and money refund.
- In this example, we create an order with two payments for a product of 750$:
- - one payment of $300 with customer account
- - one payment of $460 with cash
- Then, we refund the order with $10, and check that the amount still due is 300$.
- """
- product5 = self.env['product.product'].create({
- 'name': 'product5',
- 'type': 'product',
- 'categ_id': self.env.ref('product.product_category_all').id,
- })
- # sell product thru pos
- self.pos_config.open_ui()
- pos_session = self.pos_config.current_session_id
- product5_order = {'data':
- {'amount_paid': 750,
- 'amount_return': 10,
- 'amount_tax': 0,
- 'amount_total': 750,
- '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, 0, {
- 'discount': 0,
- 'pack_lot_ids': [],
- 'price_unit': 750.0,
- 'product_id': product5.id,
- 'price_subtotal': 750.0,
- 'price_subtotal_incl': 750.0,
- 'tax_ids': [[6, False, []]],
- 'qty': 1,
- }]],
- 'name': 'Order 12345-123-1234',
- 'partner_id': self.partner1.id,
- 'pos_session_id': pos_session.id,
- 'sequence_number': 2,
- 'statement_ids': [[0, 0, {
- 'amount': 460,
- 'name': fields.Datetime.now(),
- 'payment_method_id': self.cash_payment_method.id
- }], [0, 0, {
- 'amount': 300,
- 'name': fields.Datetime.now(),
- 'payment_method_id': self.credit_payment_method.id
- }]],
- 'uid': '12345-123-1234',
- 'user_id': self.env.uid,
- 'to_invoice': True, }
- }
- pos_order_id = self.PosOrder.create_from_ui([product5_order])[0]['id']
- pos_order = self.PosOrder.search([('id', '=', pos_order_id)])
- #assert account_move amount_residual is 300
- self.assertEqual(pos_order.account_move.amount_residual, 300)
- def test_sale_order_postponed_invoicing(self):
- """ Test the flow of creating an invoice later, after the POS session has been closed and everything has been processed.
- The process should:
- - Create a new misc entry, that will revert part of the POS closing entry.
- - Create the move and associating payment(s) entry, as it would do when closing with invoice.
- - Reconcile the receivable lines from the created misc entry with the ones from the created payment(s)
- """
- # Create the order on the first of january.
- with freeze_time('2020-01-01'):
- product = self.env['product.product'].create({
- 'name': 'Dummy product',
- 'type': 'product',
- 'categ_id': self.env.ref('product.product_category_all').id,
- 'taxes_id': self.tax_sale_a.ids,
- })
- self.pos_config.open_ui()
- pos_session = self.pos_config.current_session_id
- untax, atax = self.compute_tax(product, 500, 1)
- pos_order_data = {
- 'data': {
- 'amount_paid': untax + atax,
- 'amount_return': 0,
- 'amount_tax': atax,
- 'amount_total': untax + atax,
- '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, 0, {
- 'discount': 0,
- 'id': 42,
- 'pack_lot_ids': [],
- 'price_unit': 500.0,
- 'product_id': product.id,
- 'price_subtotal': 500.0,
- 'price_subtotal_incl': 575.0,
- 'qty': 1,
- 'tax_ids': [(6, 0, product.taxes_id.ids)]
- })],
- 'name': 'Order 12345-123-1234',
- 'partner_id': False,
- 'pos_session_id': pos_session.id,
- 'sequence_number': 2,
- 'statement_ids': [(0, 0, {
- 'amount': untax + atax,
- 'name': fields.Datetime.now(),
- 'payment_method_id': self.cash_payment_method.id
- })],
- 'uid': '12345-123-1234',
- 'user_id': self.env.uid
- },
- 'id': '12345-123-1234',
- 'to_invoice': False
- }
- pos_order_id = self.PosOrder.create_from_ui([pos_order_data])[0]['id']
- pos_order = self.env['pos.order'].browse(pos_order_id)
- # End the session. The order has been created without any invoice.
- self.pos_config.current_session_id.action_pos_session_closing_control()
- self.assertFalse(pos_order.account_move.exists())
- # Client is back on the 3rd, asks for an invoice.
- with freeze_time('2020-01-03'):
- # We set the partner on the order
- pos_order.partner_id = self.partner1.id
- pos_order.action_pos_order_invoice()
- # We should now have: an invoice, a payment, and a misc entry reconciled with the payment that reverse the original POS closing entry.
- invoice = pos_order.account_move
- closing_entry = pos_order.session_move_id
- # This search isn't the best, but we don't have any references to this move stored on other models.
- misc_reversal_entry = self.env['account.move'].search([('ref', '=', f'Reversal of POS closing entry {closing_entry.name} for order {pos_order.name} from session {pos_order.session_id.name}')])
- # In this case we will have only one, for cash payment
- payment = self.env['account.move'].search([('ref', '=like', f'Invoice payment for {pos_order.name} ({pos_order.account_move.name}) using {self.cash_payment_method.name}')])
- # And thus only one bank statement for it
- statement = self.env['account.move'].search([('journal_id', '=', self.company_data['default_journal_cash'].id)])
- self.assertTrue(invoice.exists() and closing_entry.exists() and misc_reversal_entry.exists() and payment.exists())
- # Check 1: Check that we have reversed every credit line on the closing entry.
- for closing_entry_line, misc_reversal_entry_line in zip(closing_entry.line_ids, misc_reversal_entry.line_ids):
- if closing_entry_line.balance < 0:
- self.assertEqual(closing_entry_line.balance, -misc_reversal_entry_line.balance)
- self.assertEqual(closing_entry_line.account_id, misc_reversal_entry_line.account_id)
- # Check 2: Reconciliation
- # The invoice receivable should be reconciled with the payment receivable of the same account.
- invoice_receivable_line = invoice.line_ids.filtered(lambda line: line.account_id == self.company_data['default_account_receivable'])
- payment_receivable_line = payment.line_ids.filtered(lambda line: line.account_id == self.company_data['default_account_receivable'])
- self.assertEqual(invoice_receivable_line.matching_number, payment_receivable_line.matching_number)
- # The payment receivable (POS) is reconciled with the closing entry receivable (POS)
- payment_receivable_pos_line = payment.line_ids.filtered(lambda line: line.account_id == self.company_data['company'].account_default_pos_receivable_account_id)
- misc_receivable_pos_line = misc_reversal_entry.line_ids.filtered(lambda line: line.account_id == self.company_data['company'].account_default_pos_receivable_account_id)
- self.assertEqual(misc_receivable_pos_line.matching_number, payment_receivable_pos_line.matching_number)
- # The closing entry receivable is reconciled with the bank statement
- closing_entry_receivable_line = closing_entry.line_ids.filtered(lambda line: line.account_id == self.company_data['default_account_receivable']) # Because the payment method use the default receivable
- statement_receivable_line = statement.line_ids.filtered(lambda line: line.account_id == self.company_data['default_account_receivable'] and line.name == pos_order.session_id.name) # Because the payment method use the default receivable
- self.assertEqual(closing_entry_receivable_line.matching_number, statement_receivable_line.matching_number)
- def test_order_pos_tax_same_as_company(self):
- """Test that when the default_pos_receivable_account and the partner account_receivable are the same,
- payment are correctly reconciled and the invoice is correctly marked as paid.
- """
- self.pos_config.open_ui()
- current_session = self.pos_config.current_session_id
- current_session.company_id.account_default_pos_receivable_account_id = self.partner1.property_account_receivable_id
- product5_order = {'data':
- {'amount_paid': 750,
- 'amount_tax': 0,
- 'amount_return':0,
- 'amount_total': 750,
- '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, 0, {
- 'discount': 0,
- 'pack_lot_ids': [],
- 'price_unit': 750.0,
- 'product_id': self.product3.id,
- 'price_subtotal': 750.0,
- 'price_subtotal_incl': 750.0,
- 'tax_ids': [[6, False, []]],
- 'qty': 1,
- }]],
- 'name': 'Order 12345-123-1234',
- 'partner_id': self.partner1.id,
- 'pos_session_id': current_session.id,
- 'sequence_number': 2,
- 'statement_ids': [[0, 0, {
- 'amount': 450,
- 'name': fields.Datetime.now(),
- 'payment_method_id': self.cash_payment_method.id
- }], [0, 0, {
- 'amount': 300,
- 'name': fields.Datetime.now(),
- 'payment_method_id': self.bank_payment_method.id
- }]],
- 'uid': '12345-123-1234',
- 'user_id': self.env.uid,
- 'to_invoice': True, }
- }
- pos_order_id = self.PosOrder.create_from_ui([product5_order])[0]['id']
- pos_order = self.PosOrder.search([('id', '=', pos_order_id)])
- self.assertEqual(pos_order.account_move.amount_residual, 0)
- def test_order_refund_with_owner(self):
- # open pos session
- self.pos_config.open_ui()
- current_session = self.pos_config.current_session_id
- # set up product iwith SN tracing and create two lots (1001, 1002)
- self.stock_location = self.company_data['default_warehouse'].lot_stock_id
- self.product2 = self.env['product.product'].create({
- 'name': 'Product A',
- 'type': 'product',
- 'categ_id': self.env.ref('product.product_category_all').id,
- })
- self.env['stock.quant'].with_context(inventory_mode=True).create({
- 'product_id': self.product2.id,
- 'inventory_quantity': 1,
- 'location_id': self.stock_location.id,
- 'owner_id': self.partner1.id
- }).action_apply_inventory()
- # create pos order with the two SN created before
- order = self.PosOrder.create({
- 'company_id': self.env.company.id,
- 'session_id': current_session.id,
- 'partner_id': self.partner1.id,
- 'lines': [(0, 0, {
- 'name': "OL/0001",
- 'product_id': self.product2.id,
- 'price_unit': 6,
- 'discount': 0,
- 'qty': 1,
- 'tax_ids': [[6, False, []]],
- 'price_subtotal': 6,
- 'price_subtotal_incl': 6,
- })],
- 'pricelist_id': self.pos_config.pricelist_id.id,
- 'amount_paid': 6.0,
- 'amount_total': 6.0,
- 'amount_tax': 0.0,
- 'amount_return': 0.0,
- 'to_invoice': False,
- })
- payment_context = {"active_ids": order.ids, "active_id": order.id}
- order_payment = self.PosMakePayment.with_context(**payment_context).create({
- 'amount': order.amount_total,
- 'payment_method_id': self.cash_payment_method.id
- })
- order_payment.with_context(**payment_context).check()
- # I create a refund
- refund_action = order.refund()
- refund = self.PosOrder.browse(refund_action['res_id'])
- payment_context = {"active_ids": refund.ids, "active_id": refund.id}
- refund_payment = self.PosMakePayment.with_context(**payment_context).create({
- 'amount': refund.amount_total,
- 'payment_method_id': self.cash_payment_method.id,
- })
- # I click on the validate button to register the payment.
- refund_payment.with_context(**payment_context).check()
- current_session.action_pos_session_closing_control()
- self.assertEqual(refund.picking_ids.move_line_ids_without_package.owner_id.id, order.picking_ids.move_line_ids_without_package.owner_id.id, "The owner of the refund is not the same as the owner of the original order")
- def test_journal_entries_category_without_account(self):
- #create a new product category without account
- category = self.env['product.category'].create({
- 'name': 'Category without account',
- 'property_account_income_categ_id': False,
- 'property_account_expense_categ_id': False,
- })
- account = self.env['account.account'].create({
- 'name': 'Account for category without account',
- 'code': 'X1111',
- })
- product = self.env['product.product'].create({
- 'name': 'Product with category without account',
- 'type': 'product',
- 'categ_id': category.id,
- 'property_account_income_id': account,
- })
- self.pos_config.journal_id.default_account_id = account.id
- #create a new pos order with the product
- self.pos_config.open_ui()
- current_session = self.pos_config.current_session_id
- order = self.PosOrder.create({
- 'company_id': self.env.company.id,
- 'session_id': current_session.id,
- 'partner_id': self.partner1.id,
- 'pricelist_id': self.partner1.property_product_pricelist.id,
- 'lines': [(0, 0, {
- 'name': "OL/0001",
- 'product_id': product.id,
- 'price_unit': 10,
- 'discount': 0.0,
- 'qty': 1,
- 'tax_ids': [],
- 'price_subtotal': 10,
- 'price_subtotal_incl': 10,
- })],
- 'amount_total': 10,
- 'amount_tax': 0.0,
- 'amount_paid': 10,
- 'amount_return': 0.0,
- 'to_invoice': True
- })
- #create a payment
- payment_context = {"active_ids": order.ids, "active_id": order.id}
- order_payment = self.PosMakePayment.with_context(**payment_context).create({
- 'amount': order.amount_total,
- 'payment_method_id': self.cash_payment_method.id
- })
- order_payment.with_context(**payment_context).check()
- current_session.action_pos_session_closing_control()
- self.assertEqual(current_session.move_id.line_ids[0].account_id.id, account.id)
- def test_tracked_product_with_owner(self):
- # open pos session
- self.pos_config.open_ui()
- current_session = self.pos_config.current_session_id
- # set up product iwith SN tracing and create two lots (1001, 1002)
- self.stock_location = self.company_data['default_warehouse'].lot_stock_id
- self.product2 = self.env['product.product'].create({
- 'name': 'Product A',
- 'type': 'product',
- 'tracking': 'serial',
- 'categ_id': self.env.ref('product.product_category_all').id,
- })
- lot1 = self.env['stock.lot'].create({
- 'name': '1001',
- 'product_id': self.product2.id,
- 'company_id': self.env.company.id,
- })
- self.env['stock.quant']._update_available_quantity(self.product2, self.stock_location, 1, lot_id=lot1, owner_id=self.partner1)
- # create pos order with the two SN created before
- order = self.PosOrder.create({
- 'company_id': self.env.company.id,
- 'session_id': current_session.id,
- 'partner_id': self.partner1.id,
- 'lines': [(0, 0, {
- 'name': "OL/0001",
- 'id': 1,
- 'product_id': self.product2.id,
- 'price_unit': 6,
- 'discount': 0,
- 'qty': 1,
- 'tax_ids': [[6, False, []]],
- 'price_subtotal': 6,
- 'price_subtotal_incl': 6,
- 'pack_lot_ids': [
- [0, 0, {'lot_name': '1001'}],
- ]
- })],
- 'pricelist_id': self.pos_config.pricelist_id.id,
- 'amount_paid': 6.0,
- 'amount_total': 6.0,
- 'amount_tax': 0.0,
- 'amount_return': 0.0,
- 'to_invoice': False,
- })
- payment_context = {"active_ids": order.ids, "active_id": order.id}
- order_payment = self.PosMakePayment.with_context(**payment_context).create({
- 'amount': order.amount_total,
- 'payment_method_id': self.cash_payment_method.id
- })
- order_payment.with_context(**payment_context).check()
- current_session.action_pos_session_closing_control()
- self.assertEqual(current_session.picking_ids.move_line_ids.owner_id.id, self.partner1.id)
- def test_order_refund_with_invoice(self):
- """This test make sure that credit notes of pos orders are correctly
- linked to the original invoice."""
- self.pos_config.open_ui()
- current_session = self.pos_config.current_session_id
- order_data = {'data':
- {'amount_paid': 450,
- 'amount_tax': 0,
- 'amount_return': 0,
- 'amount_total': 450,
- '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, 0, {
- 'discount': 0,
- 'pack_lot_ids': [],
- 'price_unit': 450.0,
- 'product_id': self.product3.id,
- 'price_subtotal': 450.0,
- 'price_subtotal_incl': 450.0,
- 'tax_ids': [[6, False, []]],
- 'qty': 1,
- }]],
- 'name': 'Order 12345-123-1234',
- 'partner_id': self.partner1.id,
- 'pos_session_id': current_session.id,
- 'sequence_number': 2,
- 'statement_ids': [[0, 0, {
- 'amount': 450,
- 'name': fields.Datetime.now(),
- 'payment_method_id': self.cash_payment_method.id
- }]],
- 'uid': '12345-123-1234',
- 'user_id': self.env.uid,
- 'to_invoice': True, }
- }
- order = self.PosOrder.create_from_ui([order_data])
- order = self.PosOrder.browse(order[0]['id'])
- refund_id = order.refund()['res_id']
- refund = self.PosOrder.browse(refund_id)
- context_payment = {"active_ids": refund.ids, "active_id": refund.id}
- refund_payment = self.PosMakePayment.with_context(**context_payment).create({
- 'amount': refund.amount_total,
- 'payment_method_id': self.cash_payment_method.id
- })
- refund_payment.with_context(**context_payment).check()
- refund.action_pos_order_invoice()
- #get last invoice created
- current_session.action_pos_session_closing_control()
- invoices = self.env['account.move'].search([('move_type', '=', 'out_invoice')], order='id desc', limit=1)
- credit_notes = self.env['account.move'].search([('move_type', '=', 'out_refund')], order='id desc', limit=1)
- self.assertEqual(credit_notes.ref, "Reversal of: "+invoices.name)
- self.assertEqual(credit_notes.reversed_entry_id.id, invoices.id)
- def test_invoicing_after_closing_session(self):
- """ Test that an invoice can be created after the session is closed """
- #create customer account payment method
- self.customer_account_payment_method = self.env['pos.payment.method'].create({
- 'name': 'Customer Account',
- 'split_transactions': True,
- })
- self.product1 = self.env['product.product'].create({
- 'name': 'Product A',
- 'type': 'product',
- 'categ_id': self.env.ref('product.product_category_all').id,
- })
- self.partner1.write({'parent_id': self.env['res.partner'].create({'name': 'Parent'}).id})
- #add customer account payment method to pos config
- self.pos_config.write({
- 'payment_method_ids': [(4, self.customer_account_payment_method.id, 0)],
- })
- # change the currency of PoS config
- (self.currency_data['currency'].rate_ids | self.company.currency_id.rate_ids).unlink()
- self.env['res.currency.rate'].create({
- 'rate': 0.5,
- 'currency_id': self.currency_data['currency'].id,
- 'name': datetime.today().date(),
- })
- self.pos_config.journal_id.write({
- 'currency_id': self.currency_data['currency'].id
- })
- other_pricelist = self.env['product.pricelist'].create({
- 'name': 'Public Pricelist Other',
- 'currency_id': self.currency_data['currency'].id,
- })
- self.pos_config.write({
- 'pricelist_id': other_pricelist.id,
- 'available_pricelist_ids': [(6, 0, other_pricelist.ids)],
- })
- self.pos_config.open_ui()
- current_session = self.pos_config.current_session_id
- # create pos order
- order = self.PosOrder.create({
- 'company_id': self.env.company.id,
- 'session_id': current_session.id,
- 'partner_id': self.partner1.id,
- 'lines': [(0, 0, {
- 'name': "OL/0001",
- 'product_id': self.product1.id,
- 'price_unit': 6,
- 'discount': 0,
- 'qty': 1,
- 'tax_ids': [[6, False, []]],
- 'price_subtotal': 6,
- 'price_subtotal_incl': 6,
- })],
- 'pricelist_id': self.pos_config.pricelist_id.id,
- 'amount_paid': 6.0,
- 'amount_total': 6.0,
- 'amount_tax': 0.0,
- 'amount_return': 0.0,
- 'to_invoice': True,
- })
- #pay for the order with customer account
- payment_context = {"active_ids": order.ids, "active_id": order.id}
- order_payment = self.PosMakePayment.with_context(**payment_context).create({
- 'amount': 2.0,
- 'payment_method_id': self.cash_payment_method.id
- })
- order_payment.with_context(**payment_context).check()
- payment_context = {"active_ids": order.ids, "active_id": order.id}
- order_payment = self.PosMakePayment.with_context(**payment_context).create({
- 'amount': 4.0,
- 'payment_method_id': self.customer_account_payment_method.id
- })
- order_payment.with_context(**payment_context).check()
- # close session
- current_session.action_pos_session_closing_control()
- # create invoice
- order.action_pos_order_invoice()
- #get journal entry that does the reverse payment, it the ref must contains Reversal
- reverse_payment = self.env['account.move'].search([('ref', 'ilike', "Reversal")])
- original_payment = self.env['account.move'].search([('ref', '=', current_session.display_name)])
- original_customer_payment_entry = original_payment.line_ids.filtered(lambda l: l.account_id.account_type == 'asset_receivable')
- reverser_customer_payment_entry = reverse_payment.line_ids.filtered(lambda l: l.account_id.account_type == 'asset_receivable')
- #check that both use the same account
- self.assertEqual(len(reverser_customer_payment_entry), 2)
- self.assertTrue(order.account_move.line_ids.partner_id == self.partner1.commercial_partner_id)
- self.assertEqual(reverser_customer_payment_entry[0].balance, -4.0)
- self.assertEqual(reverser_customer_payment_entry[1].balance, -8.0)
- self.assertEqual(reverser_customer_payment_entry[0].amount_currency, -2.0)
- self.assertEqual(reverser_customer_payment_entry[1].amount_currency, -4.0)
- self.assertEqual(original_customer_payment_entry.account_id.id, reverser_customer_payment_entry.account_id.id)
- self.assertEqual(reverser_customer_payment_entry.partner_id, original_customer_payment_entry.partner_id)
- def test_order_total_subtotal_account_line_values(self):
- self.tax1 = self.env['account.tax'].create({
- 'name': 'Tax 1',
- 'amount': 10,
- 'amount_type': 'percent',
- 'type_tax_use': 'sale',
- })
- #create an account to be used as income account
- self.account1 = self.env['account.account'].create({
- 'name': 'Account 1',
- 'code': 'AC1',
- 'account_type': 'income',
- 'reconcile': True,
- })
- self.product1 = self.env['product.product'].create({
- 'name': 'Product A',
- 'type': 'product',
- 'taxes_id': [(6, 0, self.tax1.ids)],
- 'categ_id': self.env.ref('product.product_category_all').id,
- 'property_account_income_id': self.account1.id,
- })
- self.product2 = self.env['product.product'].create({
- 'name': 'Product B',
- 'type': 'product',
- 'taxes_id': [(6, 0, self.tax1.ids)],
- 'categ_id': self.env.ref('product.product_category_all').id,
- 'property_account_income_id': self.account1.id,
- })
- self.pos_config.open_ui()
- #create an order with product1
- order = self.PosOrder.create({
- 'company_id': self.env.company.id,
- 'session_id': self.pos_config.current_session_id.id,
- 'partner_id': self.partner1.id,
- 'lines': [(0, 0, {
- 'name': "OL/0001",
- 'product_id': self.product1.id,
- 'price_unit': 100,
- 'discount': 0,
- 'qty': 1,
- 'tax_ids': [[6, False, [self.tax1.id]]],
- 'price_subtotal': 100,
- 'price_subtotal_incl': 110,
- }), (0, 0, {
- 'name': "OL/0002",
- 'product_id': self.product2.id,
- 'price_unit': 100,
- 'discount': 0,
- 'qty': 1,
- 'tax_ids': [[6, False, [self.tax1.id]]],
- 'price_subtotal': 100,
- 'price_subtotal_incl': 110,
- })],
- 'pricelist_id': self.pos_config.pricelist_id.id,
- 'amount_paid': 220.0,
- 'amount_total': 220.0,
- 'amount_tax': 20.0,
- 'amount_return': 0.0,
- 'to_invoice': False,
- })
- #make payment
- payment_context = {"active_ids": order.ids, "active_id": order.id}
- order_payment = self.PosMakePayment.with_context(**payment_context).create({
- 'amount': order.amount_total,
- 'payment_method_id': self.cash_payment_method.id
- })
- order_payment.with_context(**payment_context).check()
- session_id = self.pos_config.current_session_id
- # closing the session with basic pos access
- pos_user = self.env['res.users'].create({
- 'name': "PoS user",
- 'login': "pos_user",
- 'email': "pos_user@yourcompany.com",
- 'groups_id': [(6, 0, [self.ref('base.group_user'), self.ref('point_of_sale.group_pos_user')])],
- })
- self.pos_config.current_session_id.with_user(pos_user).action_pos_session_closing_control()
- #get journal entries created
- aml = session_id.move_id.line_ids.filtered(lambda x: x.account_id == self.account1 and x.tax_ids == self.tax1)
- self.assertEqual(aml.price_total, 220)
- self.assertEqual(aml.price_subtotal, 200)
- def test_multi_exp_account_real_time(self):
- #Create a real time valuation product category
- self.real_time_categ = self.env['product.category'].create({
- 'name': 'test category',
- 'parent_id': False,
- 'property_cost_method': 'fifo',
- 'property_valuation': 'real_time',
- })
- #Create 2 accounts to be used for each product
- self.account1 = self.env['account.account'].create({
- 'name': 'Account 1',
- 'code': 'AC1',
- 'reconcile': True,
- 'account_type': 'expense',
- })
- self.account2 = self.env['account.account'].create({
- 'name': 'Account 1',
- 'code': 'AC2',
- 'reconcile': True,
- 'account_type': 'expense',
- })
- self.product_a = self.env['product.product'].create({
- 'name': 'Product A',
- 'type': 'product',
- 'categ_id': self.real_time_categ.id,
- 'property_account_expense_id': self.account1.id,
- 'property_account_income_id': self.account1.id,
- })
- self.product_b = self.env['product.product'].create({
- 'name': 'Product B',
- 'type': 'product',
- 'categ_id': self.real_time_categ.id,
- 'property_account_expense_id': self.account2.id,
- 'property_account_income_id': self.account2.id,
- })
- #Create an order with the 2 products
- self.pos_config.open_ui()
- order = self.PosOrder.create({
- 'company_id': self.env.company.id,
- 'session_id': self.pos_config.current_session_id.id,
- 'partner_id': self.partner1.id,
- 'lines': [(0, 0, {
- 'name': "OL/0001",
- 'product_id': self.product_a.id,
- 'price_unit': 100,
- 'discount': 0,
- 'qty': 1,
- 'tax_ids': [],
- 'price_subtotal': 100,
- 'price_subtotal_incl': 100,
- }), (0, 0, {
- 'name': "OL/0002",
- 'product_id': self.product_b.id,
- 'price_unit': 100,
- 'discount': 0,
- 'qty': 1,
- 'tax_ids': [],
- 'price_subtotal': 100,
- 'price_subtotal_incl': 100,
- })],
- 'pricelist_id': self.pos_config.pricelist_id.id,
- 'amount_paid': 200.0,
- 'amount_total': 200.0,
- 'amount_tax': 0.0,
- 'amount_return': 0.0,
- 'to_invoice': False,
- 'to_ship': True,
- })
- #make payment
- payment_context = {"active_ids": order.ids, "active_id": order.id}
- order_payment = self.PosMakePayment.with_context(**payment_context).create({
- 'amount': order.amount_total,
- 'payment_method_id': self.cash_payment_method.id
- })
- order_payment.with_context(**payment_context).check()
- self.pos_config.current_session_id.action_pos_session_closing_control()
- order.picking_ids._action_done()
- moves = self.env['account.move'].search([('ref', '=', f'pos_order_{order.id}')])
- self.assertEqual(len(moves), 2)
|