mirror of
https://github.com/bringout/oca-ocb-sale.git
synced 2026-04-27 01:52:02 +02:00
19.0 vanilla
This commit is contained in:
parent
79f83631d5
commit
73afc09215
6267 changed files with 1534193 additions and 1130106 deletions
|
|
@ -1,13 +1,16 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from . import common_setup_methods
|
||||
from . import test_point_of_sale_flow
|
||||
from . import test_frontend
|
||||
from . import test_performances
|
||||
from . import test_point_of_sale_ui
|
||||
from . import test_anglo_saxon
|
||||
from . import test_continental
|
||||
from . import test_point_of_sale
|
||||
from . import test_pos_capture
|
||||
from . import test_pos_controller
|
||||
from . import test_pos_invoice_consolidation
|
||||
from . import test_pos_cash_rounding
|
||||
from . import test_pos_setup
|
||||
from . import test_pos_simple_orders
|
||||
from . import test_pos_simple_invoiced_orders
|
||||
|
|
@ -18,6 +21,8 @@ from . import test_pos_multiple_receivable_accounts
|
|||
from . import test_pos_other_currency_config
|
||||
from . import test_pos_with_fiscal_position
|
||||
from . import test_pos_stock_account
|
||||
from . import test_js
|
||||
from . import test_report_pos_order
|
||||
from . import test_report_session
|
||||
from . import test_res_config_settings
|
||||
from . import test_pos_product_variants
|
||||
from . import test_generic_localization
|
||||
|
|
|
|||
|
|
@ -1,134 +1,363 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
import logging
|
||||
|
||||
from random import randint
|
||||
from datetime import datetime
|
||||
|
||||
from odoo import fields, tools
|
||||
from odoo.fields import Command
|
||||
from odoo.tests import Form
|
||||
from odoo.addons.stock_account.tests.test_anglo_saxon_valuation_reconciliation_common import ValuationReconciliationTestCommon
|
||||
from odoo.tests.common import Form
|
||||
from odoo.tests import tagged
|
||||
|
||||
import logging
|
||||
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
class TestPointOfSaleCommon(ValuationReconciliationTestCommon):
|
||||
def archive_products(env):
|
||||
# Archive all existing product to avoid noise during the tours
|
||||
all_pos_product = env['product.template'].search([('available_in_pos', '=', True)])
|
||||
tip = env.ref('point_of_sale.product_product_tip').product_tmpl_id
|
||||
(all_pos_product - tip)._write({'active': False})
|
||||
|
||||
|
||||
class CommonPosTest(ValuationReconciliationTestCommon):
|
||||
@classmethod
|
||||
def setUpClass(cls, chart_template_ref=None):
|
||||
super().setUpClass(chart_template_ref=chart_template_ref)
|
||||
def setUpClass(self):
|
||||
super().setUpClass()
|
||||
archive_products(self.env)
|
||||
|
||||
cls.company_data['company'].write({
|
||||
'point_of_sale_update_stock_quantities': 'real',
|
||||
self.env.user.group_ids += self.env.ref('point_of_sale.group_pos_manager')
|
||||
self.env.ref('base.EUR').active = True
|
||||
self.env.ref('base.USD').active = True
|
||||
|
||||
self.create_res_partners(self)
|
||||
self.create_account_cash_rounding(self)
|
||||
self.create_pos_categories(self)
|
||||
self.create_account_taxes(self)
|
||||
self.create_product_templates(self)
|
||||
self.create_payment_methods(self)
|
||||
self.create_pos_configs(self)
|
||||
|
||||
def create_pos_configs(self):
|
||||
sale_journal_eur = 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,
|
||||
})
|
||||
self.pricelist_eur = self.env['product.pricelist'].create({
|
||||
'name': 'Test EUR Pricelist',
|
||||
'currency_id': self.env.ref('base.EUR').id
|
||||
})
|
||||
self.pos_config_eur = self.env['pos.config'].create({
|
||||
'name': 'PoS Config EUR',
|
||||
'journal_id': sale_journal_eur.id,
|
||||
'use_pricelist': True,
|
||||
'available_pricelist_ids': [(6, 0, self.pricelist_eur.ids)],
|
||||
'pricelist_id': self.pricelist_eur.id,
|
||||
'payment_method_ids': [(6, 0, self.bank_payment_method.ids)]
|
||||
})
|
||||
self.pos_config_usd = self.env['pos.config'].create({
|
||||
'name': 'PoS Config USD',
|
||||
'journal_id': self.company_data['default_journal_sale'].id,
|
||||
'invoice_journal_id': self.company_data['default_journal_sale'].id,
|
||||
'payment_method_ids': [
|
||||
(4, self.credit_payment_method.id),
|
||||
(4, self.bank_payment_method.id),
|
||||
(4, self.cash_payment_method.id),
|
||||
]
|
||||
})
|
||||
|
||||
cls.AccountBankStatement = cls.env['account.bank.statement']
|
||||
cls.AccountBankStatementLine = cls.env['account.bank.statement.line']
|
||||
cls.PosMakePayment = cls.env['pos.make.payment']
|
||||
cls.PosOrder = cls.env['pos.order']
|
||||
cls.PosSession = cls.env['pos.session']
|
||||
cls.company = cls.company_data['company']
|
||||
cls.product3 = cls.env['product.product'].create({
|
||||
'name': 'Product 3',
|
||||
'list_price': 450,
|
||||
def create_res_partners(self):
|
||||
self.partner_mobt = self.env['res.partner'].create({
|
||||
'name': 'MOBT',
|
||||
})
|
||||
cls.product4 = cls.env['product.product'].create({
|
||||
'name': 'Product 4',
|
||||
'list_price': 750,
|
||||
self.partner_adgu = self.env['res.partner'].create({
|
||||
'name': 'ADGU',
|
||||
})
|
||||
cls.partner1 = cls.env['res.partner'].create({'name': 'Partner 1'})
|
||||
cls.partner4 = cls.env['res.partner'].create({'name': 'Partner 4'})
|
||||
cls.pos_config = cls.env['pos.config'].create({
|
||||
'name': 'Main',
|
||||
'journal_id': cls.company_data['default_journal_sale'].id,
|
||||
'invoice_journal_id': cls.company_data['default_journal_sale'].id,
|
||||
self.partner_lowe = self.env['res.partner'].create({
|
||||
'name': 'LOWE',
|
||||
})
|
||||
cls.led_lamp = cls.env['product.product'].create({
|
||||
'name': 'LED Lamp',
|
||||
'available_in_pos': True,
|
||||
'list_price': 0.90,
|
||||
self.partner_jcb = self.env['res.partner'].create({
|
||||
'name': 'JCB',
|
||||
})
|
||||
cls.whiteboard_pen = cls.env['product.product'].create({
|
||||
'name': 'Whiteboard Pen',
|
||||
'available_in_pos': True,
|
||||
'list_price': 1.20,
|
||||
self.partner_moda = self.env['res.partner'].create({
|
||||
'name': 'MODA',
|
||||
})
|
||||
cls.newspaper_rack = cls.env['product.product'].create({
|
||||
'name': 'Newspaper Rack',
|
||||
'available_in_pos': True,
|
||||
'list_price': 1.28,
|
||||
self.partner_stva = self.env['res.partner'].create({
|
||||
'name': 'STVA',
|
||||
})
|
||||
cls.cash_payment_method = cls.env['pos.payment.method'].create({
|
||||
self.partner_manv = self.env['res.partner'].create({
|
||||
'name': 'MANV',
|
||||
})
|
||||
self.partner_vlst = self.env['res.partner'].create({
|
||||
'name': 'VLST',
|
||||
})
|
||||
|
||||
def create_account_cash_rounding(self):
|
||||
self.account_cash_rounding_down = self.env['account.cash.rounding'].create({
|
||||
'name': 'Rounding down',
|
||||
'rounding': 0.05,
|
||||
'rounding_method': 'DOWN',
|
||||
'profit_account_id': self.company_data['default_account_revenue'].id,
|
||||
'loss_account_id': self.company_data['default_account_expense'].id,
|
||||
})
|
||||
self.account_cash_rounding_up = self.env['account.cash.rounding'].create({
|
||||
'name': 'Rounding up',
|
||||
'rounding': 0.05,
|
||||
'rounding_method': 'UP',
|
||||
'profit_account_id': self.company_data['default_account_revenue'].id,
|
||||
'loss_account_id': self.company_data['default_account_expense'].id,
|
||||
})
|
||||
self.account_cash_rounding_half = self.env['account.cash.rounding'].create({
|
||||
'name': 'Rounding half',
|
||||
'rounding': 0.05,
|
||||
'profit_account_id': self.company_data['default_account_revenue'].id,
|
||||
'loss_account_id': self.company_data['default_account_expense'].id,
|
||||
})
|
||||
|
||||
def create_payment_methods(self):
|
||||
self.cash_payment_method = self.env['pos.payment.method'].create({
|
||||
'name': 'Cash',
|
||||
'receivable_account_id': cls.company_data['default_account_receivable'].id,
|
||||
'journal_id': cls.company_data['default_journal_cash'].id,
|
||||
'company_id': cls.env.company.id,
|
||||
'receivable_account_id': self.company_data['default_account_receivable'].id,
|
||||
'journal_id': self.company_data['default_journal_cash'].id,
|
||||
})
|
||||
cls.bank_payment_method = cls.env['pos.payment.method'].create({
|
||||
self.bank_payment_method = self.env['pos.payment.method'].create({
|
||||
'name': 'Bank',
|
||||
'journal_id': cls.company_data['default_journal_bank'].id,
|
||||
'receivable_account_id': cls.company_data['default_account_receivable'].id,
|
||||
'company_id': cls.env.company.id,
|
||||
'journal_id': self.company_data['default_journal_bank'].id,
|
||||
'receivable_account_id': self.company_data['default_account_receivable'].id,
|
||||
})
|
||||
cls.credit_payment_method = cls.env['pos.payment.method'].create({
|
||||
self.credit_payment_method = self.env['pos.payment.method'].create({
|
||||
'name': 'Credit',
|
||||
'receivable_account_id': cls.company_data['default_account_receivable'].id,
|
||||
'receivable_account_id': self.company_data['default_account_receivable'].id,
|
||||
'split_transactions': True,
|
||||
'company_id': cls.env.company.id,
|
||||
})
|
||||
cls.pos_config.write({'payment_method_ids': [(4, cls.credit_payment_method.id), (4, cls.bank_payment_method.id), (4, cls.cash_payment_method.id)]})
|
||||
|
||||
# Create POS journal
|
||||
cls.pos_config.journal_id = cls.env['account.journal'].create({
|
||||
'type': 'general',
|
||||
'name': 'Point of Sale - Test',
|
||||
'code': 'POSS - Test',
|
||||
'company_id': cls.env.company.id,
|
||||
'sequence': 20
|
||||
})
|
||||
|
||||
# create a VAT tax of 10%, included in the public price
|
||||
Tax = cls.env['account.tax']
|
||||
account_tax_10_incl = Tax.create({
|
||||
'name': 'VAT 10 perc Incl',
|
||||
'amount_type': 'percent',
|
||||
'amount': 10.0,
|
||||
'price_include': True,
|
||||
def create_pos_categories(self):
|
||||
self.cat_no_tax = self.env['pos.category'].create({
|
||||
'name': 'No tax',
|
||||
'sequence': 0,
|
||||
})
|
||||
self.cat_tax_five_incl = self.env['pos.category'].create({
|
||||
'name': 'Tax five incl',
|
||||
'sequence': 1,
|
||||
})
|
||||
self.cat_tax_ten_incl = self.env['pos.category'].create({
|
||||
'name': 'Tax ten incl',
|
||||
'sequence': 2,
|
||||
})
|
||||
self.cat_tax_fiften_incl = self.env['pos.category'].create({
|
||||
'name': 'Tax fifteen incl',
|
||||
'sequence': 3,
|
||||
})
|
||||
self.cat_tax_five_excl = self.env['pos.category'].create({
|
||||
'name': 'Tax five excl',
|
||||
'sequence': 4,
|
||||
})
|
||||
self.cat_tax_ten_excl = self.env['pos.category'].create({
|
||||
'name': 'Tax ten excl',
|
||||
'sequence': 5,
|
||||
})
|
||||
self.cat_tax_fiften_excl = self.env['pos.category'].create({
|
||||
'name': 'Tax fifteen excl',
|
||||
'sequence': 6,
|
||||
})
|
||||
|
||||
# assign this 10 percent tax on the [PCSC234] PC Assemble SC234 product
|
||||
# as a sale tax
|
||||
cls.product3.taxes_id = [(6, 0, [account_tax_10_incl.id])]
|
||||
|
||||
# create a VAT tax of 5%, which is added to the public price
|
||||
account_tax_05_incl = Tax.create({
|
||||
'name': 'VAT 5 perc Incl',
|
||||
'amount_type': 'percent',
|
||||
'amount': 5.0,
|
||||
'price_include': False,
|
||||
def create_account_taxes(self):
|
||||
self.tax_five_incl = self.env['account.tax'].create({
|
||||
'name': 'Tax five incl',
|
||||
'amount': 5,
|
||||
'price_include_override': 'tax_included',
|
||||
})
|
||||
self.tax_ten_incl = self.env['account.tax'].create({
|
||||
'name': 'Tax ten incl',
|
||||
'amount': 10,
|
||||
'price_include_override': 'tax_included',
|
||||
})
|
||||
self.tax_fiften_incl = self.env['account.tax'].create({
|
||||
'name': 'Tax fifteen incl',
|
||||
'amount': 15,
|
||||
'price_include_override': 'tax_included',
|
||||
})
|
||||
self.tax_five_excl = self.env['account.tax'].create({
|
||||
'name': 'Tax five excl',
|
||||
'amount': 5,
|
||||
})
|
||||
self.tax_ten_excl = self.env['account.tax'].create({
|
||||
'name': 'Tax ten excl',
|
||||
'amount': 10,
|
||||
})
|
||||
self.tax_fiften_excl = self.env['account.tax'].create({
|
||||
'name': 'Tax fifteen excl',
|
||||
'amount': 15,
|
||||
})
|
||||
|
||||
# create a second VAT tax of 5% but this time for a child company, to
|
||||
# ensure that only product taxes of the current session's company are considered
|
||||
#(this tax should be ignore when computing order's taxes in following tests)
|
||||
account_tax_05_incl_chicago = Tax.create({
|
||||
'name': 'VAT 05 perc Excl (US)',
|
||||
'amount_type': 'percent',
|
||||
'amount': 5.0,
|
||||
'price_include': False,
|
||||
'company_id': cls.company_data_2['company'].id,
|
||||
def create_product_templates(self):
|
||||
self.ten_dollars_no_tax = self.env['product.template'].create({
|
||||
'available_in_pos': True,
|
||||
'name': 'Ten dollars no tax',
|
||||
'list_price': 10.0,
|
||||
'pos_categ_ids': [(6, 0, [self.cat_no_tax.id])],
|
||||
'taxes_id': [(5, 0)],
|
||||
})
|
||||
self.twenty_dollars_no_tax = self.env['product.template'].create({
|
||||
'available_in_pos': True,
|
||||
'name': 'Twenty dollars no tax',
|
||||
'list_price': 20.0,
|
||||
'pos_categ_ids': [(6, 0, [self.cat_no_tax.id])],
|
||||
'taxes_id': [(5, 0)],
|
||||
})
|
||||
self.ten_dollars_with_5_incl = self.env['product.template'].create({
|
||||
'available_in_pos': True,
|
||||
'name': 'Ten dollars with 5 included',
|
||||
'list_price': 10.0,
|
||||
'taxes_id': [(6, 0, [self.tax_five_incl.id])],
|
||||
'pos_categ_ids': [(6, 0, [self.cat_tax_five_incl.id])],
|
||||
})
|
||||
self.twenty_dollars_with_5_incl = self.env['product.template'].create({
|
||||
'available_in_pos': True,
|
||||
'name': 'Twenty dollars with 5 included',
|
||||
'list_price': 20.0,
|
||||
'taxes_id': [(6, 0, [self.tax_five_incl.id])],
|
||||
'pos_categ_ids': [(6, 0, [self.cat_tax_five_incl.id])],
|
||||
})
|
||||
self.ten_dollars_with_10_incl = self.env['product.template'].create({
|
||||
'available_in_pos': True,
|
||||
'name': 'Ten dollars with 10 included',
|
||||
'list_price': 10.0,
|
||||
'taxes_id': [(6, 0, [self.tax_ten_incl.id])],
|
||||
'pos_categ_ids': [(6, 0, [self.cat_tax_ten_incl.id])],
|
||||
})
|
||||
self.twenty_dollars_with_10_incl = self.env['product.template'].create({
|
||||
'available_in_pos': True,
|
||||
'name': 'Twenty dollars with 10 included',
|
||||
'list_price': 20.0,
|
||||
'taxes_id': [(6, 0, [self.tax_ten_incl.id])],
|
||||
'pos_categ_ids': [(6, 0, [self.cat_tax_ten_incl.id])],
|
||||
})
|
||||
self.ten_dollars_with_15_incl = self.env['product.template'].create({
|
||||
'available_in_pos': True,
|
||||
'name': 'Ten dollars with 15 included',
|
||||
'list_price': 10.0,
|
||||
'taxes_id': [(6, 0, [self.tax_fiften_incl.id])],
|
||||
'pos_categ_ids': [(6, 0, [self.cat_tax_fiften_incl.id])],
|
||||
})
|
||||
self.twenty_dollars_with_15_incl = self.env['product.template'].create({
|
||||
'available_in_pos': True,
|
||||
'name': 'Twenty dollars with 15 included',
|
||||
'list_price': 20.0,
|
||||
'taxes_id': [(6, 0, [self.tax_fiften_incl.id])],
|
||||
'pos_categ_ids': [(6, 0, [self.cat_tax_fiften_incl.id])],
|
||||
})
|
||||
self.ten_dollars_with_5_excl = self.env['product.template'].create({
|
||||
'available_in_pos': True,
|
||||
'name': 'Ten dollars with 5 excluded',
|
||||
'list_price': 10.0,
|
||||
'taxes_id': [(6, 0, [self.tax_five_excl.id])],
|
||||
'pos_categ_ids': [(6, 0, [self.cat_tax_five_excl.id])],
|
||||
})
|
||||
self.twenty_dollars_with_5_excl = self.env['product.template'].create({
|
||||
'available_in_pos': True,
|
||||
'name': 'Twenty dollars with 5 excluded',
|
||||
'list_price': 20.0,
|
||||
'taxes_id': [(6, 0, [self.tax_five_excl.id])],
|
||||
'pos_categ_ids': [(6, 0, [self.cat_tax_five_excl.id])],
|
||||
})
|
||||
self.ten_dollars_with_10_excl = self.env['product.template'].create({
|
||||
'available_in_pos': True,
|
||||
'name': 'Ten dollars with 10 excluded',
|
||||
'list_price': 10.0,
|
||||
'taxes_id': [(6, 0, [self.tax_ten_excl.id])],
|
||||
'pos_categ_ids': [(6, 0, [self.cat_tax_ten_excl.id])],
|
||||
})
|
||||
self.twenty_dollars_with_10_excl = self.env['product.template'].create({
|
||||
'available_in_pos': True,
|
||||
'name': 'Twenty dollars with 10 excluded',
|
||||
'list_price': 20.0,
|
||||
'taxes_id': [(6, 0, [self.tax_ten_excl.id])],
|
||||
'pos_categ_ids': [(6, 0, [self.cat_tax_ten_excl.id])],
|
||||
})
|
||||
self.ten_dollars_with_15_excl = self.env['product.template'].create({
|
||||
'available_in_pos': True,
|
||||
'name': 'Ten dollars with 15 excluded',
|
||||
'list_price': 10.0,
|
||||
'taxes_id': [(6, 0, [self.tax_fiften_excl.id])],
|
||||
'pos_categ_ids': [(6, 0, [self.cat_tax_fiften_excl.id])],
|
||||
})
|
||||
self.twenty_dollars_with_15_excl = self.env['product.template'].create({
|
||||
'available_in_pos': True,
|
||||
'name': 'Twenty dollars with 15 excluded',
|
||||
'list_price': 20.0,
|
||||
'taxes_id': [(6, 0, [self.tax_fiften_excl.id])],
|
||||
'pos_categ_ids': [(6, 0, [self.cat_tax_fiften_excl.id])],
|
||||
})
|
||||
|
||||
cls.product4.company_id = False
|
||||
# I assign those 5 percent taxes on the PCSC349 product as a sale taxes
|
||||
cls.product4.write(
|
||||
{'taxes_id': [(6, 0, [account_tax_05_incl.id, account_tax_05_incl_chicago.id])]})
|
||||
def create_backend_pos_order(self, data):
|
||||
pos_config = data.get('pos_config', self.pos_config_usd)
|
||||
order_data = data.get('order_data', {})
|
||||
line_product_ids = [line_data['product_id'] for line_data in data.get('line_data', [])]
|
||||
product_by_id = {p.id: p for p in self.env['product.product'].browse(line_product_ids)}
|
||||
refund = False
|
||||
|
||||
# Set account_id in the generated repartition lines. Automatically, nothing is set.
|
||||
invoice_rep_lines = (account_tax_05_incl | account_tax_10_incl).mapped('invoice_repartition_line_ids')
|
||||
refund_rep_lines = (account_tax_05_incl | account_tax_10_incl).mapped('refund_repartition_line_ids')
|
||||
if not pos_config.current_session_id:
|
||||
pos_config.open_ui()
|
||||
|
||||
# Expense account, should just be something else than receivable/payable
|
||||
(invoice_rep_lines | refund_rep_lines).write({'account_id': cls.company_data['default_account_tax_sale'].id})
|
||||
order = self.env['pos.order'].create({
|
||||
'amount_total': 0,
|
||||
'amount_paid': 0,
|
||||
'amount_tax': 0,
|
||||
'amount_return': 0,
|
||||
'date_order': fields.Datetime.to_string(fields.Datetime.now()),
|
||||
'company_id': self.env.company.id,
|
||||
'session_id': pos_config.current_session_id.id,
|
||||
'lines': [
|
||||
Command.create({
|
||||
'price_unit': product_by_id[line_data['product_id']].lst_price,
|
||||
'price_subtotal': product_by_id[line_data['product_id']].lst_price,
|
||||
'tax_ids': [(6, 0, product_by_id[line_data['product_id']].taxes_id.ids)],
|
||||
'price_subtotal_incl': 0,
|
||||
**line_data,
|
||||
}) for line_data in data.get('line_data', [])
|
||||
],
|
||||
**order_data,
|
||||
})
|
||||
|
||||
# Re-trigger prices computation
|
||||
order.lines._onchange_amount_line_all()
|
||||
order._compute_prices()
|
||||
|
||||
if data.get('payment_data'):
|
||||
payment_context = {"active_ids": order.ids, "active_id": order.id}
|
||||
for payment in data['payment_data']:
|
||||
make_payment = {'payment_method_id': payment['payment_method_id']}
|
||||
if payment.get('amount'):
|
||||
make_payment['amount'] = payment['amount']
|
||||
order_payment = self.env['pos.make.payment'].with_context(**payment_context).create(make_payment)
|
||||
order_payment.with_context(**payment_context).check()
|
||||
|
||||
if data.get('refund_data'):
|
||||
refund_action = order.refund()
|
||||
refund = self.env['pos.order'].browse(refund_action['res_id'])
|
||||
payment_context = {"active_ids": refund.ids, "active_id": refund.id}
|
||||
|
||||
if data.get('order_data') and data['order_data'].get('to_invoice', False):
|
||||
refund.to_invoice = True
|
||||
|
||||
for refund_data in data['refund_data']:
|
||||
make_refund = {'payment_method_id': refund_data['payment_method_id']}
|
||||
if refund_data.get('amount'):
|
||||
make_refund['amount'] = refund_data['amount']
|
||||
refund_payment = self.env['pos.make.payment'].with_context(**payment_context).create(make_refund)
|
||||
refund_payment.with_context(**payment_context).check()
|
||||
|
||||
return order, refund
|
||||
|
||||
def compute_tax(self, product, price, qty=1, taxes=None, pos_config=None):
|
||||
config = pos_config or self.pos_config_usd
|
||||
if not taxes:
|
||||
taxes = product.taxes_id.filtered(lambda t: t.company_id.id == self.env.company.id)
|
||||
currency = config.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'])
|
||||
|
||||
|
||||
class TestPoSCommon(ValuationReconciliationTestCommon):
|
||||
|
|
@ -140,8 +369,9 @@ class TestPoSCommon(ValuationReconciliationTestCommon):
|
|||
"""
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls, chart_template_ref=None):
|
||||
super().setUpClass(chart_template_ref=chart_template_ref)
|
||||
def setUpClass(cls):
|
||||
super().setUpClass()
|
||||
cls.env.user.group_ids |= cls.env.ref('point_of_sale.group_pos_manager')
|
||||
|
||||
cls.company_data['company'].write({
|
||||
'point_of_sale_update_stock_quantities': 'real',
|
||||
|
|
@ -152,14 +382,7 @@ class TestPoSCommon(ValuationReconciliationTestCommon):
|
|||
})
|
||||
|
||||
# Set basic defaults
|
||||
cls.company = cls.company_data['company']
|
||||
cls.pos_sale_journal = cls.env['account.journal'].create({
|
||||
'type': 'general',
|
||||
'name': 'Point of Sale Test',
|
||||
'code': 'POSS',
|
||||
'company_id': cls.company.id,
|
||||
'sequence': 20
|
||||
})
|
||||
cls.account_tax_return_journal = cls.company_data['default_tax_return_journal']
|
||||
cls.sales_account = cls.company_data['default_account_revenue']
|
||||
cls.invoice_journal = cls.company_data['default_journal_sale']
|
||||
cls.receivable_account = cls.company_data['default_account_receivable']
|
||||
|
|
@ -173,7 +396,7 @@ class TestPoSCommon(ValuationReconciliationTestCommon):
|
|||
cls.pos_receivable_account = cls.company.account_default_pos_receivable_account_id
|
||||
cls.pos_receivable_cash = cls.copy_account(cls.company.account_default_pos_receivable_account_id, {'name': 'POS Receivable Cash'})
|
||||
cls.pos_receivable_bank = cls.copy_account(cls.company.account_default_pos_receivable_account_id, {'name': 'POS Receivable Bank'})
|
||||
cls.outstanding_bank = cls.copy_account(cls.company.account_journal_payment_debit_account_id, {'name': 'Outstanding Bank'})
|
||||
cls.outstanding_bank = cls.copy_account(cls.inbound_payment_method_line.payment_account_id, {'name': 'Outstanding Bank'})
|
||||
cls.c1_receivable = cls.copy_account(cls.receivable_account, {'name': 'Customer 1 Receivable'})
|
||||
cls.other_receivable_account = cls.env['account.account'].create({
|
||||
'name': 'Other Receivable',
|
||||
|
|
@ -187,7 +410,7 @@ class TestPoSCommon(ValuationReconciliationTestCommon):
|
|||
cls.company_currency = cls.company.currency_id
|
||||
# other_currency is a currency different from the company_currency
|
||||
# sometimes company_currency is different from USD, so handle appropriately.
|
||||
cls.other_currency = cls.currency_data['currency']
|
||||
cls.other_currency = cls.setup_other_currency("EUR", rounding=0.001)
|
||||
|
||||
cls.currency_pricelist = cls.env['product.pricelist'].create({
|
||||
'name': 'Public Pricelist',
|
||||
|
|
@ -203,18 +426,18 @@ class TestPoSCommon(ValuationReconciliationTestCommon):
|
|||
|
||||
# Set product categories
|
||||
# categ_basic
|
||||
# - just the plain 'product.product_category_all'
|
||||
# - just the plain 'product.product_category_services'
|
||||
# categ_anglo
|
||||
# - product category with fifo and real_time valuations
|
||||
# - used for checking anglo saxon accounting behavior
|
||||
cls.categ_basic = cls.env.ref('product.product_category_all')
|
||||
cls.categ_basic = cls.env.ref('product.product_category_services')
|
||||
cls.env.company.anglo_saxon_accounting = True
|
||||
cls.categ_anglo = cls._create_categ_anglo()
|
||||
|
||||
# other basics
|
||||
cls.sale_account = cls.categ_basic.property_account_income_categ_id
|
||||
cls.sale_account = cls.company.income_account_id
|
||||
cls.other_sale_account = cls.env['account.account'].search([
|
||||
('company_id', '=', cls.company.id),
|
||||
('company_ids', '=', cls.company.id),
|
||||
('account_type', '=', 'income'),
|
||||
('id', '!=', cls.sale_account.id)
|
||||
], limit=1)
|
||||
|
|
@ -243,16 +466,20 @@ class TestPoSCommon(ValuationReconciliationTestCommon):
|
|||
config = cls.env['pos.config'].create({
|
||||
'name': 'PoS Shop Test',
|
||||
'invoice_journal_id': cls.invoice_journal.id,
|
||||
'journal_id': cls.pos_sale_journal.id,
|
||||
'available_pricelist_ids': cls.currency_pricelist.ids,
|
||||
'pricelist_id': cls.currency_pricelist.id,
|
||||
})
|
||||
cls.cash_pm1 = cls.env['pos.payment.method'].create({
|
||||
'name': 'Cash',
|
||||
'journal_id': cls.company_data['default_journal_cash'].id,
|
||||
'receivable_account_id': cls.pos_receivable_cash.id,
|
||||
'company_id': cls.env.company.id,
|
||||
})
|
||||
cls.company_data['default_journal_cash'].pos_payment_method_ids.unlink()
|
||||
cls.cash_pm1 = config.payment_method_ids.filtered(lambda c: c.journal_id.type == 'cash')
|
||||
if cls.cash_pm1:
|
||||
cls.cash_pm1.write({'receivable_account_id': cls.pos_receivable_cash.id})
|
||||
else:
|
||||
cls.cash_pm1 = cls.env['pos.payment.method'].create({
|
||||
'name': 'Cash',
|
||||
'journal_id': cls.company_data['default_journal_cash'].id,
|
||||
'receivable_account_id': cls.pos_receivable_cash.id,
|
||||
'company_id': cls.env.company.id,
|
||||
})
|
||||
cls.bank_pm1 = cls.env['pos.payment.method'].create({
|
||||
'name': 'Bank',
|
||||
'journal_id': cls.company_data['default_journal_bank'].id,
|
||||
|
|
@ -263,6 +490,11 @@ class TestPoSCommon(ValuationReconciliationTestCommon):
|
|||
cls.cash_split_pm1 = cls.cash_pm1.copy(default={
|
||||
'name': 'Split (Cash) PM',
|
||||
'split_transactions': True,
|
||||
'journal_id': cls.env['account.journal'].create({
|
||||
'name': "Cash",
|
||||
'code': "CSH %s" % config.id,
|
||||
'type': 'cash',
|
||||
}).id
|
||||
})
|
||||
cls.bank_split_pm1 = cls.bank_pm1.copy(default={
|
||||
'name': 'Split (Bank) PM',
|
||||
|
|
@ -346,8 +578,7 @@ class TestPoSCommon(ValuationReconciliationTestCommon):
|
|||
'parent_id': False,
|
||||
'property_cost_method': 'fifo',
|
||||
'property_valuation': 'real_time',
|
||||
'property_stock_account_input_categ_id': cls.company_data['default_account_stock_in'].id,
|
||||
'property_stock_account_output_categ_id': cls.company_data['default_account_stock_out'].id,
|
||||
'property_stock_valuation_account_id': cls.company_data['default_account_stock_valuation'].copy().id
|
||||
})
|
||||
|
||||
@classmethod
|
||||
|
|
@ -370,11 +601,11 @@ class TestPoSCommon(ValuationReconciliationTestCommon):
|
|||
cls.tax_tag_refund_base = create_tag('Refund Base tag')
|
||||
cls.tax_tag_refund_tax = create_tag('Refund Tax tag')
|
||||
|
||||
def create_tax(percentage, price_include=False, include_base_amount=False):
|
||||
def create_tax(percentage, price_include_override='tax_excluded', include_base_amount=False):
|
||||
return cls.env['account.tax'].create({
|
||||
'name': f'Tax {percentage}%',
|
||||
'amount': percentage,
|
||||
'price_include': price_include,
|
||||
'price_include_override': price_include_override,
|
||||
'amount_type': 'percent',
|
||||
'include_base_amount': include_base_amount,
|
||||
'invoice_repartition_line_ids': [
|
||||
|
|
@ -400,12 +631,13 @@ class TestPoSCommon(ValuationReconciliationTestCommon):
|
|||
}),
|
||||
],
|
||||
})
|
||||
def create_tax_fixed(amount, price_include=False):
|
||||
|
||||
def create_tax_fixed(amount, price_include_override='tax_excluded', include_base_amount=False):
|
||||
return cls.env['account.tax'].create({
|
||||
'name': f'Tax fixed amount {amount}',
|
||||
'amount': amount,
|
||||
'price_include': price_include,
|
||||
'include_base_amount': price_include,
|
||||
'price_include_override': price_include_override,
|
||||
'include_base_amount': include_base_amount,
|
||||
'amount_type': 'fixed',
|
||||
'invoice_repartition_line_ids': [
|
||||
(0, 0, {
|
||||
|
|
@ -431,13 +663,13 @@ class TestPoSCommon(ValuationReconciliationTestCommon):
|
|||
],
|
||||
})
|
||||
|
||||
tax_fixed006 = create_tax_fixed(0.06, price_include=True)
|
||||
tax_fixed012 = create_tax_fixed(0.12, price_include=True)
|
||||
tax7 = create_tax(7, price_include=False)
|
||||
tax7base = create_tax(7, price_include=False, include_base_amount=True)
|
||||
tax10nobase = create_tax(10)
|
||||
tax10 = create_tax(10, price_include=True)
|
||||
tax21 = create_tax(21, price_include=True)
|
||||
tax_fixed006 = create_tax_fixed(0.06, price_include_override='tax_included', include_base_amount=True)
|
||||
tax_fixed012 = create_tax_fixed(0.12, price_include_override='tax_included', include_base_amount=True)
|
||||
tax7 = create_tax(7, price_include_override='tax_excluded')
|
||||
tax8 = create_tax(8, include_base_amount=True)
|
||||
tax9 = create_tax(9)
|
||||
tax10 = create_tax(10, price_include_override='tax_included')
|
||||
tax21 = create_tax(21, price_include_override='tax_included')
|
||||
|
||||
|
||||
tax_group_7_10 = tax7.copy()
|
||||
|
|
@ -449,8 +681,8 @@ class TestPoSCommon(ValuationReconciliationTestCommon):
|
|||
|
||||
return {
|
||||
'tax7': tax7,
|
||||
'tax7base': tax7base,
|
||||
'tax10nobase': tax10nobase,
|
||||
'tax8': tax8,
|
||||
'tax9': tax9,
|
||||
'tax10': tax10,
|
||||
'tax21': tax21,
|
||||
'tax_fixed006': tax_fixed006,
|
||||
|
|
@ -465,7 +697,7 @@ class TestPoSCommon(ValuationReconciliationTestCommon):
|
|||
def create_random_uid(self):
|
||||
return ('%05d-%03d-%04d' % (randint(1, 99999), randint(1, 999), randint(1, 9999)))
|
||||
|
||||
def create_ui_order_data(self, pos_order_lines_ui_args, customer=False, is_invoiced=False, payments=None, uid=None):
|
||||
def create_ui_order_data(self, pos_order_lines_ui_args, pos_order_ui_args={}, customer=False, is_invoiced=False, payments=None, uuid=None):
|
||||
""" Mocks the order_data generated by the pos ui.
|
||||
|
||||
This is useful in making orders in an open pos session without making tours.
|
||||
|
|
@ -487,9 +719,21 @@ class TestPoSCommon(ValuationReconciliationTestCommon):
|
|||
default_fiscal_position = self.config.default_fiscal_position_id
|
||||
fiscal_position = customer.property_account_position_id if customer else default_fiscal_position
|
||||
|
||||
def create_order_line(product, quantity, discount=0.0):
|
||||
def normalize_order_line_param(param):
|
||||
if isinstance(param, dict):
|
||||
return param
|
||||
|
||||
assert len(param) >= 2
|
||||
return {
|
||||
'product': param[0],
|
||||
'quantity': param[1],
|
||||
'discount': 0.0 if len(param) == 2 else param[2],
|
||||
}
|
||||
|
||||
def create_order_line(product, quantity, **kwargs):
|
||||
price_unit = self.pricelist._get_product_price(product, quantity)
|
||||
tax_ids = fiscal_position.map_tax(product.taxes_id)
|
||||
tax_ids = fiscal_position.map_tax(product.taxes_id.filtered_domain(self.env['account.tax']._check_company_domain(self.env.company)))
|
||||
discount = kwargs.get('discount', 0.0)
|
||||
price_unit_after_discount = price_unit * (1 - discount / 100.0)
|
||||
tax_values = (
|
||||
tax_ids.compute_all(price_unit_after_discount, self.currency, quantity)
|
||||
|
|
@ -500,7 +744,6 @@ class TestPoSCommon(ValuationReconciliationTestCommon):
|
|||
}
|
||||
)
|
||||
return (0, 0, {
|
||||
'discount': discount,
|
||||
'id': randint(1, 1000000),
|
||||
'pack_lot_ids': [],
|
||||
'price_unit': price_unit,
|
||||
|
|
@ -508,29 +751,29 @@ class TestPoSCommon(ValuationReconciliationTestCommon):
|
|||
'price_subtotal': tax_values['total_excluded'],
|
||||
'price_subtotal_incl': tax_values['total_included'],
|
||||
'qty': quantity,
|
||||
'tax_ids': [(6, 0, tax_ids.ids)]
|
||||
'tax_ids': [(6, 0, tax_ids.ids)],
|
||||
**kwargs
|
||||
})
|
||||
|
||||
def create_payment(payment_method, amount):
|
||||
return (0, 0, {
|
||||
'amount': amount,
|
||||
'name': fields.Datetime.to_string(fields.Datetime.now()),
|
||||
'name': fields.Datetime.now(),
|
||||
'payment_method_id': payment_method.id,
|
||||
})
|
||||
|
||||
uid = uid or self.create_random_uid()
|
||||
uuid = uuid or self.create_random_uid()
|
||||
|
||||
# 1. generate the order lines
|
||||
order_lines = [
|
||||
create_order_line(product, quantity, discount and discount[0] or 0.0)
|
||||
for product, quantity, *discount
|
||||
in pos_order_lines_ui_args
|
||||
create_order_line(**normalize_order_line_param(param))
|
||||
for param in pos_order_lines_ui_args
|
||||
]
|
||||
|
||||
# 2. generate the payments
|
||||
total_amount_incl = sum(line[2]['price_subtotal_incl'] for line in order_lines)
|
||||
if payments is None:
|
||||
default_cash_pm = self.config.payment_method_ids.filtered(lambda pm: pm.is_cash_count)[:1]
|
||||
default_cash_pm = self.config.payment_method_ids.filtered(lambda pm: pm.is_cash_count and not pm.split_transactions)[:1]
|
||||
if not default_cash_pm:
|
||||
raise Exception('There should be a cash payment method set in the pos.config.')
|
||||
payments = [create_payment(default_cash_pm, total_amount_incl)]
|
||||
|
|
@ -543,38 +786,36 @@ class TestPoSCommon(ValuationReconciliationTestCommon):
|
|||
# 3. complete the fields of the order_data
|
||||
total_amount_base = sum(line[2]['price_subtotal'] for line in order_lines)
|
||||
return {
|
||||
'data': {
|
||||
'amount_paid': sum(payment[2]['amount'] for payment in payments),
|
||||
'amount_return': 0,
|
||||
'amount_tax': total_amount_incl - total_amount_base,
|
||||
'amount_total': total_amount_incl,
|
||||
'creation_date': fields.Datetime.to_string(fields.Datetime.now()),
|
||||
'fiscal_position_id': fiscal_position.id,
|
||||
'pricelist_id': self.config.pricelist_id.id,
|
||||
'lines': order_lines,
|
||||
'name': 'Order %s' % uid,
|
||||
'partner_id': customer and customer.id,
|
||||
'pos_session_id': self.pos_session.id,
|
||||
'sequence_number': 2,
|
||||
'statement_ids': payments,
|
||||
'uid': uid,
|
||||
'user_id': self.env.user.id,
|
||||
'to_invoice': is_invoiced,
|
||||
},
|
||||
'id': uid,
|
||||
'amount_paid': sum(payment[2]['amount'] for payment in payments),
|
||||
'amount_return': 0,
|
||||
'amount_tax': total_amount_incl - total_amount_base,
|
||||
'amount_total': total_amount_incl,
|
||||
'date_order': fields.Datetime.to_string(fields.Datetime.now()),
|
||||
'fiscal_position_id': fiscal_position.id,
|
||||
'pricelist_id': self.config.pricelist_id.id,
|
||||
'name': 'Order %s' % uuid,
|
||||
'last_order_preparation_change': '{}',
|
||||
'lines': order_lines,
|
||||
'partner_id': customer and customer.id,
|
||||
'session_id': self.pos_session.id,
|
||||
'payment_ids': payments,
|
||||
'uuid': uuid,
|
||||
'user_id': self.env.uid,
|
||||
'to_invoice': is_invoiced,
|
||||
**pos_order_ui_args,
|
||||
}
|
||||
|
||||
@classmethod
|
||||
def create_product(cls, name, category, lst_price, standard_price=None, tax_ids=None, sale_account=None):
|
||||
product = cls.env['product.product'].create({
|
||||
'type': 'product',
|
||||
'is_storable': True,
|
||||
'available_in_pos': True,
|
||||
'taxes_id': [(5, 0, 0)] if not tax_ids else [(6, 0, tax_ids)],
|
||||
'name': name,
|
||||
'categ_id': category.id,
|
||||
'lst_price': lst_price,
|
||||
'standard_price': standard_price if standard_price else 0.0,
|
||||
'company_id': cls.env.company.id,
|
||||
})
|
||||
if sale_account:
|
||||
product.property_account_income_id = sale_account
|
||||
|
|
@ -611,7 +852,7 @@ class TestPoSCommon(ValuationReconciliationTestCommon):
|
|||
self.pos_session = self.config.current_session_id
|
||||
self.currency = self.pos_session.currency_id
|
||||
self.pricelist = self.pos_session.config_id.pricelist_id
|
||||
self.pos_session.set_cashbox_pos(opening_cash, None)
|
||||
self.pos_session.set_opening_control(opening_cash, None)
|
||||
return self.pos_session
|
||||
|
||||
def _run_test(self, args):
|
||||
|
|
@ -643,11 +884,12 @@ class TestPoSCommon(ValuationReconciliationTestCommon):
|
|||
return pos_session
|
||||
|
||||
def _create_orders(self, order_data_params):
|
||||
'''Returns a dict mapping uid to its created pos.order record.'''
|
||||
'''Returns a dict mapping uuid to its created pos.order record.'''
|
||||
result = {}
|
||||
for params in order_data_params:
|
||||
order_data = self.create_ui_order_data(**params)
|
||||
result[params['uid']] = self.env['pos.order'].browse([order['id'] for order in self.env['pos.order'].create_from_ui([order_data])])
|
||||
order_data = [self.create_ui_order_data(**params) for params in order_data_params]
|
||||
order_ids = [order['id'] for order in self.env['pos.order'].sync_from_ui(order_data)['pos.order']]
|
||||
for order_id in self.env["pos.order"].browse(order_ids):
|
||||
result[order_id.uuid] = order_id
|
||||
return result
|
||||
|
||||
def _check_invoice_journal_entries(self, pos_session, orders_map, expected_values):
|
||||
|
|
@ -713,8 +955,43 @@ class TestPoSCommon(ValuationReconciliationTestCommon):
|
|||
# We allow partial checks of the lines of the account move if `line_ids_predicate` is specified.
|
||||
# This means that only those that satisfy the predicate are compared to the expected account move line_ids.
|
||||
line_ids_predicate = expected_account_move_vals.pop('line_ids_predicate', lambda _: True)
|
||||
self.assertRecordValues(account_move.line_ids.filtered(line_ids_predicate), expected_account_move_vals.pop('line_ids'))
|
||||
line_ids = expected_account_move_vals.pop('line_ids')
|
||||
reconciliation_statuses = []
|
||||
for line in line_ids:
|
||||
partially_reconciled = line.pop('partially_reconciled', False)
|
||||
if partially_reconciled is True:
|
||||
reconciliation_statuses.append('partially_reconciled')
|
||||
else:
|
||||
reconciliation_statuses.append('fully_reconciled' if line.get('reconciled') else 'not_reconciled')
|
||||
account_move_line_ids = account_move.line_ids.filtered(line_ids_predicate)
|
||||
self.assertRecordValues(account_move_line_ids, line_ids)
|
||||
self.assertRecordValues(account_move, [expected_account_move_vals])
|
||||
|
||||
# Check reconciliation status
|
||||
for line, reconciliation_status in zip(account_move_line_ids, reconciliation_statuses):
|
||||
# See 'account_move_line._compute_amount_residual' for more explanation
|
||||
if reconciliation_status == 'fully_reconciled':
|
||||
if line.matching_number:
|
||||
self.assertTrue(line.full_reconcile_id)
|
||||
self.assertAlmostEqual(line.amount_residual, 0)
|
||||
elif reconciliation_status == 'partially_reconciled':
|
||||
self.assertFalse(line.full_reconcile_id)
|
||||
if line.reconciled:
|
||||
self.assertAlmostEqual(line.amount_residual, 0)
|
||||
else:
|
||||
self.assertGreater(abs(line.amount_residual), 0)
|
||||
elif reconciliation_status == 'not_reconciled':
|
||||
self.assertFalse(line.full_reconcile_id)
|
||||
self.assertFalse(line.reconciled)
|
||||
else:
|
||||
# if the expected_account_move_vals is falsy, the account_move should be falsy.
|
||||
self.assertFalse(account_move)
|
||||
|
||||
def make_payment(self, order, payment_method, amount):
|
||||
""" Make payment for the order using the given payment method.
|
||||
"""
|
||||
payment_context = {"active_id": order.id, "active_ids": order.ids}
|
||||
return self.env['pos.make.payment'].with_context(**payment_context).create({
|
||||
'amount': amount,
|
||||
'payment_method_id': payment_method.id,
|
||||
}).check()
|
||||
|
|
|
|||
|
|
@ -0,0 +1,235 @@
|
|||
from odoo.fields import Command
|
||||
|
||||
|
||||
def setup_product_combo_items(self):
|
||||
tax10 = self.env["account.tax"].create(
|
||||
{
|
||||
"name": "10%",
|
||||
"amount": 10,
|
||||
"amount_type": "percent",
|
||||
"type_tax_use": "sale",
|
||||
}
|
||||
)
|
||||
tax20in = self.env["account.tax"].create(
|
||||
{
|
||||
"name": "20% incl",
|
||||
"amount": 20,
|
||||
"amount_type": "percent",
|
||||
"type_tax_use": "sale",
|
||||
"price_include_override": "tax_included",
|
||||
"include_base_amount": True,
|
||||
}
|
||||
)
|
||||
tax30 = self.env["account.tax"].create(
|
||||
{
|
||||
"name": "30%",
|
||||
"amount": 30,
|
||||
"amount_type": "percent",
|
||||
"type_tax_use": "sale",
|
||||
}
|
||||
)
|
||||
|
||||
pos_category_1 = self.env["pos.category"].create({
|
||||
"name": "Category 1",
|
||||
})
|
||||
pos_category_2 = self.env["pos.category"].create({
|
||||
"name": "Category 2",
|
||||
})
|
||||
pos_category_3 = self.env["pos.category"].create({
|
||||
"name": "Category 3",
|
||||
})
|
||||
|
||||
combo_product_1 = self.env["product.product"].create(
|
||||
{
|
||||
"name": "Combo Product 1",
|
||||
"is_storable": True,
|
||||
"available_in_pos": True,
|
||||
"list_price": 10,
|
||||
"taxes_id": [(6, 0, [tax10.id])],
|
||||
"pos_categ_ids": [(6, 0, [pos_category_1.id])],
|
||||
}
|
||||
)
|
||||
|
||||
combo_product_2 = self.env["product.product"].create(
|
||||
{
|
||||
"name": "Combo Product 2",
|
||||
"is_storable": True,
|
||||
"available_in_pos": True,
|
||||
"list_price": 11,
|
||||
"taxes_id": [(6, 0, [tax20in.id])],
|
||||
"pos_categ_ids": [(6, 0, [pos_category_1.id])],
|
||||
}
|
||||
)
|
||||
|
||||
combo_product_3 = self.env["product.product"].create(
|
||||
{
|
||||
"name": "Combo Product 3",
|
||||
"is_storable": True,
|
||||
"available_in_pos": True,
|
||||
"list_price": 16,
|
||||
"taxes_id": [(6, 0, [tax30.id])],
|
||||
"pos_categ_ids": [(6, 0, [pos_category_1.id])],
|
||||
}
|
||||
)
|
||||
|
||||
self.desk_accessories_combo = self.env["product.combo"].create(
|
||||
{
|
||||
"name": "Desk Accessories Combo",
|
||||
"combo_item_ids": [
|
||||
Command.create({
|
||||
"product_id": combo_product_1.id,
|
||||
"extra_price": 0,
|
||||
}),
|
||||
Command.create({
|
||||
"product_id": combo_product_2.id,
|
||||
"extra_price": 0,
|
||||
}),
|
||||
Command.create({
|
||||
"product_id": combo_product_3.id,
|
||||
"extra_price": 2,
|
||||
}),
|
||||
],
|
||||
}
|
||||
)
|
||||
|
||||
combo_product_4 = self.env["product.product"].create(
|
||||
{
|
||||
"name": "Combo Product 4",
|
||||
"is_storable": True,
|
||||
"available_in_pos": True,
|
||||
"list_price": 20,
|
||||
"taxes_id": [(6, 0, [tax10.id])],
|
||||
"pos_categ_ids": [(6, 0, [pos_category_2.id])],
|
||||
}
|
||||
)
|
||||
|
||||
combo_product_5 = self.env["product.product"].create(
|
||||
{
|
||||
"name": "Combo Product 5",
|
||||
"is_storable": True,
|
||||
"available_in_pos": True,
|
||||
"list_price": 25,
|
||||
"taxes_id": [(6, 0, [tax20in.id])],
|
||||
"pos_categ_ids": [(6, 0, [pos_category_2.id])],
|
||||
}
|
||||
)
|
||||
|
||||
self.desks_combo = self.env["product.combo"].create(
|
||||
{
|
||||
"name": "Desks Combo",
|
||||
"combo_item_ids": [
|
||||
Command.create({
|
||||
"product_id": combo_product_4.id,
|
||||
"extra_price": 0,
|
||||
}),
|
||||
Command.create({
|
||||
"product_id": combo_product_5.id,
|
||||
"extra_price": 2,
|
||||
}),
|
||||
],
|
||||
}
|
||||
)
|
||||
|
||||
combo_product_6 = self.env["product.product"].create(
|
||||
{
|
||||
"name": "Combo Product 6",
|
||||
"is_storable": True,
|
||||
"available_in_pos": True,
|
||||
"list_price": 30,
|
||||
"taxes_id": [(6, 0, [tax30.id])],
|
||||
"pos_categ_ids": [(6, 0, [pos_category_3.id])],
|
||||
}
|
||||
)
|
||||
|
||||
combo_product_7 = self.env["product.product"].create(
|
||||
{
|
||||
"name": "Combo Product 7",
|
||||
"is_storable": True,
|
||||
"available_in_pos": True,
|
||||
"list_price": 32,
|
||||
"taxes_id": [(6, 0, [tax10.id])],
|
||||
"pos_categ_ids": [(6, 0, [pos_category_3.id])],
|
||||
}
|
||||
)
|
||||
|
||||
combo_product_8 = self.env["product.product"].create(
|
||||
{
|
||||
"name": "Combo Product 8",
|
||||
"is_storable": True,
|
||||
"available_in_pos": True,
|
||||
"list_price": 40,
|
||||
"taxes_id": [(6, 0, [tax20in.id])],
|
||||
"pos_categ_ids": [(6, 0, [pos_category_3.id])],
|
||||
}
|
||||
)
|
||||
|
||||
combo_product_9 = self.env["product.product"].create(
|
||||
{
|
||||
"name": "Combo Product 9",
|
||||
"is_storable": True,
|
||||
"available_in_pos": True,
|
||||
"list_price": 50,
|
||||
"taxes_id": [(6, 0, [tax20in.id])],
|
||||
"pos_categ_ids": [(6, 0, [pos_category_3.id])],
|
||||
}
|
||||
)
|
||||
|
||||
chair_color_attribute = self.env['product.attribute'].create({
|
||||
'name': 'Color',
|
||||
'display_type': 'color',
|
||||
'create_variant': 'no_variant',
|
||||
})
|
||||
chair_color_red = self.env['product.attribute.value'].create({
|
||||
'name': 'Red',
|
||||
'attribute_id': chair_color_attribute.id,
|
||||
'html_color': '#ff0000',
|
||||
})
|
||||
chair_color_blue = self.env['product.attribute.value'].create({
|
||||
'name': 'Blue',
|
||||
'attribute_id': chair_color_attribute.id,
|
||||
'html_color': '#0000ff',
|
||||
})
|
||||
self.env['product.template.attribute.line'].create({
|
||||
'product_tmpl_id': combo_product_9.product_tmpl_id.id,
|
||||
'attribute_id': chair_color_attribute.id,
|
||||
'value_ids': [(6, 0, [chair_color_red.id, chair_color_blue.id])]
|
||||
})
|
||||
|
||||
self.chairs_combo = self.env["product.combo"].create(
|
||||
{
|
||||
"name": "Chairs Combo",
|
||||
"combo_item_ids": [
|
||||
Command.create({
|
||||
"product_id": combo_product_6.id,
|
||||
"extra_price": 0,
|
||||
}),
|
||||
Command.create({
|
||||
"product_id": combo_product_7.id,
|
||||
"extra_price": 0,
|
||||
}),
|
||||
Command.create({
|
||||
"product_id": combo_product_8.id,
|
||||
"extra_price": 5,
|
||||
}),
|
||||
Command.create({
|
||||
"product_id": combo_product_9.id,
|
||||
"extra_price": 0,
|
||||
}),
|
||||
],
|
||||
}
|
||||
)
|
||||
|
||||
# Create Office Combo
|
||||
self.office_combo = self.env["product.product"].create(
|
||||
{
|
||||
"available_in_pos": True,
|
||||
"list_price": 40,
|
||||
"name": "Office Combo",
|
||||
"type": "combo",
|
||||
"uom_id": self.env.ref("uom.product_uom_unit").id,
|
||||
"combo_ids": [
|
||||
(6, 0, [self.desks_combo.id, self.chairs_combo.id, self.desk_accessories_combo.id])
|
||||
],
|
||||
"pos_categ_ids": [(6, 0, [pos_category_2.id])],
|
||||
}
|
||||
)
|
||||
|
|
@ -1,7 +1,9 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
import time
|
||||
from unittest import skip
|
||||
|
||||
from odoo import Command
|
||||
from odoo.tests import tagged
|
||||
from odoo.addons.account.tests.common import AccountTestInvoicingCommon
|
||||
|
||||
|
|
@ -9,36 +11,41 @@ from odoo.addons.account.tests.common import AccountTestInvoicingCommon
|
|||
class TestAngloSaxonCommon(AccountTestInvoicingCommon):
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls, chart_template_ref=None):
|
||||
super().setUpClass(chart_template_ref=chart_template_ref)
|
||||
def setUpClass(cls):
|
||||
super().setUpClass()
|
||||
cls.env.user.group_ids |= cls.env.ref('point_of_sale.group_pos_manager')
|
||||
cls.PosMakePayment = cls.env['pos.make.payment']
|
||||
cls.PosOrder = cls.env['pos.order']
|
||||
cls.Statement = cls.env['account.bank.statement']
|
||||
cls.company = cls.env.company
|
||||
cls.warehouse = cls.env['stock.warehouse'].search([('company_id', '=', cls.env.company.id)], limit=1)
|
||||
cls.partner = cls.env['res.partner'].create({'name': 'Partner 1'})
|
||||
cls.category = cls.env.ref('product.product_category_all')
|
||||
cls.category = cls.category.copy({'name': 'New category', 'property_valuation': 'real_time'})
|
||||
cls.category = cls.env.ref('product.product_category_services')
|
||||
cls.category = cls.category.copy({'name': 'New category','property_valuation': 'real_time'})
|
||||
cls.account = cls.env['account.account'].create({'name': 'Receivable', 'code': 'RCV00', 'account_type': 'asset_receivable', 'reconcile': True})
|
||||
account_expense = cls.env['account.account'].create({'name': 'Expense', 'code': 'EXP00', 'account_type': 'expense', 'reconcile': True})
|
||||
account_income = cls.env['account.account'].create({'name': 'Income', 'code': 'INC00', 'account_type': 'income', 'reconcile': True})
|
||||
account_output = cls.env['account.account'].create({'name': 'Output', 'code': 'OUT00', 'account_type': 'expense', 'reconcile': True})
|
||||
account_valuation = cls.env['account.account'].create({'name': 'Valuation', 'code': 'STV00', 'account_type': 'expense', 'reconcile': True})
|
||||
cls.partner.property_account_receivable_id = cls.account
|
||||
cls.category.property_account_income_categ_id = account_income
|
||||
cls.category.property_account_expense_categ_id = account_expense
|
||||
cls.category.property_stock_account_input_categ_id = cls.account
|
||||
cls.category.property_stock_account_output_categ_id = account_output
|
||||
cls.category.property_stock_valuation_account_id = account_valuation
|
||||
cls.category.property_stock_journal = cls.env['account.journal'].create({'name': 'Stock journal', 'type': 'sale', 'code': 'STK00'})
|
||||
cls.cash_journal = cls.env['account.journal'].create(
|
||||
{'name': 'CASH journal', 'type': 'cash', 'code': 'CSH02'})
|
||||
cls.cash_payment_method = cls.env['pos.payment.method'].create({
|
||||
'name': 'Cash Test',
|
||||
'journal_id': cls.cash_journal.id,
|
||||
})
|
||||
cls.pos_config = cls.env['pos.config'].create({
|
||||
'name': 'New POS config',
|
||||
'payment_method_ids': cls.cash_payment_method,
|
||||
})
|
||||
cls.product = cls.env['product.product'].create({
|
||||
'name': 'New product',
|
||||
'standard_price': 100,
|
||||
'available_in_pos': True,
|
||||
'type': 'product',
|
||||
'is_storable': True,
|
||||
})
|
||||
cls.company.anglo_saxon_accounting = True
|
||||
cls.company.point_of_sale_update_stock_quantities = 'real'
|
||||
|
|
@ -57,16 +64,18 @@ class TestAngloSaxonCommon(AccountTestInvoicingCommon):
|
|||
})
|
||||
cls.pos_config.write({'payment_method_ids': [(6, 0, cls.cash_payment_method.ids)]})
|
||||
|
||||
|
||||
@tagged('post_install', '-at_install')
|
||||
class TestAngloSaxonFlow(TestAngloSaxonCommon):
|
||||
|
||||
@skip('Temporary to fast merge new valuation')
|
||||
def test_create_account_move_line(self):
|
||||
# This test will check that the correct journal entries are created when a product in real time valuation
|
||||
# is sold in a company using anglo-saxon
|
||||
self.pos_config.open_ui()
|
||||
current_session = self.pos_config.current_session_id
|
||||
self.cash_journal.loss_account_id = self.account
|
||||
current_session.set_cashbox_pos(0, None)
|
||||
current_session.set_opening_control(0, None)
|
||||
|
||||
# I create a PoS order with 1 unit of New product at 450 EUR
|
||||
self.pos_order_pos0 = self.PosOrder.create({
|
||||
|
|
@ -87,6 +96,7 @@ class TestAngloSaxonFlow(TestAngloSaxonCommon):
|
|||
'amount_tax': 0,
|
||||
'amount_paid': 0,
|
||||
'amount_return': 0,
|
||||
'last_order_preparation_change': '{}'
|
||||
})
|
||||
|
||||
# I make a payment to fully pay the order
|
||||
|
|
@ -115,10 +125,10 @@ class TestAngloSaxonFlow(TestAngloSaxonCommon):
|
|||
self.assertFalse(self.pos_order_pos0.account_move, 'There should be no invoice in the order.')
|
||||
|
||||
# I test that the generated journal entries are correct.
|
||||
account_output = self.category.property_stock_account_output_categ_id
|
||||
expense_account = self.category.property_account_expense_categ_id
|
||||
valuation_account = self.category.property_stock_valuation_account_id
|
||||
aml = current_session.move_id.line_ids
|
||||
aml_output = aml.filtered(lambda l: l.account_id.id == account_output.id)
|
||||
aml_output = aml.filtered(lambda l: l.account_id.id == valuation_account.id)
|
||||
aml_expense = aml.filtered(lambda l: l.account_id.id == expense_account.id)
|
||||
self.assertEqual(aml_output.credit, self.product.standard_price, "Cost of Good Sold entry missing or mismatching")
|
||||
self.assertEqual(aml_expense.debit, self.product.standard_price, "Cost of Good Sold entry missing or mismatching")
|
||||
|
|
@ -141,13 +151,13 @@ class TestAngloSaxonFlow(TestAngloSaxonCommon):
|
|||
'inventory_quantity': 10.0,
|
||||
'location_id': self.warehouse.lot_stock_id.id,
|
||||
}).action_apply_inventory()
|
||||
self.assertEqual(self.product.value_svl, 30, "Value should be (5*5 + 5*1) = 30")
|
||||
self.assertEqual(self.product.quantity_svl, 10)
|
||||
self.assertEqual(self.product.total_value, 30, "Value should be (5*5 + 5*1) = 30")
|
||||
self.assertEqual(self.product.virtual_available, 10)
|
||||
|
||||
|
||||
self.pos_config.open_ui()
|
||||
pos_session = self.pos_config.current_session_id
|
||||
pos_session.set_cashbox_pos(0, None)
|
||||
pos_session.set_opening_control(0, None)
|
||||
|
||||
pos_order_values = {
|
||||
'company_id': self.company.id,
|
||||
|
|
@ -167,10 +177,12 @@ class TestAngloSaxonFlow(TestAngloSaxonCommon):
|
|||
'amount_tax': 0,
|
||||
'amount_paid': 0,
|
||||
'amount_return': 0,
|
||||
'last_order_preparation_change': '{}'
|
||||
}
|
||||
|
||||
return self.PosOrder.create(pos_order_values)
|
||||
|
||||
@skip('Temporary to fast merge new valuation')
|
||||
def test_fifo_valuation_no_invoice(self):
|
||||
"""Register a payment and validate a session after selling a fifo
|
||||
product without making an invoice for the customer"""
|
||||
|
|
@ -220,13 +232,14 @@ class TestAngloSaxonFlow(TestAngloSaxonCommon):
|
|||
self.assertEqual(pos_order_pos0.account_move.journal_id, self.pos_config.invoice_journal_id)
|
||||
self.assertEqual(line.debit, 27, 'As it is a fifo product, the move\'s value should be 5*5 + 2*1')
|
||||
|
||||
@skip('Temporary to fast merge new valuation')
|
||||
def test_cogs_with_ship_later_no_invoicing(self):
|
||||
# This test will check that the correct journal entries are created when a product in real time valuation
|
||||
# is sold using the ship later option and no invoice is created in a company using anglo-saxon
|
||||
self.pos_config.open_ui()
|
||||
current_session = self.pos_config.current_session_id
|
||||
self.cash_journal.loss_account_id = self.account
|
||||
current_session.set_cashbox_pos(0, None)
|
||||
current_session.set_opening_control(0, None)
|
||||
|
||||
# 2 step delivery method
|
||||
self.warehouse.delivery_steps = 'pick_ship'
|
||||
|
|
@ -238,7 +251,7 @@ class TestAngloSaxonFlow(TestAngloSaxonCommon):
|
|||
'pricelist_id': self.company.partner_id.property_product_pricelist.id,
|
||||
'session_id': self.pos_config.current_session_id.id,
|
||||
'to_invoice': False,
|
||||
'to_ship': True,
|
||||
'shipping_date': '2023-01-01',
|
||||
'lines': [(0, 0, {
|
||||
'name': "OL/0001",
|
||||
'product_id': self.product.id,
|
||||
|
|
@ -252,6 +265,7 @@ class TestAngloSaxonFlow(TestAngloSaxonCommon):
|
|||
'amount_tax': 0,
|
||||
'amount_paid': 0,
|
||||
'amount_return': 0,
|
||||
'last_order_preparation_change': '{}'
|
||||
})
|
||||
|
||||
# I make a payment to fully pay the order
|
||||
|
|
@ -271,8 +285,10 @@ class TestAngloSaxonFlow(TestAngloSaxonCommon):
|
|||
current_session_id.close_session_from_ui()
|
||||
self.assertEqual(current_session_id.state, 'closed', 'Check that session is closed')
|
||||
|
||||
self.assertEqual(len(current_session.picking_ids), 1, "There should be 2 pickings")
|
||||
current_session.picking_ids.move_ids.write({'quantity': 1, 'picked': True})
|
||||
current_session.picking_ids.button_validate()
|
||||
self.assertEqual(len(current_session.picking_ids), 2, "There should be 2 pickings")
|
||||
current_session.picking_ids.move_ids_without_package.quantity_done = 1
|
||||
current_session.picking_ids.button_validate()
|
||||
|
||||
# I test that the generated journal entries are correct.
|
||||
|
|
@ -282,24 +298,21 @@ class TestAngloSaxonFlow(TestAngloSaxonCommon):
|
|||
aml_output = aml.filtered(lambda l: l.account_id.id == account_output.id)
|
||||
aml_expense = aml.filtered(lambda l: l.account_id.id == expense_account.id)
|
||||
|
||||
self.assertEqual(len(aml_output), 3, "There should be 3 output account move lines")
|
||||
self.assertEqual(len(aml_output), 2, "There should be 2 output account move lines")
|
||||
# 2 moves in POS journal (Pos order + manual entry at delivery)
|
||||
self.assertEqual(len(aml_output.move_id.filtered(lambda l: l.journal_id == self.pos_config.journal_id)), 2)
|
||||
self.assertEqual(len(aml_output.move_id.filtered(lambda l: l.journal_id == self.pos_config.journal_id)), 1)
|
||||
# 1 move in stock journal (delivery from stock layers)
|
||||
self.assertEqual(len(aml_output.move_id.filtered(lambda l: l.journal_id == self.category.property_stock_journal)), 1)
|
||||
#Check the lines created after the picking validation
|
||||
self.assertEqual(aml_output[2].credit, self.product.standard_price, "Cost of Good Sold entry missing or mismatching")
|
||||
self.assertEqual(aml_output[2].debit, 0.0, "Cost of Good Sold entry missing or mismatching")
|
||||
self.assertEqual(aml_output[1].debit, self.product.standard_price, "Cost of Good Sold entry missing or mismatching")
|
||||
self.assertEqual(aml_output[1].credit, 0.0, "Cost of Good Sold entry missing or mismatching")
|
||||
self.assertEqual(aml_expense[1].debit, self.product.standard_price, "Cost of Good Sold entry missing or mismatching")
|
||||
self.assertEqual(aml_expense[1].credit, 0.0, "Cost of Good Sold entry missing or mismatching")
|
||||
#Check the lines created by the PoS session
|
||||
self.assertEqual(aml_output[0].debit, 0.0, "Cost of Good Sold entry missing or mismatching")
|
||||
self.assertEqual(aml_output[0].credit, 0.0, "Cost of Good Sold entry missing or mismatching")
|
||||
self.assertEqual(aml_output[1].credit, self.product.standard_price, "Cost of Good Sold entry missing or mismatching")
|
||||
self.assertEqual(aml_output[1].debit, 0.0, "Cost of Good Sold entry missing or mismatching")
|
||||
self.assertEqual(aml_expense[0].debit, self.product.standard_price, "Cost of Good Sold entry missing or mismatching")
|
||||
self.assertEqual(aml_expense[0].credit, 0.0, "Cost of Good Sold entry missing or mismatching")
|
||||
self.assertEqual(aml_expense[0].debit, 0.0, "Cost of Good Sold entry missing or mismatching")
|
||||
#Check the lines created by the PoS session
|
||||
self.assertEqual(aml_output[0].debit, 100.0, "Cost of Good Sold entry missing or mismatching")
|
||||
self.assertEqual(aml_output[0].credit, 0.0, "Cost of Good Sold entry missing or mismatching")
|
||||
|
||||
@skip('Temporary to fast merge new valuation')
|
||||
def test_action_pos_order_invoice(self):
|
||||
self.company.point_of_sale_update_stock_quantities = 'closing'
|
||||
|
||||
|
|
@ -347,13 +360,14 @@ class TestAngloSaxonFlow(TestAngloSaxonCommon):
|
|||
self.pos_config.open_ui()
|
||||
pricelist = self.env['product.pricelist'].create({
|
||||
'name': 'Test Pricelist',
|
||||
'discount_policy': 'without_discount',
|
||||
'item_ids': [(0, 0, {
|
||||
'compute_price': 'percentage',
|
||||
'percent_price': 5,
|
||||
'min_quantity': 0,
|
||||
'applied_on': '3_global',
|
||||
})]
|
||||
'item_ids': [
|
||||
Command.create({
|
||||
'compute_price': 'percentage',
|
||||
'percent_price': '5.0',
|
||||
'min_quantity': 0,
|
||||
'applied_on': '3_global',
|
||||
})
|
||||
],
|
||||
})
|
||||
self.product.lst_price = 100
|
||||
self.pos_order_pos0 = self.PosOrder.create({
|
||||
|
|
@ -365,7 +379,7 @@ class TestAngloSaxonFlow(TestAngloSaxonCommon):
|
|||
'product_id': self.product.id,
|
||||
'price_unit': 95,
|
||||
'qty': 1.0,
|
||||
'tax_ids': [(6, 0, self.product.taxes_id.ids)],
|
||||
'tax_ids': [(6, 0, self.tax_purchase_a.ids)],
|
||||
'price_subtotal': 90.25,
|
||||
'price_subtotal_incl': 103.79,
|
||||
'discount': 5,
|
||||
|
|
@ -386,9 +400,190 @@ class TestAngloSaxonFlow(TestAngloSaxonCommon):
|
|||
|
||||
res = self.pos_order_pos0.action_pos_order_invoice()
|
||||
invoice = self.env['account.move'].browse(res['res_id'])
|
||||
self.assertTrue('Price discount from 100.00 -> 95.00' in invoice.invoice_line_ids.filtered(lambda l: l.display_type == "line_note").display_name)
|
||||
self.assertTrue('Price discount from 100.00 to 95.00' in invoice.invoice_line_ids.filtered(lambda l: l.display_type == "line_note").display_name)
|
||||
product_line = invoice.invoice_line_ids.filtered(lambda l: l.display_type == "product")
|
||||
self.assertEqual(product_line.price_unit, 95) # Only fiscal position applies
|
||||
self.assertEqual(product_line.price_unit, 95) # Only pricelist applies
|
||||
self.assertEqual(product_line.discount, 5) # Disount is reflected
|
||||
self.assertEqual(product_line.price_subtotal, 90.25) # Discount applies on price_unit
|
||||
self.assertEqual(product_line.price_total, 103.79) # Taxes applied with price_total
|
||||
|
||||
@skip('Temporary to fast merge new valuation')
|
||||
def test_cogs_with_ship_later_with_backorder(self):
|
||||
# This test will check that the correct journal entries are created when 2 products are sold
|
||||
# using the ship later option and one of them is processed in a backorder
|
||||
self.pos_config.open_ui()
|
||||
current_session = self.pos_config.current_session_id
|
||||
self.cash_journal.loss_account_id = self.account
|
||||
current_session.set_opening_control(0, None)
|
||||
|
||||
# Create 2 product one with no cost and one with a cost of 20 EUR
|
||||
self.product_2 = self.env['product.product'].create({
|
||||
'name': 'New product 2',
|
||||
'standard_price': 20,
|
||||
'available_in_pos': True,
|
||||
'is_storable': True,
|
||||
'categ_id': self.category.id,
|
||||
})
|
||||
|
||||
self.product_1 = self.env['product.product'].create({
|
||||
'name': 'New product 1',
|
||||
'standard_price': 0,
|
||||
'available_in_pos': True,
|
||||
'is_storable': True,
|
||||
'categ_id': self.category.id,
|
||||
})
|
||||
|
||||
# I create a PoS order with 1 unit of New product at 450 EUR
|
||||
self.pos_order_pos0 = self.PosOrder.create({
|
||||
'company_id': self.company.id,
|
||||
'partner_id': self.partner.id,
|
||||
'pricelist_id': self.company.partner_id.property_product_pricelist.id,
|
||||
'session_id': self.pos_config.current_session_id.id,
|
||||
'to_invoice': False,
|
||||
'shipping_date': '2023-01-01',
|
||||
'lines': [(0, 0, {
|
||||
'name': "OL/0001",
|
||||
'product_id': self.product_1.id,
|
||||
'price_unit': 100,
|
||||
'discount': 0.0,
|
||||
'qty': 1.0,
|
||||
'price_subtotal': 100,
|
||||
'price_subtotal_incl': 100,
|
||||
}), (0, 0, {
|
||||
'name': "OL/0002",
|
||||
'product_id': self.product_2.id,
|
||||
'price_unit': 200,
|
||||
'discount': 0.0,
|
||||
'qty': 1.0,
|
||||
'price_subtotal': 200,
|
||||
'price_subtotal_incl': 200,
|
||||
})],
|
||||
'amount_total': 300,
|
||||
'amount_tax': 0,
|
||||
'amount_paid': 0,
|
||||
'amount_return': 0,
|
||||
'last_order_preparation_change': '{}'
|
||||
})
|
||||
|
||||
# I make a payment to fully pay the order
|
||||
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': 300.0,
|
||||
'payment_method_id': self.cash_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 close the current session to generate the journal entries
|
||||
current_session_id = self.pos_config.current_session_id
|
||||
current_session_id.post_closing_cash_details(300.0)
|
||||
current_session_id.close_session_from_ui()
|
||||
self.assertEqual(current_session_id.state, 'closed', 'Check that session is closed')
|
||||
|
||||
current_session.picking_ids.move_ids.filtered(lambda m: m.product_id == self.product_2).write({'quantity': 1, 'picked': True})
|
||||
res_dict = current_session.picking_ids.button_validate()
|
||||
self.env['stock.backorder.confirmation'].with_context(res_dict['context']).process()
|
||||
|
||||
# I test that the generated journal entries are correct.
|
||||
out = self.product_1.categ_id.property_stock_account_output_categ_id
|
||||
exp = self.product_1._get_product_accounts()['expense']
|
||||
aml = current_session._get_related_account_moves().line_ids
|
||||
aml_output = aml.filtered(lambda l: l.account_id.id == out.id and l.journal_id == self.pos_config.journal_id)
|
||||
aml_expense = aml.filtered(lambda l: l.account_id.id == exp.id and l.journal_id == self.pos_config.journal_id)
|
||||
|
||||
self.assertEqual(len(aml_expense), 1, "There should be 1 output account move lines")
|
||||
self.assertEqual(aml_expense.debit, 20)
|
||||
self.assertEqual(aml_expense.credit, 0)
|
||||
|
||||
self.assertEqual(len(aml_output), 1, "There should be 1 output account move lines")
|
||||
self.assertEqual(aml_output.debit, 0)
|
||||
self.assertEqual(aml_output.credit, 20)
|
||||
|
||||
backorder_picking = current_session.picking_ids.filtered(lambda p: p.state == 'confirmed')
|
||||
backorder_picking.move_ids.write({'quantity': 1, 'picked': True})
|
||||
backorder_picking.button_validate()
|
||||
|
||||
# As the second item has no cost, the account move line should be the same as before
|
||||
aml = current_session._get_related_account_moves().line_ids
|
||||
aml_output = aml.filtered(lambda l: l.account_id.id == out.id and l.journal_id == self.pos_config.journal_id)
|
||||
aml_expense = aml.filtered(lambda l: l.account_id.id == exp.id and l.journal_id == self.pos_config.journal_id)
|
||||
|
||||
self.assertEqual(len(aml_expense), 1, "There should be 1 output account move lines")
|
||||
self.assertEqual(aml_expense.debit, 20)
|
||||
self.assertEqual(aml_expense.credit, 0)
|
||||
|
||||
self.assertEqual(len(aml_output), 1, "There should be 1 output account move lines")
|
||||
self.assertEqual(aml_output.debit, 0)
|
||||
self.assertEqual(aml_output.credit, 20)
|
||||
|
||||
def test_cogs_multi_products_perpetual(self):
|
||||
"""
|
||||
Check that an order with mutliple products that is invoiced
|
||||
in anglo saxon perpetual posts its stock valuation entries
|
||||
"""
|
||||
self.category.property_valuation = 'real_time'
|
||||
self.product.write({
|
||||
'categ_id': self.category,
|
||||
'standard_price': 20,
|
||||
'list_price': 100
|
||||
})
|
||||
product2 = self.env['product.product'].create({
|
||||
'name': 'P2',
|
||||
'categ_id': self.category.id,
|
||||
'standard_price': 100,
|
||||
'list_price': 200,
|
||||
'available_in_pos': True,
|
||||
'is_storable': True,
|
||||
})
|
||||
|
||||
self.pos_config.open_ui()
|
||||
pos_session = self.pos_config.current_session_id
|
||||
pos_session.set_opening_control(0, None)
|
||||
|
||||
# create order
|
||||
pos_order_values = {
|
||||
'company_id': self.company.id,
|
||||
'partner_id': self.partner.id,
|
||||
'session_id': self.pos_config.current_session_id.id,
|
||||
'lines': [Command.create({
|
||||
'product_id': self.product.id,
|
||||
'price_unit': 100,
|
||||
'discount': 0.0,
|
||||
'qty': 1.0,
|
||||
'price_subtotal': 100,
|
||||
'price_subtotal_incl': 100,
|
||||
}), Command.create({
|
||||
'product_id': product2.id,
|
||||
'price_unit': 200,
|
||||
'discount': 0.0,
|
||||
'qty': 1.0,
|
||||
'price_subtotal': 200,
|
||||
'price_subtotal_incl': 200,
|
||||
})],
|
||||
'amount_total': 300,
|
||||
'amount_tax': 0,
|
||||
'amount_paid': 0,
|
||||
'amount_return': 0,
|
||||
'last_order_preparation_change': '{}',
|
||||
'to_invoice': True,
|
||||
}
|
||||
pos_order = self.PosOrder.create(pos_order_values)
|
||||
|
||||
# register payment
|
||||
context_make_payment = {"active_ids": [pos_order.id], "active_id": pos_order.id}
|
||||
pos_payment = self.PosMakePayment.with_context(context_make_payment).create({
|
||||
'amount': 300.0,
|
||||
'payment_method_id': self.cash_payment_method.id,
|
||||
})
|
||||
context_payment = {'active_id': pos_order.id}
|
||||
pos_payment.with_context(context_payment).check()
|
||||
|
||||
valuation_account = self.category.property_stock_valuation_account_id
|
||||
valuation_lines = pos_order.account_move.line_ids.filtered(lambda line: line.account_id == valuation_account)
|
||||
|
||||
self.assertRecordValues(valuation_lines.sorted(lambda aml: aml.product_id.id), [
|
||||
{'product_id': self.product.id, 'credit': 20.0},
|
||||
{'product_id': product2.id, 'credit': 100.0},
|
||||
])
|
||||
|
|
|
|||
|
|
@ -0,0 +1,78 @@
|
|||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from odoo.tests import tagged
|
||||
from odoo.addons.point_of_sale.tests.test_anglo_saxon import TestAngloSaxonCommon
|
||||
|
||||
|
||||
class TestContinentalCommon(TestAngloSaxonCommon):
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
super().setUpClass()
|
||||
cls.env.company.anglo_saxon_accounting = False
|
||||
|
||||
|
||||
@tagged('post_install', '-at_install')
|
||||
class TestContinentalPerpetualFlow(TestContinentalCommon):
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
super().setUpClass()
|
||||
cls.env.company.inventory_valuation = 'real_time'
|
||||
cls.category.property_valuation = 'real_time'
|
||||
cls.product.write({
|
||||
'name': "Real time valo product",
|
||||
'categ_id': cls.category,
|
||||
'standard_price': 20,
|
||||
'list_price': 100
|
||||
})
|
||||
|
||||
def test_inventory_valuation_session_closing_no_invoice(self):
|
||||
""" Tests that closing the session posts the stock valuation
|
||||
move line entries, even if order was not invoiced. """
|
||||
self.pos_config.open_ui()
|
||||
pos_session = self.pos_config.current_session_id
|
||||
pos_session.set_opening_control(0, None)
|
||||
|
||||
# create order
|
||||
pos_order_values = {
|
||||
'company_id': self.company.id,
|
||||
'partner_id': self.partner.id,
|
||||
'session_id': self.pos_config.current_session_id.id,
|
||||
'lines': [(0, 0, {
|
||||
'name': "OL/0001",
|
||||
'product_id': self.product.id,
|
||||
'price_unit': 100,
|
||||
'discount': 0.0,
|
||||
'qty': 1.0,
|
||||
'price_subtotal': 100,
|
||||
'price_subtotal_incl': 100,
|
||||
})],
|
||||
'amount_total': 100,
|
||||
'amount_tax': 0,
|
||||
'amount_paid': 0,
|
||||
'amount_return': 0,
|
||||
'last_order_preparation_change': '{}'
|
||||
}
|
||||
|
||||
pos_order = self.PosOrder.create(pos_order_values)
|
||||
|
||||
# register payment
|
||||
context_make_payment = {"active_ids": [pos_order.id], "active_id": pos_order.id}
|
||||
pos_payment = self.PosMakePayment.with_context(context_make_payment).create({
|
||||
'amount': 100.0,
|
||||
'payment_method_id': self.cash_payment_method.id,
|
||||
})
|
||||
context_payment = {'active_id': pos_order.id}
|
||||
pos_payment.with_context(context_payment).check()
|
||||
|
||||
# validate the session
|
||||
current_session_id = self.pos_config.current_session_id
|
||||
current_session_id.post_closing_cash_details(100.0)
|
||||
current_session_id.close_session_from_ui()
|
||||
|
||||
valuation_account = self.category.property_stock_valuation_account_id
|
||||
valuation_lines = current_session_id.move_id.line_ids.filtered(lambda line: line.account_id == valuation_account)
|
||||
|
||||
self.assertEqual(len(valuation_lines), 1)
|
||||
self.assertEqual(valuation_lines.credit, 20.0)
|
||||
File diff suppressed because it is too large
Load diff
|
|
@ -0,0 +1,29 @@
|
|||
from odoo.addons.point_of_sale.tests.test_frontend import TestPointOfSaleHttpCommon
|
||||
from odoo.tests import tagged
|
||||
from odoo.fields import Command
|
||||
|
||||
|
||||
@tagged('post_install', '-at_install', 'post_install_l10n')
|
||||
class TestGenericLocalization(TestPointOfSaleHttpCommon):
|
||||
allow_inherited_tests_method = True
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
super().setUpClass()
|
||||
cls.partner_a.name = "AAAA Generic Partner"
|
||||
cls.partner_a.vat = "32345678"
|
||||
cls.whiteboard_pen.write({
|
||||
'standard_price': 10.0,
|
||||
'taxes_id': [Command.link(cls.tax_sale_a.id)]
|
||||
})
|
||||
|
||||
cls.wall_shelf.write({
|
||||
'standard_price': 10.0,
|
||||
'taxes_id': [Command.link(cls.tax_sale_a.id)]
|
||||
})
|
||||
|
||||
def test_generic_localization(self):
|
||||
self.main_pos_config.open_ui()
|
||||
url = "/pos/ui?config_id=%d" % self.main_pos_config.id
|
||||
url += "&company_name=%s" % self.main_pos_config.company_id.name
|
||||
self.start_tour(url, "generic_localization_tour", login="accountman")
|
||||
|
|
@ -1,29 +0,0 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
import logging
|
||||
|
||||
from odoo.tests import tagged, HttpCase
|
||||
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@tagged("post_install", "-at_install")
|
||||
class WebSuite(HttpCase):
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
env = self.env(user=self.env.ref('base.user_admin'))
|
||||
payment_method = env['pos.payment.method'].create({'name': 'Lets Pay for Tests'})
|
||||
env['product.product'].create({'name': 'Test Product', 'available_in_pos': True})
|
||||
self.main_pos_config = self.main_pos_config = env['pos.config'].create({
|
||||
'name': 'Shop',
|
||||
'payment_method_ids': [(4, payment_method.id)]
|
||||
})
|
||||
|
||||
def test_pos_js(self):
|
||||
# open a session, the /pos/ui controller will redirect to it
|
||||
self.main_pos_config.open_ui()
|
||||
self.main_pos_config.current_session_id.set_cashbox_pos(0, None)
|
||||
|
||||
# point_of_sale desktop test suite
|
||||
self.browser_js("/pos/ui/tests?mod=web", "", "", login="admin", timeout=1800)
|
||||
|
|
@ -0,0 +1,43 @@
|
|||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
import logging
|
||||
|
||||
from odoo.addons.point_of_sale.tests.test_frontend import TestPointOfSaleHttpCommon
|
||||
|
||||
from odoo.cli.populate import Populate
|
||||
from odoo.tests.common import tagged
|
||||
from odoo.tools import mute_logger
|
||||
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@tagged('-standard', 'pos_performance', '-at_install', 'post_install')
|
||||
class TestPosPerformance(TestPointOfSaleHttpCommon):
|
||||
"""
|
||||
These tests are designed for local performance testing only and will be skipped
|
||||
unless the 'pos_performance' tag is explicitly included in the test tags.
|
||||
|
||||
To execute these tests locally, use the 'pos_performance' tag before the test name.
|
||||
Example:
|
||||
--test-tags pos_performance.test_pos_session_open_product_performance
|
||||
"""
|
||||
|
||||
def __populate_model(self, model_name, total_count):
|
||||
before_count = self.env[model_name].search_count([])
|
||||
if not before_count:
|
||||
return False
|
||||
populate_count = round(total_count / before_count) - 1
|
||||
Populate.populate(self.env, {model_name: populate_count}, 1)
|
||||
|
||||
after_count = self.env[model_name].search_count([])
|
||||
_logger.info("\n\nBefore %s Count: %s\nAfter %s Count: %s\n\n", model_name, before_count, model_name, after_count)
|
||||
return True
|
||||
|
||||
@mute_logger('odoo.models.unlink', 'odoo.cli.populate', 'odoo.tools.populate', 'odoo.tests.common', 'werkzeug')
|
||||
def test_pos_session_open_product_performance(self):
|
||||
self.env['ir.config_parameter'].sudo().set_param('point_of_sale.limited_product_count', 20000)
|
||||
if not self.__populate_model('product.template', 20000):
|
||||
_logger.warning("The product.template model must contain at least one record before it can be populated.")
|
||||
return
|
||||
self.main_pos_config.with_user(self.pos_user).open_ui()
|
||||
self.start_pos_tour('tourSessionOpenProductPerformance', timeout=2000)
|
||||
|
|
@ -1,36 +1,44 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from odoo.fields import Command
|
||||
from odoo.tests.common import TransactionCase
|
||||
from odoo.exceptions import UserError
|
||||
|
||||
|
||||
class TestPointOfSale(TransactionCase):
|
||||
def setUp(self):
|
||||
super(TestPointOfSale, self).setUp()
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
super().setUpClass()
|
||||
|
||||
# ignore pre-existing pricelists for the purpose of this test
|
||||
self.env["product.pricelist"].search([]).write({"active": False})
|
||||
cls.env["product.pricelist"].search([]).write({"active": False})
|
||||
|
||||
self.currency = self.env.ref("base.USD")
|
||||
self.company1 = self.env["res.company"].create({
|
||||
cls.currency = cls.env.ref("base.USD")
|
||||
cls.company1, cls.company2 = cls.env["res.company"].create([{
|
||||
"name": "company 1",
|
||||
"currency_id": self.currency.id
|
||||
})
|
||||
self.company2 = self.env["res.company"].create({
|
||||
"currency_id": cls.currency.id
|
||||
}, {
|
||||
"name": "company 2",
|
||||
"currency_id": self.currency.id
|
||||
})
|
||||
self.company2_pricelist = self.env["product.pricelist"].create({
|
||||
"currency_id": cls.currency.id
|
||||
}])
|
||||
cls.company2_pricelist = cls.env["product.pricelist"].create({
|
||||
"name": "company 2 pricelist",
|
||||
"currency_id": self.currency.id,
|
||||
"company_id": self.company2.id,
|
||||
"currency_id": cls.currency.id,
|
||||
"company_id": cls.company2.id,
|
||||
"sequence": 1, # force this pricelist to be first
|
||||
})
|
||||
cls.bank_journal = cls.env['account.journal'].create({
|
||||
'name': 'Bank',
|
||||
'type': 'bank',
|
||||
'company_id': cls.company1.id,
|
||||
'code': 'BNK',
|
||||
'sequence': 11,
|
||||
})
|
||||
|
||||
self.env.user.company_id = self.company1
|
||||
cls.env.user.company_id = cls.company1
|
||||
|
||||
def test_default_pricelist_with_company(self):
|
||||
""" Verify that the default pricelist belongs to the same company as the config """
|
||||
def test_no_default_pricelist(self):
|
||||
""" Verify that the default pricelist isn't automatically set in the config """
|
||||
company1_pricelist = self.env["product.pricelist"].create({
|
||||
"name": "company 1 pricelist",
|
||||
"currency_id": self.currency.id,
|
||||
|
|
@ -38,26 +46,106 @@ class TestPointOfSale(TransactionCase):
|
|||
"sequence": 2,
|
||||
})
|
||||
|
||||
# make sure this doesn't pick the company2 pricelist
|
||||
# make sure this doesn't pick a pricelist as default
|
||||
new_config = self.env["pos.config"].create({
|
||||
"name": "usd config"
|
||||
"name": "usd config", "available_pricelist_ids": [(6, 0, [company1_pricelist.id])]
|
||||
})
|
||||
|
||||
self.assertEqual(new_config.pricelist_id, company1_pricelist,
|
||||
self.assertEqual(new_config.pricelist_id, self.env['product.pricelist'],
|
||||
"POS config incorrectly has pricelist %s" % new_config.pricelist_id.display_name)
|
||||
|
||||
def test_default_pricelist_without_company(self):
|
||||
""" Verify that a default pricelist without a company works """
|
||||
universal_pricelist = self.env["product.pricelist"].create({
|
||||
"name": "universal pricelist",
|
||||
"currency_id": self.currency.id,
|
||||
"sequence": 2,
|
||||
def test_product_combo_variants(self):
|
||||
# Create product and combo
|
||||
product = self.env['product.product'].create({
|
||||
'name': 'Test Product 1',
|
||||
'list_price': 100,
|
||||
'taxes_id': False,
|
||||
'available_in_pos': True,
|
||||
})
|
||||
|
||||
# make sure this doesn't pick the company2 pricelist
|
||||
new_config = self.env["pos.config"].create({
|
||||
"name": "usd config"
|
||||
product_combo = self.env["product.combo"].create(
|
||||
{
|
||||
"name": "Product combo",
|
||||
"combo_item_ids": [
|
||||
Command.create({
|
||||
"product_id": product.id,
|
||||
"extra_price": 0,
|
||||
}),
|
||||
],
|
||||
}
|
||||
)
|
||||
# Add attribute and values, simulating variant creation
|
||||
size_attribute = self.env['product.attribute'].create({'name': 'Size'})
|
||||
attribute_value_1 = self.env['product.attribute.value'].create({'name': 'Large', 'attribute_id': size_attribute.id})
|
||||
attribute_value_2 = self.env['product.attribute.value'].create({'name': 'Small', 'attribute_id': size_attribute.id})
|
||||
original_product_id = product.id
|
||||
product_template = product.product_tmpl_id
|
||||
product.product_tmpl_id.with_context(create_product_product=True).write({
|
||||
'attribute_line_ids': [(0, 0, {
|
||||
'attribute_id': size_attribute.id,
|
||||
'value_ids': [(6, 0, [attribute_value_1.id, attribute_value_2.id])],
|
||||
})],
|
||||
})
|
||||
# Check that original product should not be in combo anymore (replace by variants)
|
||||
self.assertTrue(original_product_id not in product_combo.combo_item_ids.mapped('product_id').ids, "Original product should not be in combo")
|
||||
|
||||
self.assertEqual(new_config.pricelist_id, universal_pricelist,
|
||||
"POS config incorrectly has pricelist %s" % new_config.pricelist_id.display_name)
|
||||
def test_pos_bill_digits(self):
|
||||
coin = self.env["pos.bill"].create({
|
||||
"name": "0.005 not rounded",
|
||||
"value": 0.005
|
||||
})
|
||||
self.assertEqual(coin.value, 0.005)
|
||||
|
||||
def test_pos_config_creates_warehouse(self):
|
||||
warehouse = self.env['stock.warehouse'].search([('company_id', '=', self.env.company.id)])
|
||||
if warehouse:
|
||||
warehouse.write({'active': False, 'name': 'Archived ' + warehouse[0].name})
|
||||
pos_config = self.env['pos.config'].create({
|
||||
'name': 'Shop',
|
||||
'module_pos_restaurant': False,
|
||||
})
|
||||
self.assertEqual(pos_config.warehouse_id.code, 'Sho')
|
||||
|
||||
def test_session_filter_local_data(self):
|
||||
product1 = self.env['product.template'].create({
|
||||
'name': 'product1'
|
||||
})
|
||||
product2 = self.env['product.template'].create({
|
||||
'name': 'product2'
|
||||
})
|
||||
product3 = self.env['product.template'].create({
|
||||
'name': 'product3'
|
||||
})
|
||||
config = self.env["pos.config"].create({
|
||||
"name": "shop"
|
||||
})
|
||||
session = self.env['pos.session'].create({'name': 'Test Session', 'config_id': config.id})
|
||||
|
||||
# Delete one product and archive another one
|
||||
products_to_display = [product1.id, product2.id, product3.id]
|
||||
product1.write({'active': False})
|
||||
product2.unlink()
|
||||
models_to_filter = {'product.template': products_to_display}
|
||||
products_to_display = list(set(products_to_display) - set(session.filter_local_data(models_to_filter)['product.template']))
|
||||
self.assertEqual(products_to_display, [product3.id])
|
||||
|
||||
# No change
|
||||
product4 = self.env['product.template'].create({
|
||||
'name': 'product4'
|
||||
})
|
||||
products_to_display = [product3.id, product4.id]
|
||||
models_to_filter = {'product.template': products_to_display}
|
||||
products_to_display = list(set(products_to_display) - set(session.filter_local_data(models_to_filter)['product.template']))
|
||||
self.assertEqual(sorted(products_to_display), sorted([product3.id, product4.id]))
|
||||
|
||||
# Delete all products
|
||||
products_to_display = [product3.id, product4.id]
|
||||
product3.unlink()
|
||||
product4.unlink()
|
||||
models_to_filter = {'product.template': products_to_display}
|
||||
products_to_display = list(set(products_to_display) - set(session.filter_local_data(models_to_filter)['product.template']))
|
||||
self.assertEqual(products_to_display, [])
|
||||
|
||||
# Cannot archive config while session is active
|
||||
with self.assertRaises(UserError):
|
||||
config.write({'active': False})
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -13,4 +13,4 @@ class TestUi(HttpCase):
|
|||
@tools.mute_logger('odoo.http')
|
||||
def test_01_point_of_sale_tour(self):
|
||||
|
||||
self.start_tour("/web", 'point_of_sale_tour', login="admin")
|
||||
self.start_tour("/odoo", 'point_of_sale_tour', login="admin")
|
||||
|
|
|
|||
|
|
@ -5,8 +5,12 @@ import odoo
|
|||
|
||||
from odoo import fields
|
||||
from odoo.addons.point_of_sale.tests.common import TestPoSCommon
|
||||
from odoo.exceptions import ValidationError
|
||||
from freezegun import freeze_time
|
||||
from dateutil.relativedelta import relativedelta
|
||||
from datetime import datetime, timedelta
|
||||
import unittest.mock
|
||||
from odoo.http import UserError
|
||||
|
||||
|
||||
@odoo.tests.tagged('post_install', '-at_install')
|
||||
|
|
@ -26,8 +30,9 @@ class TestPoSBasicConfig(TestPoSCommon):
|
|||
self.product3 = self.create_product('Product 3', self.categ_basic, 30.0, 15)
|
||||
self.product4 = self.create_product('Product_4', self.categ_basic, 9.96, 4.98)
|
||||
self.product99 = self.create_product('Product_99', self.categ_basic, 99, 50)
|
||||
self.product_multi_tax = self.create_product('Multi-tax product', self.categ_basic, 100, 100, (self.taxes['tax7base'] | self.taxes['tax10nobase']).ids)
|
||||
self.product_multi_tax = self.create_product('Multi-tax product', self.categ_basic, 100, 100, (self.taxes['tax8'] | self.taxes['tax9']).ids)
|
||||
self.adjust_inventory([self.product1, self.product2, self.product3], [100, 50, 50])
|
||||
self.company_data_2 = self.setup_other_company()
|
||||
|
||||
def test_orders_no_invoiced(self):
|
||||
""" Test for orders without invoice
|
||||
|
|
@ -107,9 +112,9 @@ class TestPoSBasicConfig(TestPoSCommon):
|
|||
self._run_test({
|
||||
'payment_methods': self.cash_pm1 | self.bank_pm1,
|
||||
'orders': [
|
||||
{'pos_order_lines_ui_args': [(self.product1, 10), (self.product2, 5)], 'uid': '00100-010-0001'},
|
||||
{'pos_order_lines_ui_args': [(self.product2, 7), (self.product3, 1)], 'uid': '00100-010-0002'},
|
||||
{'pos_order_lines_ui_args': [(self.product1, 1), (self.product3, 5), (self.product2, 3)], 'payments': [(self.bank_pm1, 220)], 'uid': '00100-010-0003'},
|
||||
{'pos_order_lines_ui_args': [(self.product1, 10), (self.product2, 5)], 'uuid': '00100-010-0001'},
|
||||
{'pos_order_lines_ui_args': [(self.product2, 7), (self.product3, 1)], 'uuid': '00100-010-0002'},
|
||||
{'pos_order_lines_ui_args': [(self.product1, 1), (self.product3, 5), (self.product2, 3)], 'payments': [(self.bank_pm1, 220)], 'uuid': '00100-010-0003'},
|
||||
],
|
||||
'before_closing_cb': _before_closing_cb,
|
||||
'journal_entries_before_closing': {},
|
||||
|
|
@ -222,12 +227,12 @@ class TestPoSBasicConfig(TestPoSCommon):
|
|||
invoiced_order = self.pos_session.order_ids.filtered(lambda order: order.account_move)
|
||||
self.assertEqual(1, len(invoiced_order), 'Only one order is invoiced in this test.')
|
||||
|
||||
# check state of orders before validating the session.
|
||||
self.assertEqual('invoiced', invoiced_order.state, msg="state should be 'invoiced' for invoiced orders.")
|
||||
# check account_move of orders before validating the session.
|
||||
self.assertTrue(invoiced_order.account_move, msg="Invoiced orders must have account_move.")
|
||||
uninvoiced_orders = self.pos_session.order_ids - invoiced_order
|
||||
self.assertTrue(
|
||||
all([order.state == 'paid' for order in uninvoiced_orders]),
|
||||
msg="state should be 'paid' for uninvoiced orders before validating the session."
|
||||
all(not order.account_move for order in uninvoiced_orders),
|
||||
msg="Uninvoiced orders do not have account_move."
|
||||
)
|
||||
|
||||
def _after_closing_cb():
|
||||
|
|
@ -241,9 +246,9 @@ class TestPoSBasicConfig(TestPoSCommon):
|
|||
self._run_test({
|
||||
'payment_methods': self.cash_pm1 | self.bank_pm1,
|
||||
'orders': [
|
||||
{'pos_order_lines_ui_args': [(self.product1, 6), (self.product2, 3), (self.product3, 1), ], 'payments': [(self.cash_pm1, 150)], 'uid': '00100-010-0001'},
|
||||
{'pos_order_lines_ui_args': [(self.product1, 1), (self.product2, 20), ], 'payments': [(self.bank_pm1, 410)], 'uid': '00100-010-0002'},
|
||||
{'pos_order_lines_ui_args': [(self.product1, 10), (self.product3, 1), ], 'payments': [(self.bank_pm1, 130)], 'is_invoiced': True, 'customer': self.customer, 'uid': '00100-010-0003'},
|
||||
{'pos_order_lines_ui_args': [(self.product1, 6), (self.product2, 3), (self.product3, 1), ], 'payments': [(self.cash_pm1, 150)], 'uuid': '00100-010-0001'},
|
||||
{'pos_order_lines_ui_args': [(self.product1, 1), (self.product2, 20), ], 'payments': [(self.bank_pm1, 410)], 'uuid': '00100-010-0002'},
|
||||
{'pos_order_lines_ui_args': [(self.product1, 10), (self.product3, 1), ], 'payments': [(self.bank_pm1, 130)], 'is_invoiced': True, 'customer': self.customer, 'uuid': '00100-010-0003'},
|
||||
],
|
||||
'before_closing_cb': _before_closing_cb,
|
||||
'journal_entries_before_closing': {
|
||||
|
|
@ -299,7 +304,7 @@ class TestPoSBasicConfig(TestPoSCommon):
|
|||
self._run_test({
|
||||
'payment_methods': self.cash_pm1 | self.bank_pm1,
|
||||
'orders': [
|
||||
{'pos_order_lines_ui_args': [(self.product0, 1)], 'payments': [(self.bank_pm1, 0)], 'customer': self.customer, 'is_invoiced': True, 'uid': '00100-010-0001'},
|
||||
{'pos_order_lines_ui_args': [(self.product0, 1)], 'payments': [(self.bank_pm1, 0)], 'customer': self.customer, 'is_invoiced': True, 'uuid': '00100-010-0001'},
|
||||
],
|
||||
'journal_entries_before_closing': {
|
||||
'00100-010-0001': {
|
||||
|
|
@ -324,7 +329,7 @@ class TestPoSBasicConfig(TestPoSCommon):
|
|||
def test_return_order_invoiced(self):
|
||||
|
||||
def _before_closing_cb():
|
||||
order = self.pos_session.order_ids.filtered(lambda order: '666-666-666' in order.pos_reference)
|
||||
order = self.pos_session.order_ids.filtered(lambda order: '666-666-666' in order.uuid)
|
||||
|
||||
# refund
|
||||
order.refund()
|
||||
|
|
@ -344,7 +349,7 @@ class TestPoSBasicConfig(TestPoSCommon):
|
|||
self._run_test({
|
||||
'payment_methods': self.cash_pm1 | self.bank_pm1,
|
||||
'orders': [
|
||||
{'pos_order_lines_ui_args': [(self.product1, 10)], 'payments': [(self.cash_pm1, 100)], 'customer': self.customer, 'is_invoiced': True, 'uid': '666-666-666'},
|
||||
{'pos_order_lines_ui_args': [(self.product1, 10)], 'payments': [(self.cash_pm1, 100)], 'customer': self.customer, 'is_invoiced': True, 'uuid': '666-666-666'},
|
||||
],
|
||||
'before_closing_cb': _before_closing_cb,
|
||||
'journal_entries_before_closing': {
|
||||
|
|
@ -424,7 +429,7 @@ class TestPoSBasicConfig(TestPoSCommon):
|
|||
self.assertAlmostEqual(orders_total, self.pos_session.total_payments_amount, msg='Total order amount should be equal to the total payment amount.')
|
||||
|
||||
# return order
|
||||
order_to_return = self.pos_session.order_ids.filtered(lambda order: '12345-123-1234' in order.pos_reference)
|
||||
order_to_return = self.pos_session.order_ids.filtered(lambda order: '12345-123-1234' in order.uuid)
|
||||
order_to_return.refund()
|
||||
refund_order = self.pos_session.order_ids.filtered(lambda order: order.state == 'draft')
|
||||
|
||||
|
|
@ -473,8 +478,8 @@ class TestPoSBasicConfig(TestPoSCommon):
|
|||
self._run_test({
|
||||
'payment_methods': self.cash_pm1 | self.bank_pm1,
|
||||
'orders': [
|
||||
{'pos_order_lines_ui_args': [(self.product1, 1), (self.product2, 5)], 'payments': [(self.bank_pm1, 110)], 'uid': '00100-010-0001'},
|
||||
{'pos_order_lines_ui_args': [(self.product1, 3), (self.product2, 2), (self.product3, 1)], 'payments': [(self.cash_pm1, 100)], 'uid': '12345-123-1234'},
|
||||
{'pos_order_lines_ui_args': [(self.product1, 1), (self.product2, 5)], 'payments': [(self.bank_pm1, 110)], 'uuid': '00100-010-0001'},
|
||||
{'pos_order_lines_ui_args': [(self.product1, 3), (self.product2, 2), (self.product3, 1)], 'payments': [(self.cash_pm1, 100)], 'uuid': '12345-123-1234'},
|
||||
],
|
||||
'before_closing_cb': _before_closing_cb,
|
||||
'journal_entries_before_closing': {},
|
||||
|
|
@ -502,9 +507,9 @@ class TestPoSBasicConfig(TestPoSCommon):
|
|||
self._run_test({
|
||||
'payment_methods': self.cash_split_pm1 | self.bank_pm1,
|
||||
'orders': [
|
||||
{'pos_order_lines_ui_args': [(self.product1, 10), (self.product2, 5)], 'payments': [(self.cash_split_pm1, 100), (self.bank_pm1, 100)], 'customer': self.customer, 'is_invoiced': False, 'uid': '00100-010-0001'},
|
||||
{'pos_order_lines_ui_args': [(self.product2, 7), (self.product3, 1)], 'payments': [(self.cash_split_pm1, 70), (self.bank_pm1, 100)], 'customer': self.customer, 'is_invoiced': False, 'uid': '00100-010-0002'},
|
||||
{'pos_order_lines_ui_args': [(self.product1, 1), (self.product3, 5), (self.product2, 3)], 'payments': [(self.cash_split_pm1, 120), (self.bank_pm1, 100)], 'customer': self.customer, 'is_invoiced': False, 'uid': '00100-010-0003'},
|
||||
{'pos_order_lines_ui_args': [(self.product1, 10), (self.product2, 5)], 'payments': [(self.cash_split_pm1, 100), (self.bank_pm1, 100)], 'customer': self.customer, 'is_invoiced': False, 'uuid': '00100-010-0001'},
|
||||
{'pos_order_lines_ui_args': [(self.product2, 7), (self.product3, 1)], 'payments': [(self.cash_split_pm1, 70), (self.bank_pm1, 100)], 'customer': self.customer, 'is_invoiced': False, 'uuid': '00100-010-0002'},
|
||||
{'pos_order_lines_ui_args': [(self.product1, 1), (self.product3, 5), (self.product2, 3)], 'payments': [(self.cash_split_pm1, 120), (self.bank_pm1, 100)], 'customer': self.customer, 'is_invoiced': False, 'uuid': '00100-010-0003'},
|
||||
],
|
||||
'journal_entries_before_closing': {},
|
||||
'journal_entries_after_closing': {
|
||||
|
|
@ -610,10 +615,10 @@ class TestPoSBasicConfig(TestPoSCommon):
|
|||
))
|
||||
|
||||
# sync orders
|
||||
order = self.env['pos.order'].create_from_ui(orders)
|
||||
self.env['pos.order'].sync_from_ui(orders)
|
||||
|
||||
self.assertEqual(orders[0]['data']['amount_return'], 0, msg='The amount return should be 0')
|
||||
self.assertEqual(orders[1]['data']['amount_return'], 0, msg='The amount return should be 0')
|
||||
self.assertEqual(orders[0]['amount_return'], 0, msg='The amount return should be 0')
|
||||
self.assertEqual(orders[1]['amount_return'], 0, msg='The amount return should be 0')
|
||||
|
||||
# close the session
|
||||
self.pos_session.action_pos_session_validate()
|
||||
|
|
@ -628,17 +633,17 @@ class TestPoSBasicConfig(TestPoSCommon):
|
|||
self._run_test({
|
||||
'payment_methods': self.cash_pm1 | self.cash_split_pm1 | self.bank_pm1 | self.bank_split_pm1,
|
||||
'orders': [
|
||||
{'pos_order_lines_ui_args': [(self.product1, 10)], 'payments':[(self.cash_pm1, 100)], 'customer': self.customer, 'is_invoiced': True, 'uid': '00100-010-0001'},
|
||||
{'pos_order_lines_ui_args': [(self.product1, 10)], 'payments':[(self.bank_pm1, 100)], 'customer': self.customer, 'is_invoiced': True, 'uid': '00100-010-0002'},
|
||||
{'pos_order_lines_ui_args': [(self.product1, 10)], 'payments':[(self.cash_split_pm1, 100)], 'customer': self.customer, 'is_invoiced': True, 'uid': '00100-010-0003'},
|
||||
{'pos_order_lines_ui_args': [(self.product1, 10)], 'payments':[(self.bank_split_pm1, 100)], 'customer': self.customer, 'is_invoiced': True, 'uid': '00100-010-0004'},
|
||||
{'pos_order_lines_ui_args': [(self.product1, 10)], 'payments':[(self.cash_pm1, 100)], 'customer': self.customer, 'is_invoiced': False, 'uid': '00100-010-0005'},
|
||||
{'pos_order_lines_ui_args': [(self.product1, 10)], 'payments':[(self.bank_pm1, 100)], 'customer': self.customer, 'is_invoiced': False, 'uid': '00100-010-0006'},
|
||||
{'pos_order_lines_ui_args': [(self.product99, 1)], 'payments':[(self.cash_split_pm1, 99)], 'customer': self.customer, 'is_invoiced': False, 'uid': '00100-010-0007'},
|
||||
{'pos_order_lines_ui_args': [(self.product99, 1)], 'payments':[(self.bank_split_pm1, 99)], 'customer': self.customer, 'is_invoiced': False, 'uid': '00100-010-0008'},
|
||||
{'pos_order_lines_ui_args': [(self.product1, 10)], 'payments':[(self.bank_pm1, 100)], 'customer': self.other_customer, 'is_invoiced': True, 'uid': '00100-010-0009'},
|
||||
{'pos_order_lines_ui_args': [(self.product1, 10)], 'payments':[(self.bank_pm1, 100)], 'customer': self.other_customer, 'is_invoiced': True, 'uid': '00100-010-0010'},
|
||||
{'pos_order_lines_ui_args': [(self.product1, 10)], 'payments':[(self.bank_pm1, 100)], 'customer': self.customer, 'is_invoiced': True, 'uid': '00100-010-0011'},
|
||||
{'pos_order_lines_ui_args': [(self.product1, 10)], 'payments':[(self.cash_pm1, 100)], 'customer': self.customer, 'is_invoiced': True, 'uuid': '00100-010-0001'},
|
||||
{'pos_order_lines_ui_args': [(self.product1, 10)], 'payments':[(self.bank_pm1, 100)], 'customer': self.customer, 'is_invoiced': True, 'uuid': '00100-010-0002'},
|
||||
{'pos_order_lines_ui_args': [(self.product1, 10)], 'payments':[(self.cash_split_pm1, 100)], 'customer': self.customer, 'is_invoiced': True, 'uuid': '00100-010-0003'},
|
||||
{'pos_order_lines_ui_args': [(self.product1, 10)], 'payments':[(self.bank_split_pm1, 100)], 'customer': self.customer, 'is_invoiced': True, 'uuid': '00100-010-0004'},
|
||||
{'pos_order_lines_ui_args': [(self.product1, 10)], 'payments':[(self.cash_pm1, 100)], 'customer': self.customer, 'is_invoiced': False, 'uuid': '00100-010-0005'},
|
||||
{'pos_order_lines_ui_args': [(self.product1, 10)], 'payments':[(self.bank_pm1, 100)], 'customer': self.customer, 'is_invoiced': False, 'uuid': '00100-010-0006'},
|
||||
{'pos_order_lines_ui_args': [(self.product99, 1)], 'payments':[(self.cash_split_pm1, 99)], 'customer': self.customer, 'is_invoiced': False, 'uuid': '00100-010-0007'},
|
||||
{'pos_order_lines_ui_args': [(self.product99, 1)], 'payments':[(self.bank_split_pm1, 99)], 'customer': self.customer, 'is_invoiced': False, 'uuid': '00100-010-0008'},
|
||||
{'pos_order_lines_ui_args': [(self.product1, 10)], 'payments':[(self.bank_pm1, 100)], 'customer': self.other_customer, 'is_invoiced': True, 'uuid': '00100-010-0009'},
|
||||
{'pos_order_lines_ui_args': [(self.product1, 10)], 'payments':[(self.bank_pm1, 100)], 'customer': self.other_customer, 'is_invoiced': True, 'uuid': '00100-010-0010'},
|
||||
{'pos_order_lines_ui_args': [(self.product1, 10)], 'payments':[(self.bank_pm1, 100)], 'customer': self.customer, 'is_invoiced': True, 'uuid': '00100-010-0011'},
|
||||
],
|
||||
'journal_entries_before_closing': {
|
||||
'00100-010-0001': {
|
||||
|
|
@ -818,8 +823,21 @@ class TestPoSBasicConfig(TestPoSCommon):
|
|||
self.open_new_session(0)
|
||||
session = self.pos_session
|
||||
order_data = self.create_ui_order_data([(self.product3, 1)])
|
||||
amount_paid = order_data['data']['amount_paid']
|
||||
self.env['pos.order'].create_from_ui([order_data])
|
||||
amount_paid = order_data['amount_paid']
|
||||
with (
|
||||
self.assertLogs('odoo.addons.point_of_sale.models.pos_order', level='DEBUG') as cm,
|
||||
unittest.mock.patch('odoo.addons.point_of_sale.models.pos_order.randrange', return_value=1996)
|
||||
):
|
||||
res = self.env['pos.order'].sync_from_ui([order_data])
|
||||
# Basic check for logs on order synchronization
|
||||
order_log_str = self.env['pos.order']._get_order_log_representation(order_data)
|
||||
odoo_order_id = res['pos.order'][0]['id']
|
||||
self.assertEqual(len(cm.output), 4)
|
||||
self.assertEqual(cm.output[0], f"INFO:odoo.addons.point_of_sale.models.pos_order:PoS synchronisation #1996 started for PoS orders references: [{order_log_str}]")
|
||||
self.assertTrue(cm.output[1].startswith(f'DEBUG:odoo.addons.point_of_sale.models.pos_order:PoS synchronisation #1996 processing order {order_log_str} order full data: '))
|
||||
self.assertEqual(cm.output[2], f'INFO:odoo.addons.point_of_sale.models.pos_order:PoS synchronisation #1996 order {order_log_str} created pos.order #{odoo_order_id}')
|
||||
self.assertEqual(cm.output[3], 'INFO:odoo.addons.point_of_sale.models.pos_order:PoS synchronisation #1996 finished')
|
||||
|
||||
session.post_closing_cash_details(amount_paid)
|
||||
session.close_session_from_ui()
|
||||
|
||||
|
|
@ -840,13 +858,22 @@ class TestPoSBasicConfig(TestPoSCommon):
|
|||
|
||||
def open_and_check(pos_data):
|
||||
self.config = pos_data['config']
|
||||
self.open_new_session()
|
||||
self.open_new_session(pos_data['amount_paid'])
|
||||
session = self.pos_session
|
||||
session.set_cashbox_pos(pos_data['amount_paid'], False)
|
||||
self.assertEqual(session.cash_register_balance_start, pos_data['amount_paid'])
|
||||
|
||||
pos01_config = self.config
|
||||
pos02_config = pos01_config.copy()
|
||||
self.cash_journal = self.env['account.journal'].create(
|
||||
{'name': 'CASH journal', 'type': 'cash', 'code': 'CSH00'})
|
||||
self.cash_payment_method = self.env['pos.payment.method'].create({
|
||||
'name': 'Cash Test',
|
||||
'journal_id': self.cash_journal.id,
|
||||
'receivable_account_id': pos01_config.payment_method_ids.filtered(lambda s: s.is_cash_count)[
|
||||
1].receivable_account_id.id
|
||||
})
|
||||
pos02_config = pos01_config.copy({
|
||||
'payment_method_ids': self.cash_payment_method
|
||||
})
|
||||
pos01_data = {'config': pos01_config, 'p_qty': 1, 'amount_paid': 0}
|
||||
pos02_data = {'config': pos02_config, 'p_qty': 3, 'amount_paid': 0}
|
||||
|
||||
|
|
@ -855,8 +882,8 @@ class TestPoSBasicConfig(TestPoSCommon):
|
|||
session = self.pos_session
|
||||
|
||||
order_data = self.create_ui_order_data([(self.product3, pos_data['p_qty'])])
|
||||
pos_data['amount_paid'] += order_data['data']['amount_paid']
|
||||
self.env['pos.order'].create_from_ui([order_data])
|
||||
pos_data['amount_paid'] += order_data['amount_paid']
|
||||
self.env['pos.order'].sync_from_ui([order_data])
|
||||
|
||||
session.post_closing_cash_details(pos_data['amount_paid'])
|
||||
session.close_session_from_ui()
|
||||
|
|
@ -864,8 +891,26 @@ class TestPoSBasicConfig(TestPoSCommon):
|
|||
open_and_check(pos01_data)
|
||||
open_and_check(pos02_data)
|
||||
|
||||
def test_load_pos_data_should_not_fail(self):
|
||||
"""load_pos_data shouldn't fail
|
||||
def test_pos_session_name_sequencing(self):
|
||||
""" This test check if the session name is correctly set according to the sequence """
|
||||
|
||||
sequence = self.env['ir.sequence'].search([('code', '=', 'pos.session')])
|
||||
sequence.prefix = '/'
|
||||
sequence.write({'number_next_actual': 1000})
|
||||
name = self.config.name
|
||||
|
||||
self.open_new_session(0)
|
||||
self.assertEqual(self.pos_session.name, name + '/01000')
|
||||
|
||||
self.pos_session.close_session_from_ui()
|
||||
|
||||
sequence.prefix = 'TEST/'
|
||||
|
||||
self.open_new_session(0)
|
||||
self.assertEqual(self.pos_session.name, 'TEST/01001')
|
||||
|
||||
def test_load_data_should_not_fail(self):
|
||||
"""load_data shouldn't fail
|
||||
|
||||
(Include test conditions here if possible)
|
||||
|
||||
|
|
@ -879,12 +924,23 @@ class TestPoSBasicConfig(TestPoSCommon):
|
|||
'company_id': company2.id,
|
||||
})
|
||||
|
||||
# activate limited partners loading
|
||||
self.config.limited_partners_loading = True
|
||||
self.open_new_session()
|
||||
|
||||
# calling load_pos_data should not raise an error
|
||||
self.pos_session.load_pos_data()
|
||||
# calling load_data should not raise an error
|
||||
self.pos_session.load_data([])
|
||||
|
||||
def test_load_data_picks_the_company_website_domain(self):
|
||||
if self.env['ir.module.module']._get('website').state != 'installed':
|
||||
self.skipTest("website module is required for this test")
|
||||
|
||||
company_website = self.config.company_id.website_id
|
||||
|
||||
if company_website:
|
||||
company_website.write({'domain': 'https://custom.test.domain.com'})
|
||||
self.open_new_session()
|
||||
response = self.pos_session.load_data([])
|
||||
|
||||
self.assertEqual(response['pos.config'][0]['_base_url'], company_website.domain)
|
||||
|
||||
def test_invoice_past_refund(self):
|
||||
""" Test invoicing a past refund
|
||||
|
|
@ -912,7 +968,7 @@ class TestPoSBasicConfig(TestPoSCommon):
|
|||
"""
|
||||
def _before_closing_cb():
|
||||
# Return the order
|
||||
order_to_return = self.pos_session.order_ids.filtered(lambda order: '12345-123-1234' in order.pos_reference)
|
||||
order_to_return = self.pos_session.order_ids.filtered(lambda order: '12345-123-1234' in order.uuid)
|
||||
order_to_return.refund()
|
||||
refund_order = self.pos_session.order_ids.filtered(lambda order: order.state == 'draft')
|
||||
|
||||
|
|
@ -930,7 +986,7 @@ class TestPoSBasicConfig(TestPoSCommon):
|
|||
self._run_test({
|
||||
'payment_methods': self.cash_pm1 | self.bank_pm1,
|
||||
'orders': [
|
||||
{'pos_order_lines_ui_args': [(self.product3, 1)], 'payments': [(self.cash_pm1, 30)], 'uid': '12345-123-1234'},
|
||||
{'pos_order_lines_ui_args': [(self.product3, 1)], 'payments': [(self.cash_pm1, 30)], 'uuid': '12345-123-1234'},
|
||||
],
|
||||
'before_closing_cb': _before_closing_cb,
|
||||
'journal_entries_before_closing': {},
|
||||
|
|
@ -962,7 +1018,7 @@ class TestPoSBasicConfig(TestPoSCommon):
|
|||
# Check the credit note
|
||||
self.assertTrue(return_to_invoice.account_move, 'Invoice should be created.')
|
||||
self.assertEqual(return_to_invoice.account_move.move_type, 'out_refund', 'Invoice should be a credit note.')
|
||||
self.assertEqual(return_to_invoice.account_move.invoice_date, new_session_date, 'Invoice date should be the same as the session it is created in.')
|
||||
self.assertEqual(return_to_invoice.account_move.invoice_date, new_session_date.date(), 'Invoice date should be the same as the session it is created in.')
|
||||
self.assertRecordValues(return_to_invoice.account_move, [{
|
||||
'amount_untaxed': 30,
|
||||
'amount_tax': 0,
|
||||
|
|
@ -978,7 +1034,7 @@ class TestPoSBasicConfig(TestPoSCommon):
|
|||
self._run_test({
|
||||
'payment_methods': self.cash_pm1 | self.bank_pm1,
|
||||
'orders': [
|
||||
{'pos_order_lines_ui_args': [(self.product99, 1)], 'payments': [(self.bank_pm1, 99)], 'customer': False, 'is_invoiced': False, 'uid': '00100-010-0001'},
|
||||
{'pos_order_lines_ui_args': [(self.product99, 1)], 'payments': [(self.bank_pm1, 99)], 'customer': False, 'is_invoiced': False, 'uuid': '00100-010-0001'},
|
||||
],
|
||||
'journal_entries_before_closing': {},
|
||||
'journal_entries_after_closing': {
|
||||
|
|
@ -1030,24 +1086,24 @@ class TestPoSBasicConfig(TestPoSCommon):
|
|||
self._run_test({
|
||||
'payment_methods': self.cash_pm1 | self.bank_pm1,
|
||||
'orders': [
|
||||
{'pos_order_lines_ui_args': [(self.product_multi_tax, 1)], 'payments': [(self.bank_pm1, 117.7)], 'customer': False, 'is_invoiced': False, 'uid': '00100-010-0001'},
|
||||
{'pos_order_lines_ui_args': [(self.product_multi_tax, 1)], 'payments': [(self.bank_pm1, 117.72)], 'customer': False, 'is_invoiced': False, 'uuid': '00100-010-0001'},
|
||||
],
|
||||
'journal_entries_before_closing': {},
|
||||
'journal_entries_after_closing': {
|
||||
'session_journal_entry': {
|
||||
'line_ids': [
|
||||
{'account_id': self.tax_received_account.id, 'partner_id': False, 'debit': 0, 'credit': 7, 'reconciled': False},
|
||||
{'account_id': self.tax_received_account.id, 'partner_id': False, 'debit': 0, 'credit': 10.7, 'reconciled': False},
|
||||
{'account_id': self.tax_received_account.id, 'partner_id': False, 'debit': 0, 'credit': 8, 'reconciled': False},
|
||||
{'account_id': self.tax_received_account.id, 'partner_id': False, 'debit': 0, 'credit': 9.72, 'reconciled': False},
|
||||
{'account_id': self.sales_account.id, 'partner_id': False, 'debit': 0, 'credit': 100, 'reconciled': False},
|
||||
{'account_id': self.bank_pm1.receivable_account_id.id, 'partner_id': False, 'debit': 117.7, 'credit': 0, 'reconciled': True},
|
||||
{'account_id': self.bank_pm1.receivable_account_id.id, 'partner_id': False, 'debit': 117.72, 'credit': 0, 'reconciled': True},
|
||||
],
|
||||
},
|
||||
'cash_statement': [],
|
||||
'bank_payments': [
|
||||
((117.7, ), {
|
||||
((117.72, ), {
|
||||
'line_ids': [
|
||||
{'account_id': self.bank_pm1.outstanding_account_id.id, 'partner_id': False, 'debit': 117.7, 'credit': 0, 'reconciled': False},
|
||||
{'account_id': self.bank_pm1.receivable_account_id.id, 'partner_id': False, 'debit': 0, 'credit': 117.7, 'reconciled': True},
|
||||
{'account_id': self.bank_pm1.outstanding_account_id.id, 'partner_id': False, 'debit': 117.72, 'credit': 0, 'reconciled': False},
|
||||
{'account_id': self.bank_pm1.receivable_account_id.id, 'partner_id': False, 'debit': 0, 'credit': 117.72, 'reconciled': True},
|
||||
]
|
||||
})
|
||||
],
|
||||
|
|
@ -1069,7 +1125,376 @@ class TestPoSBasicConfig(TestPoSCommon):
|
|||
self.assertTrue(order_to_invoice.account_move, 'Invoice should be created.')
|
||||
self.assertRecordValues(order_to_invoice.account_move.line_ids, [
|
||||
{'account_id': self.sales_account.id, 'balance': -100, 'reconciled': False},
|
||||
{'account_id': self.tax_received_account.id, 'balance': -7, 'reconciled': False},
|
||||
{'account_id': self.tax_received_account.id, 'balance': -10.7, 'reconciled': False},
|
||||
{'account_id': self.receivable_account.id, 'balance': 117.7, 'reconciled': True},
|
||||
{'account_id': self.tax_received_account.id, 'balance': -8, 'reconciled': False},
|
||||
{'account_id': self.tax_received_account.id, 'balance': -9.72, 'reconciled': False},
|
||||
{'account_id': self.receivable_account.id, 'balance': 117.72, 'reconciled': True},
|
||||
])
|
||||
|
||||
def test_limited_products_loading(self):
|
||||
self.env['ir.config_parameter'].sudo().set_param('point_of_sale.limited_product_count', 3)
|
||||
|
||||
# Make the service products that are available in the pos inactive.
|
||||
# We don't need them to test the loading of 'consu' products.
|
||||
self.env['product.template'].search([('available_in_pos', '=', True), ('type', '=', 'service')]).write({'available_in_pos': False})
|
||||
|
||||
session = self.open_new_session(0)
|
||||
self.product1.write({'company_id': False})
|
||||
self.product2.write({'company_id': False})
|
||||
self.product3.write({'company_id': False})
|
||||
|
||||
def get_top_product_ids(count):
|
||||
data = session.load_data([])
|
||||
special_product = session.config_id._get_special_products().ids
|
||||
available_top_product = [product for product in data['product.template'] if product['product_variant_ids'][0] not in special_product]
|
||||
return [p['product_variant_ids'][0] for p in available_top_product[:count]]
|
||||
|
||||
self.patch(self.env.cr, 'now', lambda: datetime.now() + timedelta(days=1))
|
||||
self.env['pos.order'].sync_from_ui([self.create_ui_order_data([(self.product1, 1)])])
|
||||
self.assertEqual(get_top_product_ids(1), [self.product1.id])
|
||||
|
||||
self.patch(self.env.cr, 'now', lambda: datetime.now() + timedelta(days=2))
|
||||
self.env['pos.order'].sync_from_ui([self.create_ui_order_data([(self.product2, 1)])])
|
||||
self.assertEqual(get_top_product_ids(2), [self.product1.id, self.product2.id])
|
||||
|
||||
self.patch(self.env.cr, 'now', lambda: datetime.now() + timedelta(days=3))
|
||||
self.env['pos.order'].sync_from_ui([self.create_ui_order_data([(self.product3, 1)])])
|
||||
self.assertEqual(get_top_product_ids(3), [self.product1.id, self.product2.id, self.product3.id])
|
||||
|
||||
def test_closing_entry_by_product(self):
|
||||
# set the Group by Product at Closing Entry
|
||||
self.config.is_closing_entry_by_product = True
|
||||
self.open_new_session()
|
||||
|
||||
# 4 orders
|
||||
|
||||
# Orders
|
||||
# ======
|
||||
# +---------+----------+---------------+----------+-----+-------+
|
||||
# | order | payments | invoiced? | product | qty | total |
|
||||
# +---------+----------+---------------+----------+-----+-------+
|
||||
# | order 1 | bank | no | product1 | 2 | 60 |
|
||||
# | | | | product4 | 3 | 39.84 |
|
||||
# +---------+----------+---------------+----------+-----+-------+
|
||||
# | order 2 | bank | yes | product4 | 1 | 29.88 |
|
||||
# | | | | product2 | 5 | 400 |
|
||||
# +---------+----------+---------------+----------+-----+-------+
|
||||
# | order 3 | bank | yes | product1 | 3 | 29.88 |
|
||||
# | | | | product2 | 10 | 400 |
|
||||
# +---------+----------+---------------+----------+-----+-------+
|
||||
# | order 4 | bank | yes | product1 | 5 | 29.88 |
|
||||
# | | | | product0 | 10| 400 |
|
||||
# +---------+----------+---------------+----------+-----+-------+
|
||||
|
||||
# Expected Output
|
||||
# +---------------+-----------+
|
||||
# | invoice_line | Quantity |
|
||||
# +---------------+-----------+
|
||||
# | Product 0 | 10 |
|
||||
# +---------------+-----------+
|
||||
# | Product 1 | 10 |
|
||||
# +---------------+-----------+
|
||||
# | Product 2 | 15 |
|
||||
# +---------------+-----------+
|
||||
# | Product 4 | 4 |
|
||||
# +---------------+-----------+
|
||||
|
||||
# create orders
|
||||
orders = []
|
||||
|
||||
# create orders
|
||||
orders = []
|
||||
orders.append(self.create_ui_order_data(
|
||||
[(self.product1, 2), (self.product4, 3)],
|
||||
payments=[(self.bank_pm1, 49.88)]
|
||||
))
|
||||
orders.append(self.create_ui_order_data(
|
||||
[(self.product4, 1), (self.product2, 5)],
|
||||
payments=[(self.bank_pm1, 109.96)]
|
||||
))
|
||||
orders.append(self.create_ui_order_data(
|
||||
[(self.product1, 3), (self.product2, 10)],
|
||||
payments=[(self.bank_pm1, 230)]
|
||||
))
|
||||
orders.append(self.create_ui_order_data(
|
||||
[(self.product1, 5), (self.product0, 10)],
|
||||
payments=[(self.bank_pm1, 50)]
|
||||
))
|
||||
|
||||
# sync orders
|
||||
self.env['pos.order'].sync_from_ui(orders)
|
||||
# close the session
|
||||
self.pos_session.action_pos_session_validate()
|
||||
|
||||
# check values after the session is closed
|
||||
session_account_move = self.pos_session.move_id
|
||||
|
||||
# Define expected quantities for each product
|
||||
expected_product_quantity = {
|
||||
self.product0: 10,
|
||||
self.product1: 10,
|
||||
self.product2: 15,
|
||||
self.product4: 4,
|
||||
}
|
||||
# Iterate through invoice lines and assert the expected quantities
|
||||
for i in session_account_move.line_ids:
|
||||
if i.product_id and expected_product_quantity.get(i.product_id):
|
||||
self.assertEqual(i.quantity, expected_product_quantity.get(i.product_id), f"Unexpected quantity for {i.product_id.name}")
|
||||
|
||||
def test_pos_payment_method_copy(self):
|
||||
"""
|
||||
Test POS payment method copy:
|
||||
- Create two payment methods in which one of the payment method's journal type be cash
|
||||
- Copy multiple payment methods
|
||||
- Check the duplicated cash payment method journal should be empty
|
||||
"""
|
||||
pm_1 = self.cash_pm1
|
||||
pm_2 = self.bank_pm1
|
||||
pm_3, pm_4 = (pm_1 + pm_2).copy()
|
||||
|
||||
self.assertTrue(pm_3)
|
||||
self.assertFalse(pm_3.journal_id)
|
||||
self.assertTrue(pm_4)
|
||||
self.assertEqual(pm_4.journal_id.type, "bank")
|
||||
|
||||
def test_single_config_global_invoice(self):
|
||||
"""For a single POS config, create multiple orders and consolidate them into a single invoice"""
|
||||
self.open_new_session()
|
||||
# create orders
|
||||
orders = []
|
||||
orders.append(self.create_ui_order_data(
|
||||
[(self.product1, 2), (self.product4, 3)],
|
||||
payments=[(self.bank_pm1, 49.88)]
|
||||
))
|
||||
orders.append(self.create_ui_order_data(
|
||||
[(self.product4, 1), (self.product2, 5)],
|
||||
payments=[(self.bank_pm1, 109.96)]
|
||||
))
|
||||
|
||||
# sync orders
|
||||
self.env['pos.order'].sync_from_ui(orders)
|
||||
# close the session
|
||||
self.pos_session.action_pos_session_validate()
|
||||
|
||||
pos_orders = self.env['pos.order'].search([])
|
||||
# set customer for the orders
|
||||
pos_orders.write({'partner_id': self.customer.id})
|
||||
|
||||
# create consolidated invoice
|
||||
self.env['pos.make.invoice'].create({"consolidated_billing": True}).with_context({"active_ids": pos_orders.ids}).action_create_invoices()
|
||||
# check if have single invoice
|
||||
self.assertEqual(len(pos_orders), 2)
|
||||
self.assertEqual(len(pos_orders.account_move), 1)
|
||||
self.assertEqual(pos_orders.account_move.partner_id, self.customer)
|
||||
self.assertEqual(pos_orders.account_move.amount_total, sum(pos_orders.mapped('amount_total')))
|
||||
self.assertEqual(pos_orders.account_move.payment_state, 'paid')
|
||||
self.assertEqual(pos_orders.account_move.state, 'posted')
|
||||
|
||||
def test_multi_config_global_invoice(self):
|
||||
self.open_new_session()
|
||||
orders = []
|
||||
orders.append(self.create_ui_order_data(
|
||||
[(self.product1, 3), (self.product2, 10)],
|
||||
payments=[(self.bank_pm1, 230)]
|
||||
))
|
||||
orders.append(self.create_ui_order_data(
|
||||
[(self.product1, 5), (self.product0, 10)],
|
||||
payments=[(self.bank_pm1, 50)]
|
||||
))
|
||||
self.env['pos.order'].sync_from_ui(orders)
|
||||
self.pos_session.action_pos_session_validate()
|
||||
|
||||
# open new session & create orders
|
||||
self.open_new_session()
|
||||
orders2 = []
|
||||
orders2.append(self.create_ui_order_data(
|
||||
[(self.product1, 2), (self.product4, 3)],
|
||||
payments=[(self.bank_pm1, 49.88)]
|
||||
))
|
||||
orders2.append(self.create_ui_order_data(
|
||||
[(self.product4, 1), (self.product2, 5)],
|
||||
payments=[(self.bank_pm1, 109.96)]
|
||||
))
|
||||
self.env['pos.order'].sync_from_ui(orders2)
|
||||
self.pos_session.action_pos_session_validate()
|
||||
|
||||
pos_orders = self.env['pos.order'].search([])
|
||||
# set customer for the orders
|
||||
pos_orders.write({'partner_id': self.customer.id})
|
||||
|
||||
# create consolidated invoice
|
||||
self.env['pos.make.invoice'].create({"consolidated_billing": True}).with_context({"active_ids": pos_orders.ids}).action_create_invoices()
|
||||
# check if have single invoice
|
||||
self.assertEqual(len(pos_orders), 4)
|
||||
self.assertEqual(len(pos_orders.account_move), 1)
|
||||
self.assertEqual(pos_orders.account_move.partner_id, self.customer)
|
||||
self.assertEqual(pos_orders.account_move.amount_total, round(sum(pos_orders.mapped('amount_total')), 2))
|
||||
self.assertEqual(pos_orders.account_move.payment_state, 'paid')
|
||||
self.assertEqual(pos_orders.account_move.state, 'posted')
|
||||
|
||||
def test_double_syncing_same_order(self):
|
||||
""" Test that double syncing the same order doesn't create duplicates records
|
||||
"""
|
||||
self.open_new_session()
|
||||
|
||||
# Create an order
|
||||
order_data = self.create_ui_order_data([(self.product1, 1)], payments=[(self.cash_pm1, 10)], customer=self.customer, is_invoiced=True)
|
||||
order_data['access_token'] = '0123456789'
|
||||
res = self.env['pos.order'].sync_from_ui([order_data])
|
||||
order_id = res['pos.order'][0]['id']
|
||||
|
||||
# Sync the same order again
|
||||
res = self.env['pos.order'].sync_from_ui([order_data])
|
||||
self.assertEqual(res['pos.order'][0]['id'], order_id, 'Syncing the same order should not create a new one')
|
||||
|
||||
order = self.env['pos.order'].browse(order_id)
|
||||
self.assertEqual(order.picking_count, 1, 'Order should have one picking')
|
||||
self.assertEqual(len(order.payment_ids), 1, 'Order should have one payment')
|
||||
self.assertEqual(self.env['account.move'].search_count([('pos_order_ids', 'in', order.ids)]), 1, 'Order should have one invoice')
|
||||
|
||||
def test_pos_archived_combination(self):
|
||||
product = self.env['product.template'].create({
|
||||
'name': 'Product Test',
|
||||
'available_in_pos': True,
|
||||
'list_price': 10,
|
||||
'taxes_id': False,
|
||||
})
|
||||
|
||||
attribute_1, attribute_2, attribute_3 = self.env['product.attribute'].create([{
|
||||
'name': 'Attribute 1',
|
||||
'create_variant': 'always',
|
||||
'value_ids': [(0, 0, {
|
||||
'name': 'Value 1',
|
||||
}), (0, 0, {
|
||||
'name': 'Value 2',
|
||||
})],
|
||||
}, {
|
||||
'name': 'Attribute 2',
|
||||
'create_variant': 'always',
|
||||
'value_ids': [(0, 0, {
|
||||
'name': 'Value 1',
|
||||
}), (0, 0, {
|
||||
'name': 'Value 2',
|
||||
})],
|
||||
}, {
|
||||
'name': 'Attribute 3',
|
||||
'create_variant': 'always',
|
||||
'value_ids': [(0, 0, {
|
||||
'name': 'Value 1',
|
||||
}), (0, 0, {
|
||||
'name': 'Value 2',
|
||||
})],
|
||||
}])
|
||||
|
||||
_, _, ptal = self.env['product.template.attribute.line'].create([{
|
||||
'product_tmpl_id': product.id,
|
||||
'attribute_id': attribute_1.id,
|
||||
'value_ids': [(6, 0, attribute_1.value_ids.ids)],
|
||||
'sequence': 3,
|
||||
}, {
|
||||
'product_tmpl_id': product.id,
|
||||
'attribute_id': attribute_2.id,
|
||||
'value_ids': [(6, 0, attribute_2.value_ids.ids)],
|
||||
'sequence': 2,
|
||||
}, {
|
||||
'product_tmpl_id': product.id,
|
||||
'attribute_id': attribute_3.id,
|
||||
'value_ids': [(6, 0, attribute_3.value_ids.ids)],
|
||||
'sequence': 1,
|
||||
}])
|
||||
|
||||
product.write({
|
||||
'attribute_line_ids': [(2, ptal.id)],
|
||||
})
|
||||
|
||||
self.open_new_session()
|
||||
response = self.pos_session.load_data([])
|
||||
product_data = next((item for item in response['product.template'] if item['id'] == product.id), None)
|
||||
|
||||
self.assertEqual(len(product_data['_archived_combinations']), 0, "There should be no archived combinations for the product")
|
||||
|
||||
first_variant = product.product_variant_ids[0]
|
||||
first_variant.write({'active': False})
|
||||
|
||||
response = self.pos_session.load_data([])
|
||||
product_data = next((item for item in response['product.template'] if item['id'] == product.id), None)
|
||||
|
||||
self.assertEqual(len(product_data['_archived_combinations']), 1, "There should be one archived combination for the product")
|
||||
self.assertEqual(len(product_data['_archived_combinations'][0]), 2, "Archived combination should have two values")
|
||||
self.assertTrue(all(value in product_data['_archived_combinations'][0] for value in first_variant.product_template_attribute_value_ids.ids), "Archived combination should match the first variant's attribute values")
|
||||
|
||||
def test_refunded_order_id(self):
|
||||
"""
|
||||
An order containing refunded lines from two different orders is no longer allowed,
|
||||
but some legacy records of this kind may still exist.
|
||||
This test ensures that the refunded_order_id is correctly computed in such cases.
|
||||
"""
|
||||
current_session = self.open_new_session()
|
||||
orders = list(self._create_orders([
|
||||
{'pos_order_lines_ui_args': [(self.product1, 1)]},
|
||||
{'pos_order_lines_ui_args': [(self.product2, 1)]}
|
||||
]).values())
|
||||
|
||||
refund_order = self.env['pos.order'].create({
|
||||
'company_id': self.env.company.id,
|
||||
'session_id': current_session.id,
|
||||
'lines': [
|
||||
(0, 0, {
|
||||
'product_id': self.product1.id,
|
||||
'price_unit': -10,
|
||||
'qty': 1,
|
||||
'tax_ids': [[6, False, []]],
|
||||
'price_subtotal': -10,
|
||||
'price_subtotal_incl': -10,
|
||||
'refunded_orderline_id': orders[0].lines[0].id
|
||||
}),
|
||||
(0, 0, {
|
||||
'product_id': self.product2.id,
|
||||
'price_unit': -10,
|
||||
'qty': 1,
|
||||
'tax_ids': [[6, False, []]],
|
||||
'price_subtotal': -10,
|
||||
'price_subtotal_incl': -10,
|
||||
'refunded_orderline_id': orders[1].lines[0].id
|
||||
})
|
||||
],
|
||||
'amount_paid': -10,
|
||||
'amount_total': -10,
|
||||
'amount_tax': 0.0,
|
||||
'amount_return': 0.0,
|
||||
})
|
||||
|
||||
self.assertEqual(refund_order.refunded_order_id, orders[0])
|
||||
|
||||
def test_cannot_archive_journal_linked_to_pos_payment_method(self):
|
||||
"""Test that archiving a journal linked to a POS payment method is blocked, and allowed when not linked."""
|
||||
|
||||
test_journal = self.env['account.journal'].create({
|
||||
'name': 'Test POS Journal',
|
||||
'type': 'cash',
|
||||
'code': 'TPJ',
|
||||
'company_id': self.env.company.id,
|
||||
})
|
||||
test_payment_method = self.env['pos.payment.method'].create({
|
||||
'name': 'Test PM',
|
||||
'journal_id': test_journal.id,
|
||||
'receivable_account_id': self.cash_pm1.receivable_account_id.id,
|
||||
})
|
||||
|
||||
with self.assertRaises(ValidationError):
|
||||
test_journal.action_archive()
|
||||
|
||||
# Unlink the payment method and try again (should succeed)
|
||||
test_payment_method.journal_id = False
|
||||
test_journal.action_archive()
|
||||
self.assertFalse(test_journal.active, "Journal should be archived when not linked to a POS payment method.")
|
||||
|
||||
def test_archive_delete_special_product(self):
|
||||
special_product = self.env.ref('point_of_sale.product_product_tip')
|
||||
with self.assertRaisesRegex(UserError, "You cannot archive a product that is set as a special product in a Point of Sale configuration. Please change the configuration first."):
|
||||
special_product.action_archive()
|
||||
with self.assertRaisesRegex(UserError, "You cannot archive a product that is set as a special product in a Point of Sale configuration. Please change the configuration first."):
|
||||
special_product.product_variant_ids[0].action_archive()
|
||||
with self.assertRaisesRegex(UserError, "You cannot archive a product that is set as a special product in a Point of Sale configuration. Please change the configuration first."):
|
||||
special_product.unlink()
|
||||
with self.assertRaisesRegex(UserError, "You cannot archive a product that is set as a special product in a Point of Sale configuration. Please change the configuration first."):
|
||||
special_product.product_variant_ids[0].unlink()
|
||||
|
|
|
|||
|
|
@ -1,173 +0,0 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
import logging
|
||||
from unittest.mock import patch
|
||||
|
||||
import odoo
|
||||
from odoo.addons.point_of_sale.models.pos_order import PosOrder
|
||||
from odoo.addons.point_of_sale.models.pos_session import PosSession
|
||||
from odoo.addons.point_of_sale.tests.common import TestPoSCommon
|
||||
|
||||
|
||||
class IntendedException(Exception):
|
||||
pass
|
||||
|
||||
|
||||
def mocked_process_order(*args):
|
||||
# We just want the order process to crash (to see if it is captured)
|
||||
raise IntendedException()
|
||||
|
||||
|
||||
def mocked_handle_order_process_fail(self, order: dict, exception: Exception, draft: bool):
|
||||
# We DO NOT want to create a new env in the test as the current pos_session does not exist (as it was not committed)
|
||||
self._process_order_process_fail(order, exception)
|
||||
|
||||
|
||||
@odoo.tests.tagged('post_install', '-at_install')
|
||||
class TestPosCapture(TestPoSCommon):
|
||||
"""
|
||||
Test the capture system of failed to process orders
|
||||
"""
|
||||
|
||||
def setUp(self):
|
||||
super(TestPosCapture, self).setUp()
|
||||
self.config = self.basic_config
|
||||
|
||||
self.product1 = self.create_product('Product 1', self.categ_basic, 10, 5)
|
||||
|
||||
def assert_activity_and_attachment(self, pos_session, number):
|
||||
pos_attachments_domain = [
|
||||
['res_model', '=', pos_session._name],
|
||||
['res_id', '=', pos_session.id]
|
||||
]
|
||||
self.assertEqual(len(pos_session.activity_ids), number)
|
||||
self.assertEqual(len(self.env['ir.attachment'].search(pos_attachments_domain)), number)
|
||||
|
||||
def test_capture_one_order(self):
|
||||
# open a session
|
||||
session = self.open_new_session()
|
||||
|
||||
orders = [self.create_ui_order_data([(self.product1, 1)])]
|
||||
|
||||
self.assert_activity_and_attachment(session, 0)
|
||||
with patch.object(PosOrder, '_process_order', mocked_process_order),\
|
||||
patch.object(PosSession, '_handle_order_process_fail', mocked_handle_order_process_fail),\
|
||||
self.assertLogs('odoo.addons.point_of_sale.models.pos_order', level=logging.ERROR) as logger_error_output:
|
||||
try:
|
||||
self.env['pos.order'].create_from_ui(orders)
|
||||
except IntendedException:
|
||||
self.assertIn("An error occurred when processing the PoS order", logger_error_output.output[0])
|
||||
self.assert_activity_and_attachment(session, 1)
|
||||
self.assertEqual(session.activity_ids[0].user_id.id, self.env.user.id)
|
||||
|
||||
def test_capture_two_orders(self):
|
||||
"""Two order even with same content should have distinct captured file"""
|
||||
# open a session
|
||||
session = self.open_new_session()
|
||||
|
||||
order1 = [self.create_ui_order_data([(self.product1, 1)], uid='12345-678-1996')]
|
||||
order2 = [self.create_ui_order_data([(self.product1, 1)], uid='12345-678-1999')] # Different order with same content but different uuid
|
||||
|
||||
with patch.object(PosOrder, '_process_order', mocked_process_order),\
|
||||
patch.object(PosSession, '_handle_order_process_fail', mocked_handle_order_process_fail),\
|
||||
self.assertLogs('odoo.addons.point_of_sale.models.pos_order', level=logging.ERROR):
|
||||
try:
|
||||
self.env['pos.order'].create_from_ui(order1)
|
||||
except IntendedException:
|
||||
self.assert_activity_and_attachment(session, 1)
|
||||
|
||||
try:
|
||||
self.env['pos.order'].create_from_ui(order2)
|
||||
except IntendedException:
|
||||
self.assert_activity_and_attachment(session, 2)
|
||||
|
||||
def test_capture_one_order_twice(self):
|
||||
"""Should have only one attachment as we sync the same order twice"""
|
||||
# open a session
|
||||
session = self.open_new_session()
|
||||
|
||||
orders = [self.create_ui_order_data([(self.product1, 1)])]
|
||||
|
||||
self.assert_activity_and_attachment(session, 0)
|
||||
with patch.object(PosOrder, '_process_order', mocked_process_order),\
|
||||
patch.object(PosSession, '_handle_order_process_fail', mocked_handle_order_process_fail),\
|
||||
self.assertLogs('odoo.addons.point_of_sale.models.pos_order', level=logging.ERROR):
|
||||
for _ in range(2):
|
||||
try:
|
||||
self.env['pos.order'].create_from_ui(orders)
|
||||
except IntendedException:
|
||||
self.assert_activity_and_attachment(session, 1)
|
||||
|
||||
def test_capture_order_same_uuid(self):
|
||||
"""Should have 2 attachments as the content is different"""
|
||||
# open a session
|
||||
session = self.open_new_session()
|
||||
|
||||
order1 = [self.create_ui_order_data([(self.product1, 1)], uid='12345-678-1996')]
|
||||
order2 = [self.create_ui_order_data([(self.product1, 2)], uid='12345-678-1996')]
|
||||
|
||||
self.assert_activity_and_attachment(session, 0)
|
||||
with patch.object(PosOrder, '_process_order', mocked_process_order),\
|
||||
patch.object(PosSession, '_handle_order_process_fail', mocked_handle_order_process_fail),\
|
||||
self.assertLogs('odoo.addons.point_of_sale.models.pos_order', level=logging.ERROR):
|
||||
try:
|
||||
self.env['pos.order'].create_from_ui(order1)
|
||||
except IntendedException:
|
||||
self.assert_activity_and_attachment(session, 1)
|
||||
|
||||
try:
|
||||
self.env['pos.order'].create_from_ui(order2)
|
||||
except IntendedException:
|
||||
self.assert_activity_and_attachment(session, 2)
|
||||
|
||||
def test_capture_one_order_and_removed(self):
|
||||
"""Check if the attachment and activity is automatically remove after the order sync"""
|
||||
# open a session
|
||||
session = self.open_new_session()
|
||||
|
||||
orders = [self.create_ui_order_data([(self.product1, 1)])]
|
||||
|
||||
self.assert_activity_and_attachment(session, 0)
|
||||
with patch.object(PosOrder, '_process_order', mocked_process_order),\
|
||||
patch.object(PosSession, '_handle_order_process_fail', mocked_handle_order_process_fail),\
|
||||
self.assertLogs('odoo.addons.point_of_sale.models.pos_order', level=logging.ERROR):
|
||||
try:
|
||||
self.env['pos.order'].create_from_ui(orders)
|
||||
except IntendedException:
|
||||
pass
|
||||
|
||||
self.assert_activity_and_attachment(session, 1)
|
||||
# Resync the order, this time it should go through!
|
||||
self.env['pos.order'].create_from_ui(orders)
|
||||
# Should automatically remove the attachment for this order after sync
|
||||
self.assert_activity_and_attachment(session, 0)
|
||||
|
||||
def test_capture_two_orders_and_removed(self):
|
||||
"""Check if the attachment and activity is automatically remove after the order sync (with 2 orders)"""
|
||||
# open a session
|
||||
session = self.open_new_session()
|
||||
|
||||
order1 = [self.create_ui_order_data([(self.product1, 1)], uid='12345-678-1996')]
|
||||
order2 = [self.create_ui_order_data([(self.product1, 1)], uid='12345-678-1999')] # Different order with same content but different uuid
|
||||
|
||||
with patch.object(PosOrder, '_process_order', mocked_process_order),\
|
||||
patch.object(PosSession, '_handle_order_process_fail', mocked_handle_order_process_fail),\
|
||||
self.assertLogs('odoo.addons.point_of_sale.models.pos_order', level=logging.ERROR):
|
||||
try:
|
||||
self.env['pos.order'].create_from_ui(order1)
|
||||
except IntendedException:
|
||||
self.assert_activity_and_attachment(session, 1)
|
||||
|
||||
try:
|
||||
self.env['pos.order'].create_from_ui(order2)
|
||||
except IntendedException:
|
||||
self.assert_activity_and_attachment(session, 2)
|
||||
|
||||
self.assert_activity_and_attachment(session, 2)
|
||||
# Resync the order, this time it should go through!
|
||||
self.env['pos.order'].create_from_ui(order2)
|
||||
# Should automatically remove the attachment for this order after sync
|
||||
self.assert_activity_and_attachment(session, 1)
|
||||
|
||||
self.env['pos.order'].create_from_ui(order1)
|
||||
# Should automatically remove the attachment for this order after sync
|
||||
self.assert_activity_and_attachment(session, 0)
|
||||
|
|
@ -0,0 +1,184 @@
|
|||
from odoo import Command
|
||||
from odoo.addons.point_of_sale.tests.test_frontend import TestPointOfSaleHttpCommon
|
||||
from odoo.tests import tagged
|
||||
|
||||
|
||||
@tagged('post_install', '-at_install')
|
||||
class TestPosCashRounding(TestPointOfSaleHttpCommon):
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
super().setUpClass()
|
||||
cls.partner_a.name = "AAAAAA" # The POS only load the first 100 partners
|
||||
cls.cash_rounding_add_invoice_line = cls.env['account.cash.rounding'].create({
|
||||
'name': "cash_rounding_add_invoice_line",
|
||||
'rounding': 0.05,
|
||||
'rounding_method': 'HALF-UP',
|
||||
'strategy': 'add_invoice_line',
|
||||
'profit_account_id': cls.env.company.default_cash_difference_income_account_id.id,
|
||||
'loss_account_id': cls.env.company.default_cash_difference_expense_account_id.id,
|
||||
})
|
||||
cls.cash_rounding_biggest_tax = cls.env['account.cash.rounding'].create({
|
||||
'name': "cash_rounding_biggest_tax",
|
||||
'rounding': 0.05,
|
||||
'rounding_method': 'HALF-UP',
|
||||
'strategy': 'biggest_tax',
|
||||
'profit_account_id': cls.env.company.default_cash_difference_income_account_id.id,
|
||||
'loss_account_id': cls.env.company.default_cash_difference_expense_account_id.id,
|
||||
})
|
||||
|
||||
cls.product = cls.env['product.product'].create({
|
||||
'name': "random_product",
|
||||
'available_in_pos': True,
|
||||
'list_price': 13.67,
|
||||
'taxes_id': [Command.set(cls.company_data['default_tax_sale'].ids)],
|
||||
'pos_categ_ids': [Command.set(cls.pos_desk_misc_test.ids)],
|
||||
})
|
||||
|
||||
def test_cash_rounding_halfup_biggest_tax_not_only_round_cash_method(self):
|
||||
self.skipTest('To re-introduce when feature is ready')
|
||||
self.main_pos_config.write({
|
||||
'rounding_method': self.cash_rounding_biggest_tax.id,
|
||||
'cash_rounding': True,
|
||||
'only_round_cash_method': False,
|
||||
})
|
||||
with self.with_new_session(user=self.pos_user) as session:
|
||||
self.start_pos_tour('test_cash_rounding_halfup_biggest_tax_not_only_round_cash_method')
|
||||
refund, order = self.env['pos.order'].search([('session_id', '=', session.id)], limit=2)
|
||||
self.assertRecordValues(order, [{
|
||||
'amount_tax': 2.03,
|
||||
'amount_total': 15.7,
|
||||
'amount_paid': 15.7,
|
||||
}])
|
||||
self.assertRecordValues(order.account_move, [{
|
||||
'amount_untaxed': 13.67,
|
||||
'amount_tax': 2.03,
|
||||
'amount_total': 15.7,
|
||||
}])
|
||||
self.assertRecordValues(refund, [{
|
||||
'amount_tax': -2.03,
|
||||
'amount_total': -15.7,
|
||||
'amount_paid': -15.7,
|
||||
}])
|
||||
self.assertRecordValues(refund.account_move, [{
|
||||
'amount_untaxed': 13.67,
|
||||
'amount_tax': 2.03,
|
||||
'amount_total': 15.7,
|
||||
}])
|
||||
|
||||
def test_cash_rounding_halfup_biggest_tax_not_only_round_cash_method_pay_by_bank_and_cash(self):
|
||||
self.skipTest('To re-introduce when feature is ready')
|
||||
self.main_pos_config.write({
|
||||
'rounding_method': self.cash_rounding_biggest_tax.id,
|
||||
'cash_rounding': True,
|
||||
'only_round_cash_method': False,
|
||||
})
|
||||
with self.with_new_session(user=self.pos_user) as session:
|
||||
self.start_pos_tour('test_cash_rounding_halfup_biggest_tax_not_only_round_cash_method_pay_by_bank_and_cash')
|
||||
refund, order = self.env['pos.order'].search([('session_id', '=', session.id)], limit=2)
|
||||
self.assertRecordValues(order, [{
|
||||
'amount_tax': 2.03,
|
||||
'amount_total': 15.7,
|
||||
'amount_paid': 15.72,
|
||||
}])
|
||||
self.assertRecordValues(order.account_move, [{
|
||||
'amount_untaxed': 13.69,
|
||||
'amount_tax': 2.03,
|
||||
'amount_total': 15.72,
|
||||
}])
|
||||
self.assertRecordValues(refund, [{
|
||||
'amount_tax': -2.03,
|
||||
'amount_total': -15.7,
|
||||
'amount_paid': -15.72,
|
||||
}])
|
||||
self.assertRecordValues(refund.account_move, [{
|
||||
'amount_untaxed': 13.69,
|
||||
'amount_tax': 2.03,
|
||||
'amount_total': 15.72,
|
||||
}])
|
||||
|
||||
def test_cash_rounding_halfup_biggest_tax_only_round_cash_method(self):
|
||||
self.skipTest('To re-introduce when feature is ready')
|
||||
self.main_pos_config.write({
|
||||
'rounding_method': self.cash_rounding_biggest_tax.id,
|
||||
'cash_rounding': True,
|
||||
'only_round_cash_method': True,
|
||||
})
|
||||
with self.with_new_session(user=self.pos_user) as session:
|
||||
self.start_pos_tour('test_cash_rounding_halfup_biggest_tax_only_round_cash_method')
|
||||
refund, order = self.env['pos.order'].search([('session_id', '=', session.id)], limit=2)
|
||||
self.assertRecordValues(order, [{
|
||||
'amount_tax': 2.05,
|
||||
'amount_total': 15.72,
|
||||
'amount_paid': 15.7,
|
||||
}])
|
||||
self.assertRecordValues(order.account_move, [{
|
||||
'amount_untaxed': 13.67,
|
||||
'amount_tax': 2.03,
|
||||
'amount_total': 15.7,
|
||||
}])
|
||||
self.assertRecordValues(refund, [{
|
||||
'amount_tax': -2.05,
|
||||
'amount_total': -15.72,
|
||||
'amount_paid': -15.7,
|
||||
}])
|
||||
self.assertRecordValues(refund.account_move, [{
|
||||
'amount_untaxed': 13.67,
|
||||
'amount_tax': 2.03,
|
||||
'amount_total': 15.7,
|
||||
}])
|
||||
|
||||
def test_cash_rounding_halfup_biggest_tax_only_round_cash_method_pay_by_bank_and_cash(self):
|
||||
self.skipTest('To re-introduce when feature is ready')
|
||||
self.main_pos_config.write({
|
||||
'rounding_method': self.cash_rounding_biggest_tax.id,
|
||||
'cash_rounding': True,
|
||||
'only_round_cash_method': True,
|
||||
})
|
||||
with self.with_new_session(user=self.pos_user) as session:
|
||||
self.start_pos_tour('test_cash_rounding_halfup_biggest_tax_only_round_cash_method_pay_by_bank_and_cash')
|
||||
refund, order = self.env['pos.order'].search([('session_id', '=', session.id)], limit=2)
|
||||
self.assertRecordValues(order, [{
|
||||
'amount_tax': 2.05,
|
||||
'amount_total': 15.72,
|
||||
'amount_paid': 15.73,
|
||||
}])
|
||||
self.assertRecordValues(order.account_move, [{
|
||||
'amount_untaxed': 13.70,
|
||||
'amount_tax': 2.03,
|
||||
'amount_total': 15.73,
|
||||
}])
|
||||
self.assertRecordValues(refund, [{
|
||||
'amount_tax': -2.05,
|
||||
'amount_total': -15.72,
|
||||
'amount_paid': -15.73,
|
||||
}])
|
||||
self.assertRecordValues(refund.account_move, [{
|
||||
'amount_untaxed': 13.70,
|
||||
'amount_tax': 2.03,
|
||||
'amount_total': 15.73,
|
||||
}])
|
||||
|
||||
def test_archived_product_removed_and_order_is_refunded(self):
|
||||
"""
|
||||
Tests that once product is archived after order is created
|
||||
product is not shown but the order can still be refunded.
|
||||
"""
|
||||
self.pos_admin.write({
|
||||
'group_ids': [
|
||||
(4, self.env.ref('product.group_product_manager').id),
|
||||
(4, self.env.ref('account.group_account_manager').id),
|
||||
]
|
||||
})
|
||||
self.env['product.product'].create({
|
||||
'is_storable': True,
|
||||
'name': 'A Test Product',
|
||||
'available_in_pos': True,
|
||||
'list_price': 1,
|
||||
})
|
||||
self.main_pos_config.with_user(self.pos_admin).open_ui()
|
||||
self.start_tour(
|
||||
"/pos/ui?config_id=%d" % self.main_pos_config.id,
|
||||
"test_archived_product_removed_and_order_is_refunded",
|
||||
login="pos_admin"
|
||||
)
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from datetime import datetime
|
||||
import odoo
|
||||
from odoo.addons.mail.tests.common import mail_new_test_user
|
||||
from odoo.addons.point_of_sale.tests.test_frontend import TestPointOfSaleHttpCommon
|
||||
|
|
@ -15,11 +15,12 @@ class TestPoSController(TestPointOfSaleHttpCommon):
|
|||
self.new_partner = self.env['res.partner'].create({
|
||||
'name': 'AAA Partner',
|
||||
'zip': '12345',
|
||||
'state_id': self.env.ref('base.state_us_1').id,
|
||||
'country_id': self.env.ref('base.us').id,
|
||||
})
|
||||
self.product1 = self.env['product.product'].create({
|
||||
'name': 'Test Product 1',
|
||||
'type': 'product',
|
||||
'is_storable': True,
|
||||
'list_price': 10.0,
|
||||
'taxes_id': False,
|
||||
})
|
||||
|
|
@ -55,13 +56,14 @@ class TestPoSController(TestPointOfSaleHttpCommon):
|
|||
'city': "Test City",
|
||||
'zipcode': self.new_partner.zip,
|
||||
'country_id': self.new_partner.country_id.id,
|
||||
'state_id': self.new_partner.state_id,
|
||||
'state_id': self.new_partner.state_id.id,
|
||||
'phone': "123456789",
|
||||
'csrf_token': odoo.http.Request.csrf_token(self)
|
||||
}
|
||||
self.url_open(f'/pos/ticket/validate?access_token={self.pos_order.access_token}', data=get_invoice_data)
|
||||
self.assertEqual(self.env['res.partner'].sudo().search_count([('name', '=', 'AAA Partner')]), 1)
|
||||
self.assertTrue(self.pos_order.is_invoiced, "The pos order should have an invoice")
|
||||
self.assertTrue(len(self.pos_order.pos_reference) >= 12, "The pos reference should not be less than 12 characters")
|
||||
|
||||
def test_qr_code_receipt_user_connected(self):
|
||||
"""This test make sure that when the user is already connected he correctly gets redirected to the invoice."""
|
||||
|
|
@ -80,7 +82,7 @@ class TestPoSController(TestPointOfSaleHttpCommon):
|
|||
|
||||
self.product1 = self.env['product.product'].create({
|
||||
'name': 'Test Product 1',
|
||||
'type': 'product',
|
||||
'is_storable': True,
|
||||
'list_price': 10.0,
|
||||
'taxes_id': False,
|
||||
})
|
||||
|
|
@ -108,3 +110,98 @@ class TestPoSController(TestPointOfSaleHttpCommon):
|
|||
res = self.url_open(f'/pos/ticket/validate?access_token={self.pos_order.access_token}', timeout=30000)
|
||||
self.assertTrue(self.pos_order.is_invoiced, "The pos order should have an invoice")
|
||||
self.assertTrue("my/invoices" in res.url)
|
||||
|
||||
def test_qr_code_receipt_user_not_connected(self):
|
||||
"""This test make sure that when the user is not connected (public user). Order should invoiced with public user data."""
|
||||
|
||||
self.product1 = self.env['product.product'].create({
|
||||
'name': 'Test Product 1',
|
||||
'is_storable': True,
|
||||
'list_price': 10.0,
|
||||
'taxes_id': False,
|
||||
})
|
||||
self.main_pos_config.open_ui()
|
||||
self.pos_order = self.env['pos.order'].create({
|
||||
'session_id': self.main_pos_config.current_session_id.id,
|
||||
'company_id': self.env.company.id,
|
||||
'access_token': '1234567890',
|
||||
'lines': [(0, 0, {
|
||||
'name': "Test Product 1",
|
||||
'product_id': self.product1.id,
|
||||
'price_unit': 10,
|
||||
'tax_ids': False,
|
||||
'price_subtotal': 10,
|
||||
'price_subtotal_incl': 10,
|
||||
})],
|
||||
'amount_tax': 10,
|
||||
'amount_total': 10,
|
||||
'amount_paid': 10.0,
|
||||
'amount_return': 10.0,
|
||||
'pos_reference': '2500-002-00002',
|
||||
'ticket_code': 'inPoS',
|
||||
'date_order': datetime.today(),
|
||||
})
|
||||
context_make_payment = {"active_ids": [self.pos_order.id], "active_id": self.pos_order.id}
|
||||
self.pos_make_payment = self.env['pos.make.payment'].with_context(context_make_payment).create({
|
||||
'amount': 10.0,
|
||||
'payment_method_id': self.main_pos_config.payment_method_ids[0].id,
|
||||
})
|
||||
context_payment = {'active_id': self.pos_order.id}
|
||||
self.pos_make_payment.with_context(context_payment).check()
|
||||
self.main_pos_config.current_session_id.close_session_from_ui()
|
||||
self.start_tour('/pos/ticket', 'invoicePoSOrderWithSelfInvocing', login=None)
|
||||
self.assertTrue(self.pos_order.account_move, "The pos order should have an invoice after self invoicing")
|
||||
|
||||
def test_qr_code_receipt_user_updated(self):
|
||||
"""This test make sure that when the user is already connected he correctly gets redirected to the invoice."""
|
||||
self.authenticate(None, None)
|
||||
self.partner_1 = self.env['res.partner'].create({
|
||||
'name': 'Valid Lelitre',
|
||||
'email': 'valid.lelitre@agrolait.com',
|
||||
})
|
||||
|
||||
self.product1 = self.env['product.product'].create({
|
||||
'name': 'Test Product 1',
|
||||
'is_storable': True,
|
||||
'list_price': 10.0,
|
||||
'taxes_id': False,
|
||||
})
|
||||
self.main_pos_config.open_ui()
|
||||
self.pos_order = self.env['pos.order'].create({
|
||||
'session_id': self.main_pos_config.current_session_id.id,
|
||||
'company_id': self.env.company.id,
|
||||
'partner_id': self.partner_1.id,
|
||||
'access_token': '1234567890',
|
||||
'lines': [(0, 0, {
|
||||
'name': "OL/0001",
|
||||
'product_id': self.product1.id,
|
||||
'price_unit': 10,
|
||||
'discount': 0.0,
|
||||
'qty': 1.0,
|
||||
'tax_ids': False,
|
||||
'price_subtotal': 10,
|
||||
'price_subtotal_incl': 10,
|
||||
})],
|
||||
'amount_tax': 10,
|
||||
'amount_total': 10,
|
||||
'amount_paid': 10.0,
|
||||
'amount_return': 10.0,
|
||||
})
|
||||
self.main_pos_config.current_session_id.close_session_from_ui()
|
||||
get_invoice_data = {
|
||||
'access_token': self.pos_order.access_token,
|
||||
'name': 'New Name',
|
||||
'email': "test@test.com",
|
||||
'vat': 'VAT_TEST_NUMBER_123',
|
||||
'street': "Test street",
|
||||
'city': "Test City",
|
||||
'zipcode': '12345',
|
||||
'country_id': self.company.country_id.id,
|
||||
'phone': "123456789",
|
||||
'state_id': self.env['res.country.state'].search([], limit=1).id,
|
||||
'csrf_token': odoo.http.Request.csrf_token(self)
|
||||
}
|
||||
self.url_open(f'/pos/ticket/validate?access_token={self.pos_order.access_token}', data=get_invoice_data, timeout=30000)
|
||||
self.assertEqual(self.partner_1.vat, 'VAT_TEST_NUMBER_123')
|
||||
self.assertEqual(self.partner_1.name, 'New Name')
|
||||
self.assertEqual(self.partner_1.zip, '12345')
|
||||
|
|
|
|||
|
|
@ -0,0 +1,107 @@
|
|||
from odoo import Command
|
||||
from odoo.addons.point_of_sale.tests.common import CommonPosTest, TestPoSCommon
|
||||
from odoo.tests.common import tagged
|
||||
|
||||
|
||||
@tagged('post_install', '-at_install')
|
||||
class TestPosInvoiceConsolidation(TestPoSCommon, CommonPosTest):
|
||||
|
||||
def setUp(cls):
|
||||
super().setUp()
|
||||
cls.config = cls.basic_config
|
||||
cls.user1 = cls.env.user
|
||||
cls.user2 = cls.simple_accountman
|
||||
cls.user2.group_ids = [Command.link(cls.env.ref('point_of_sale.group_pos_user').id)]
|
||||
cls.product1 = cls.create_product('Product 1', cls.categ_basic, 10.0)
|
||||
cls.product2 = cls.create_product('Product 2', cls.categ_basic, 20.0)
|
||||
|
||||
def test_ignore_generated_invoices(self):
|
||||
self.open_new_session()
|
||||
|
||||
with self.with_user(self.user1.login):
|
||||
orders_user1 = self._create_orders([{
|
||||
'pos_order_lines_ui_args': [(self.product1, 1)],
|
||||
'customer': self.customer,
|
||||
'is_invoiced': False,
|
||||
'uuid': 'u1-order',
|
||||
}])
|
||||
# This flattens the dict into the recordset
|
||||
orders_user1 = sum(orders_user1.values(), self.env['pos.order'])
|
||||
|
||||
with self.with_user(self.user2.login):
|
||||
orders_user2 = self._create_orders([
|
||||
{
|
||||
'pos_order_lines_ui_args': [(self.product1, 2)],
|
||||
'customer': self.customer,
|
||||
'is_invoiced': False,
|
||||
}, {
|
||||
'pos_order_lines_ui_args': [(self.product2, 1)],
|
||||
'customer': self.customer,
|
||||
'is_invoiced': False,
|
||||
}
|
||||
])
|
||||
# This flattens the dict into the recordset
|
||||
orders_user2 = sum(orders_user2.values(), self.env['pos.order'])
|
||||
|
||||
self.env['pos.make.invoice'].create({'consolidated_billing': True}).with_context(active_ids=orders_user1.ids).action_create_invoices()
|
||||
|
||||
invoice_user1 = orders_user1.account_move
|
||||
invoice_user2 = orders_user2.account_move
|
||||
|
||||
self.assertEqual(len(invoice_user1), 1, "User 1 should have one invoice")
|
||||
self.assertEqual(orders_user1.amount_total, invoice_user1.amount_total)
|
||||
|
||||
self.assertEqual(len(invoice_user2), 0, "User 2 should have no invoices")
|
||||
|
||||
all_orders = orders_user1 + orders_user2
|
||||
self.env['pos.make.invoice'].create({'consolidated_billing': True}).with_context(active_ids=all_orders.ids).action_create_invoices()
|
||||
invoice_user1 = orders_user1.account_move
|
||||
invoice_user2 = orders_user2.account_move
|
||||
|
||||
self.assertEqual(len(invoice_user1), 1, "User 1 should have one invoice")
|
||||
self.assertEqual(orders_user1.amount_total, invoice_user1.amount_total)
|
||||
|
||||
self.assertEqual(len(invoice_user2), 1, "User 2 should have one invoice")
|
||||
self.assertEqual(sum(orders_user2.mapped('amount_total')), invoice_user2.amount_total)
|
||||
|
||||
def test_invoice_grouped_by_user_id(self):
|
||||
self.open_new_session()
|
||||
|
||||
with self.with_user(self.user1.login):
|
||||
orders_user1 = self._create_orders([{
|
||||
'pos_order_lines_ui_args': [(self.product1, 1)],
|
||||
'customer': self.customer,
|
||||
'is_invoiced': False,
|
||||
'uuid': 'u1-order',
|
||||
}])
|
||||
# This flattens the dict into the recordset
|
||||
orders_user1 = sum(orders_user1.values(), self.env['pos.order'])
|
||||
|
||||
with self.with_user(self.user2.login):
|
||||
orders_user2 = self._create_orders([
|
||||
{
|
||||
'pos_order_lines_ui_args': [(self.product1, 2)],
|
||||
'customer': self.customer,
|
||||
'is_invoiced': False,
|
||||
}, {
|
||||
'pos_order_lines_ui_args': [(self.product2, 1)],
|
||||
'customer': self.customer,
|
||||
'is_invoiced': False,
|
||||
}
|
||||
])
|
||||
# This flattens the dict into the recordset
|
||||
orders_user2 = sum(orders_user2.values(), self.env['pos.order'])
|
||||
|
||||
all_orders = orders_user1 + orders_user2
|
||||
|
||||
# create consolidated invoice
|
||||
self.env['pos.make.invoice'].create({'consolidated_billing': True}).with_context(active_ids=all_orders.ids).action_create_invoices()
|
||||
|
||||
invoice_user1 = orders_user1.account_move
|
||||
invoice_user2 = orders_user2.account_move
|
||||
|
||||
self.assertEqual(len(invoice_user1), 1, "User 1 should have one invoice")
|
||||
self.assertEqual(orders_user1.amount_total, invoice_user1.amount_total)
|
||||
|
||||
self.assertEqual(len(invoice_user2), 1, "User 2 should have one invoice")
|
||||
self.assertEqual(sum(orders_user2.mapped('amount_total')), invoice_user2.amount_total)
|
||||
|
|
@ -1,5 +1,7 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
from unittest import skip
|
||||
|
||||
import odoo
|
||||
from odoo.addons.point_of_sale.tests.common import TestPoSCommon
|
||||
|
||||
|
|
@ -42,7 +44,7 @@ class TestPosMargin(TestPoSCommon):
|
|||
self.create_ui_order_data([(product1, 2), (product2, 2)])]
|
||||
|
||||
# sync orders
|
||||
self.env['pos.order'].create_from_ui(orders)
|
||||
self.env['pos.order'].sync_from_ui(orders)
|
||||
|
||||
# check margins
|
||||
self.assertEqual(self.pos_session.order_ids[0].margin, 5)
|
||||
|
|
@ -74,7 +76,7 @@ class TestPosMargin(TestPoSCommon):
|
|||
self.create_ui_order_data([(product1, 2), (product2, 2)])]
|
||||
|
||||
# sync orders
|
||||
self.env['pos.order'].create_from_ui(orders)
|
||||
self.env['pos.order'].sync_from_ui(orders)
|
||||
|
||||
# check margins
|
||||
self.assertEqual(self.pos_session.order_ids[0].margin, -5)
|
||||
|
|
@ -106,7 +108,7 @@ class TestPosMargin(TestPoSCommon):
|
|||
self.create_ui_order_data([(product1, 2), (product2, 2)])]
|
||||
|
||||
# sync orders
|
||||
self.env['pos.order'].create_from_ui(orders)
|
||||
self.env['pos.order'].sync_from_ui(orders)
|
||||
|
||||
# check margins
|
||||
self.assertEqual(self.pos_session.order_ids[0].margin, 10)
|
||||
|
|
@ -140,7 +142,7 @@ class TestPosMargin(TestPoSCommon):
|
|||
self.create_ui_order_data([(product1, 2), (product2, 2)])]
|
||||
|
||||
# sync orders
|
||||
self.env['pos.order'].create_from_ui(orders)
|
||||
self.env['pos.order'].sync_from_ui(orders)
|
||||
|
||||
# check margins
|
||||
self.assertEqual(self.pos_session.order_ids[0].margin, 5)
|
||||
|
|
@ -178,7 +180,7 @@ class TestPosMargin(TestPoSCommon):
|
|||
self.create_ui_order_data([(product1, 2), (product2, 2)])]
|
||||
|
||||
# sync orders
|
||||
self.env['pos.order'].create_from_ui(orders)
|
||||
self.env['pos.order'].sync_from_ui(orders)
|
||||
|
||||
# check margins in the config currency
|
||||
self.assertEqual(self.pos_session.order_ids[0].margin, 2.5)
|
||||
|
|
@ -220,7 +222,7 @@ class TestPosMargin(TestPoSCommon):
|
|||
self.create_ui_order_data([(product1, 2), (product2, 2)])]
|
||||
|
||||
# sync orders
|
||||
self.env['pos.order'].create_from_ui(orders)
|
||||
self.env['pos.order'].sync_from_ui(orders)
|
||||
|
||||
# check margins in the config currency
|
||||
self.assertEqual(self.pos_session.order_ids[0].margin, 2.5)
|
||||
|
|
@ -255,7 +257,7 @@ class TestPosMargin(TestPoSCommon):
|
|||
self.create_ui_order_data([(product1, -2), (product2, -2)])]
|
||||
|
||||
# sync orders
|
||||
self.env['pos.order'].create_from_ui(orders)
|
||||
self.env['pos.order'].sync_from_ui(orders)
|
||||
|
||||
# check margins
|
||||
self.assertEqual(self.pos_session.order_ids[0].margin, -5)
|
||||
|
|
@ -270,6 +272,7 @@ class TestPosMargin(TestPoSCommon):
|
|||
# close session
|
||||
self.pos_session.action_pos_session_validate()
|
||||
|
||||
@skip('Temporary to fast merge new valuation')
|
||||
def test_fifo_margin_real_time(self):
|
||||
"""
|
||||
Test margin where there is product in FIFO with stock update in real time
|
||||
|
|
@ -279,7 +282,6 @@ class TestPosMargin(TestPoSCommon):
|
|||
product2 = self.create_product('Product 2', self.categ_basic, 50, 30)
|
||||
|
||||
move1 = self.env['stock.move'].create({
|
||||
'name': 'IN 2 unit @ 3 per unit',
|
||||
'location_id': self.supplier_location.id,
|
||||
'location_dest_id': self.stock_location.id,
|
||||
'product_id': product1.id,
|
||||
|
|
@ -289,11 +291,11 @@ class TestPosMargin(TestPoSCommon):
|
|||
}).sudo()
|
||||
move1._action_confirm()
|
||||
move1._action_assign()
|
||||
move1.move_line_ids.qty_done = 2
|
||||
move1.move_line_ids.quantity = 2
|
||||
move1.picked = True
|
||||
move1._action_done()
|
||||
|
||||
move2 = self.env['stock.move'].create({
|
||||
'name': 'IN 1 unit @ 7 per unit',
|
||||
'location_id': self.supplier_location.id,
|
||||
'location_dest_id': self.stock_location.id,
|
||||
'product_id': product1.id,
|
||||
|
|
@ -303,7 +305,8 @@ class TestPosMargin(TestPoSCommon):
|
|||
}).sudo()
|
||||
move2._action_confirm()
|
||||
move2._action_assign()
|
||||
move2.move_line_ids.qty_done = 1
|
||||
move2.move_line_ids.quantity = 1
|
||||
move2.picked = True
|
||||
move2._action_done()
|
||||
|
||||
# open a session
|
||||
|
|
@ -314,7 +317,7 @@ class TestPosMargin(TestPoSCommon):
|
|||
self.create_ui_order_data([(product1, 2)])]
|
||||
|
||||
# sync orders
|
||||
self.env['pos.order'].create_from_ui(orders)
|
||||
self.env['pos.order'].sync_from_ui(orders)
|
||||
|
||||
# check margins
|
||||
self.assertEqual(self.pos_session.order_ids[0].margin, 27)
|
||||
|
|
@ -327,6 +330,7 @@ class TestPosMargin(TestPoSCommon):
|
|||
# close session
|
||||
self.pos_session.action_pos_session_validate()
|
||||
|
||||
@skip('Temporary to fast merge new valuation')
|
||||
def test_avco_margin_closing_time(self):
|
||||
"""
|
||||
Test margin where there is product in AVCO with stock update in closing
|
||||
|
|
@ -339,7 +343,6 @@ class TestPosMargin(TestPoSCommon):
|
|||
|
||||
|
||||
move1 = self.env['stock.move'].create({
|
||||
'name': 'IN 2 unit @ 3 per unit',
|
||||
'location_id': self.supplier_location.id,
|
||||
'location_dest_id': self.stock_location.id,
|
||||
'product_id': product1.id,
|
||||
|
|
@ -349,11 +352,11 @@ class TestPosMargin(TestPoSCommon):
|
|||
}).sudo()
|
||||
move1._action_confirm()
|
||||
move1._action_assign()
|
||||
move1.move_line_ids.qty_done = 2
|
||||
move1.move_line_ids.quantity = 2
|
||||
move1.picked = True
|
||||
move1._action_done()
|
||||
|
||||
move2 = self.env['stock.move'].create({
|
||||
'name': 'IN 1 unit @ 6 per unit',
|
||||
'location_id': self.supplier_location.id,
|
||||
'location_dest_id': self.stock_location.id,
|
||||
'product_id': product1.id,
|
||||
|
|
@ -363,7 +366,8 @@ class TestPosMargin(TestPoSCommon):
|
|||
}).sudo()
|
||||
move2._action_confirm()
|
||||
move2._action_assign()
|
||||
move2.move_line_ids.qty_done = 1
|
||||
move2.move_line_ids.quantity = 1
|
||||
move2.picked = True
|
||||
move2._action_done()
|
||||
|
||||
# open a session
|
||||
|
|
@ -374,7 +378,7 @@ class TestPosMargin(TestPoSCommon):
|
|||
self.create_ui_order_data([(product1, 2)])]
|
||||
|
||||
# sync orders
|
||||
self.env['pos.order'].create_from_ui(orders)
|
||||
self.env['pos.order'].sync_from_ui(orders)
|
||||
|
||||
# check margins which are not really computed so it should be 0
|
||||
self.assertEqual(self.pos_session.order_ids[0].margin, 0)
|
||||
|
|
|
|||
|
|
@ -90,14 +90,14 @@ class TestPoSMultipleReceivableAccounts(TestPoSCommon):
|
|||
self.assertAlmostEqual(orders_total, self.pos_session.total_payments_amount, msg='Total order amount should be equal to the total payment amount.')
|
||||
|
||||
# check if there is one invoiced order
|
||||
self.assertEqual(len(self.pos_session.order_ids.filtered(lambda order: order.state == 'invoiced')), 1, 'There should only be one invoiced order.')
|
||||
self.assertEqual(len(self.pos_session.order_ids.filtered(lambda order: order.account_move)), 1, 'There should only be one invoiced order.')
|
||||
|
||||
self._run_test({
|
||||
'payment_methods': self.cash_pm1 | self.bank_pm1,
|
||||
'orders': [
|
||||
{'pos_order_lines_ui_args': [(self.product1, 10), (self.product2, 10), (self.product3, 10)], 'uid': '00100-010-0001'},
|
||||
{'pos_order_lines_ui_args': [(self.product1, 5), (self.product2, 5)], 'payments': [(self.bank_pm1, 158.75)], 'uid': '00100-010-0002'},
|
||||
{'pos_order_lines_ui_args': [(self.product2, 5), (self.product3, 5)], 'payments': [(self.bank_pm1, 264.76)], 'is_invoiced': True, 'customer': self.other_customer, 'uid': '09876-098-0987'},
|
||||
{'pos_order_lines_ui_args': [(self.product1, 10), (self.product2, 10), (self.product3, 10)], 'uuid': '00100-010-0001'},
|
||||
{'pos_order_lines_ui_args': [(self.product1, 5), (self.product2, 5)], 'payments': [(self.bank_pm1, 158.75)], 'uuid': '00100-010-0002'},
|
||||
{'pos_order_lines_ui_args': [(self.product2, 5), (self.product3, 5)], 'payments': [(self.bank_pm1, 264.76)], 'is_invoiced': True, 'customer': self.other_customer, 'uuid': '09876-098-0987'},
|
||||
],
|
||||
'before_closing_cb': _before_closing_cb,
|
||||
'journal_entries_before_closing': {
|
||||
|
|
@ -106,7 +106,7 @@ class TestPoSMultipleReceivableAccounts(TestPoSCommon):
|
|||
'line_ids_predicate': lambda line: line.account_id in self.other_sale_account | self.sales_account | self.other_receivable_account,
|
||||
'line_ids': [
|
||||
{'account_id': self.other_sale_account.id, 'partner_id': self.other_customer.id, 'debit': 0, 'credit': 90.86, 'reconciled': False},
|
||||
{'account_id': self.sales_account.id, 'partner_id': self.other_customer.id, 'debit': 0, 'credit': 140.86, 'reconciled': False},
|
||||
{'account_id': self.sales_account.id, 'partner_id': self.other_customer.id, 'debit': 0, 'credit': 140.87, 'reconciled': False},
|
||||
{'account_id': self.other_receivable_account.id, 'partner_id': self.other_customer.id, 'debit': 264.76, 'credit': 0, 'reconciled': True},
|
||||
]
|
||||
},
|
||||
|
|
@ -124,10 +124,10 @@ class TestPoSMultipleReceivableAccounts(TestPoSCommon):
|
|||
'session_journal_entry': {
|
||||
'line_ids': [
|
||||
{'account_id': self.tax_received_account.id, 'partner_id': False, 'debit': 0, 'credit': 31.26, 'reconciled': False},
|
||||
{'account_id': self.tax_received_account.id, 'partner_id': False, 'debit': 0, 'credit': 55.43, 'reconciled': False},
|
||||
{'account_id': self.tax_received_account.id, 'partner_id': False, 'debit': 0, 'credit': 55.44, 'reconciled': False},
|
||||
{'account_id': self.sales_account.id, 'partner_id': False, 'debit': 0, 'credit': 164.85, 'reconciled': False},
|
||||
{'account_id': self.other_sale_account.id, 'partner_id': False, 'debit': 0, 'credit': 272.59, 'reconciled': False},
|
||||
{'account_id': self.sales_account.id, 'partner_id': False, 'debit': 0, 'credit': 281.73, 'reconciled': False},
|
||||
{'account_id': self.sales_account.id, 'partner_id': False, 'debit': 0, 'credit': 281.72, 'reconciled': False},
|
||||
{'account_id': self.bank_pm1.receivable_account_id.id, 'partner_id': False, 'debit': 423.51, 'credit': 0, 'reconciled': True},
|
||||
{'account_id': self.cash_pm1.receivable_account_id.id, 'partner_id': False, 'debit': 647.11, 'credit': 0, 'reconciled': True},
|
||||
{'account_id': self.pos_receivable_account.id, 'partner_id': False, 'debit': 0, 'credit': 264.76, 'reconciled': True},
|
||||
|
|
@ -192,14 +192,14 @@ class TestPoSMultipleReceivableAccounts(TestPoSCommon):
|
|||
self.assertAlmostEqual(orders_total, self.pos_session.total_payments_amount, msg='Total order amount should be equal to the total payment amount.')
|
||||
|
||||
# check if there is one invoiced order
|
||||
self.assertEqual(len(self.pos_session.order_ids.filtered(lambda order: order.state == 'invoiced')), 3, 'All orders should be invoiced.')
|
||||
self.assertEqual(len(self.pos_session.order_ids.filtered(lambda order: order.account_move)), 3, 'All orders should be invoiced.')
|
||||
|
||||
self._run_test({
|
||||
'payment_methods': self.cash_pm1 | self.bank_pm1,
|
||||
'orders': [
|
||||
{'pos_order_lines_ui_args': [(self.product1, 10), (self.product2, 10), (self.product3, 10)], 'is_invoiced': True, 'customer': self.other_customer, 'uid': '09876-098-0987'},
|
||||
{'pos_order_lines_ui_args': [(self.product1, 5), (self.product2, 5)], 'payments': [(self.bank_pm1, 158.75)], 'is_invoiced': True, 'customer': self.customer, 'uid': '09876-098-0988'},
|
||||
{'pos_order_lines_ui_args': [(self.product2, 5), (self.product3, 5)], 'payments': [(self.bank_pm1, 264.76)], 'is_invoiced': True, 'customer': self.other_customer, 'uid': '09876-098-0989'},
|
||||
{'pos_order_lines_ui_args': [(self.product1, 10), (self.product2, 10), (self.product3, 10)], 'is_invoiced': True, 'customer': self.other_customer, 'uuid': '09876-098-0987'},
|
||||
{'pos_order_lines_ui_args': [(self.product1, 5), (self.product2, 5)], 'payments': [(self.bank_pm1, 158.75)], 'is_invoiced': True, 'customer': self.customer, 'uuid': '09876-098-0988'},
|
||||
{'pos_order_lines_ui_args': [(self.product2, 5), (self.product3, 5)], 'payments': [(self.bank_pm1, 264.76)], 'is_invoiced': True, 'customer': self.other_customer, 'uuid': '09876-098-0989'},
|
||||
],
|
||||
'before_closing_cb': _before_closing_cb,
|
||||
'journal_entries_before_closing': {
|
||||
|
|
@ -209,7 +209,7 @@ class TestPoSMultipleReceivableAccounts(TestPoSCommon):
|
|||
'line_ids': [
|
||||
{'account_id': self.sales_account.id, 'partner_id': self.other_customer.id, 'debit': 0, 'credit': 109.90, 'reconciled': False},
|
||||
{'account_id': self.other_sale_account.id, 'partner_id': self.other_customer.id, 'debit': 0, 'credit': 181.73, 'reconciled': False},
|
||||
{'account_id': self.sales_account.id, 'partner_id': self.other_customer.id, 'debit': 0, 'credit': 281.73, 'reconciled': False},
|
||||
{'account_id': self.sales_account.id, 'partner_id': self.other_customer.id, 'debit': 0, 'credit': 281.72, 'reconciled': False},
|
||||
{'account_id': self.other_receivable_account.id, 'partner_id': self.other_customer.id, 'debit': 647.11, 'credit': 0, 'reconciled': True},
|
||||
]
|
||||
},
|
||||
|
|
@ -245,7 +245,7 @@ class TestPoSMultipleReceivableAccounts(TestPoSCommon):
|
|||
'line_ids_predicate': lambda line: line.account_id in self.other_sale_account | self.sales_account | self.other_receivable_account,
|
||||
'line_ids': [
|
||||
{'account_id': self.other_sale_account.id, 'partner_id': self.other_customer.id, 'debit': 0, 'credit': 90.86, 'reconciled': False},
|
||||
{'account_id': self.sales_account.id, 'partner_id': self.other_customer.id, 'debit': 0, 'credit': 140.86, 'reconciled': False},
|
||||
{'account_id': self.sales_account.id, 'partner_id': self.other_customer.id, 'debit': 0, 'credit': 140.87, 'reconciled': False},
|
||||
{'account_id': self.other_receivable_account.id, 'partner_id': self.other_customer.id, 'debit': 264.76, 'credit': 0, 'reconciled': True},
|
||||
]
|
||||
},
|
||||
|
|
|
|||
|
|
@ -1,10 +1,11 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from unittest import skip
|
||||
|
||||
import odoo
|
||||
|
||||
from odoo import tools
|
||||
from odoo.tests.common import Form
|
||||
from odoo.addons.point_of_sale.tests.common import TestPoSCommon
|
||||
|
||||
@odoo.tests.tagged('post_install', '-at_install')
|
||||
|
|
@ -34,7 +35,6 @@ class TestPoSOtherCurrencyConfig(TestPoSCommon):
|
|||
})
|
||||
self.config.pricelist_id.write({'item_ids': [(6, 0, (self.config.pricelist_id.item_ids | pricelist_item).ids)]})
|
||||
|
||||
self.output_account = self.categ_anglo.property_stock_account_output_categ_id
|
||||
self.expense_account = self.categ_anglo.property_account_expense_categ_id
|
||||
|
||||
def test_01_check_product_cost(self):
|
||||
|
|
@ -91,9 +91,9 @@ class TestPoSOtherCurrencyConfig(TestPoSCommon):
|
|||
self._run_test({
|
||||
'payment_methods': self.cash_pm2 | self.bank_pm2,
|
||||
'orders': [
|
||||
{'pos_order_lines_ui_args': [(self.product1, 10), (self.product2, 10), (self.product3, 10)], 'uid': '00100-010-0001'},
|
||||
{'pos_order_lines_ui_args': [(self.product1, 5), (self.product2, 5)], 'uid': '00100-010-0002'},
|
||||
{'pos_order_lines_ui_args': [(self.product2, 5), (self.product3, 5)], 'payments': [(self.bank_pm2, 139.95)], 'uid': '00100-010-0003'},
|
||||
{'pos_order_lines_ui_args': [(self.product1, 10), (self.product2, 10), (self.product3, 10)], 'uuid': '00100-010-0001'},
|
||||
{'pos_order_lines_ui_args': [(self.product1, 5), (self.product2, 5)], 'uuid': '00100-010-0002'},
|
||||
{'pos_order_lines_ui_args': [(self.product2, 5), (self.product3, 5)], 'payments': [(self.bank_pm2, 139.95)], 'uuid': '00100-010-0003'},
|
||||
],
|
||||
'before_closing_cb': _before_closing_cb,
|
||||
'journal_entries_before_closing': {},
|
||||
|
|
@ -167,9 +167,9 @@ class TestPoSOtherCurrencyConfig(TestPoSCommon):
|
|||
self._run_test({
|
||||
'payment_methods': self.cash_pm2 | self.bank_pm2,
|
||||
'orders': [
|
||||
{'pos_order_lines_ui_args': [(self.product1, 10), (self.product2, 10), (self.product3, 10)], 'uid': '00100-010-0001'},
|
||||
{'pos_order_lines_ui_args': [(self.product1, 5), (self.product2, 5)], 'is_invoiced': True, 'customer': self.customer, 'uid': '00100-010-0002'},
|
||||
{'pos_order_lines_ui_args': [(self.product2, 5), (self.product3, 5)], 'payments': [(self.bank_pm2, 139.95)], 'is_invoiced': True, 'customer': self.customer, 'uid': '00100-010-0003'},
|
||||
{'pos_order_lines_ui_args': [(self.product1, 10), (self.product2, 10), (self.product3, 10)], 'uuid': '00100-010-0001'},
|
||||
{'pos_order_lines_ui_args': [(self.product1, 5), (self.product2, 5)], 'is_invoiced': True, 'customer': self.customer, 'uuid': '00100-010-0002'},
|
||||
{'pos_order_lines_ui_args': [(self.product2, 5), (self.product3, 5)], 'payments': [(self.bank_pm2, 139.95)], 'is_invoiced': True, 'customer': self.customer, 'uuid': '00100-010-0003'},
|
||||
],
|
||||
'before_closing_cb': _before_closing_cb,
|
||||
'journal_entries_before_closing': {
|
||||
|
|
@ -223,6 +223,7 @@ class TestPoSOtherCurrencyConfig(TestPoSCommon):
|
|||
},
|
||||
})
|
||||
|
||||
@skip('Temporary to fast merge new valuation')
|
||||
def test_04_anglo_saxon_products(self):
|
||||
"""
|
||||
======
|
||||
|
|
@ -263,10 +264,10 @@ class TestPoSOtherCurrencyConfig(TestPoSCommon):
|
|||
self._run_test({
|
||||
'payment_methods': self.cash_pm2,
|
||||
'orders': [
|
||||
{'pos_order_lines_ui_args': [(self.product4, 7), (self.product5, 7)], 'uid': '00100-010-0001'},
|
||||
{'pos_order_lines_ui_args': [(self.product5, 6), (self.product4, 6), (self.product6, 49)], 'uid': '00100-010-0002'},
|
||||
{'pos_order_lines_ui_args': [(self.product5, 2), (self.product6, 13)], 'uid': '00100-010-0003'},
|
||||
{'pos_order_lines_ui_args': [(self.product6, 1)], 'uid': '00100-010-0004'},
|
||||
{'pos_order_lines_ui_args': [(self.product4, 7), (self.product5, 7)], 'uuid': '00100-010-0001'},
|
||||
{'pos_order_lines_ui_args': [(self.product5, 6), (self.product4, 6), (self.product6, 49)], 'uuid': '00100-010-0002'},
|
||||
{'pos_order_lines_ui_args': [(self.product5, 2), (self.product6, 13)], 'uuid': '00100-010-0003'},
|
||||
{'pos_order_lines_ui_args': [(self.product6, 1)], 'uuid': '00100-010-0004'},
|
||||
],
|
||||
'journal_entries_before_closing': {},
|
||||
'journal_entries_after_closing': {
|
||||
|
|
@ -294,7 +295,7 @@ class TestPoSOtherCurrencyConfig(TestPoSCommon):
|
|||
self._run_test({
|
||||
'payment_methods': self.cash_pm2,
|
||||
'orders': [
|
||||
{'pos_order_lines_ui_args': [(self.product7, 7)], 'uid': '00100-010-0001'},
|
||||
{'pos_order_lines_ui_args': [(self.product7, 7)], 'uuid': '00100-010-0001'},
|
||||
],
|
||||
'journal_entries_before_closing': {},
|
||||
'journal_entries_after_closing': {
|
||||
|
|
@ -363,3 +364,24 @@ class TestPoSOtherCurrencyConfig(TestPoSCommon):
|
|||
debit += line.debit
|
||||
credit += line.credit
|
||||
self.assertEqual(tools.float_compare(debit, credit, precision_rounding=self.other_currency_config.currency_id.rounding), 0) # debit and credit should be equal
|
||||
|
||||
def test_with_session_check_product_cost(self):
|
||||
def find_by(list_of_dicts, key, value):
|
||||
return next((d for d in list_of_dicts if d.get(key) == value), None)
|
||||
|
||||
self.other_currency_config.open_ui()
|
||||
product = self.other_currency_config.current_session_id.load_data([])['product.product']
|
||||
|
||||
self.assertAlmostEqual(find_by(product, 'id', self.product1.id)['lst_price'], 5.00)
|
||||
self.assertAlmostEqual(find_by(product, 'id', self.product2.id)['lst_price'], 10.00)
|
||||
self.assertAlmostEqual(find_by(product, 'id', self.product3.id)['lst_price'], 15.00)
|
||||
self.assertAlmostEqual(find_by(product, 'id', self.product4.id)['lst_price'], 50.00)
|
||||
self.assertAlmostEqual(find_by(product, 'id', self.product5.id)['lst_price'], 100.00)
|
||||
self.assertAlmostEqual(find_by(product, 'id', self.product6.id)['lst_price'], 22.65)
|
||||
self.assertAlmostEqual(find_by(product, 'id', self.product7.id)['lst_price'], 3.50)
|
||||
|
||||
def test_pos_data_standard_price_converted(self):
|
||||
self.other_currency_config.open_ui()
|
||||
res = self.other_currency_config.current_session_id.load_data({})
|
||||
product1_data = next(filter(lambda product: product['display_name'] == "Product 1", res['product.product']))
|
||||
self.assertEqual(product1_data['standard_price'], 2.5) # standard price should be converted
|
||||
|
|
|
|||
|
|
@ -0,0 +1,291 @@
|
|||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from odoo import Command
|
||||
from odoo.tests import tagged
|
||||
|
||||
from odoo.addons.product.tests.common import ProductVariantsCommon
|
||||
from odoo.addons.point_of_sale.tests.test_frontend import TestPointOfSaleHttpCommon
|
||||
|
||||
|
||||
@tagged('post_install', '-at_install')
|
||||
class TestPoSProductVariants(ProductVariantsCommon, TestPointOfSaleHttpCommon):
|
||||
|
||||
def test_integration_dynamic_variant_price(self):
|
||||
"""Tests the price of products with dynamic variant when added to cart"""
|
||||
self.env['product.attribute.value'].create({
|
||||
'name': 'dyn3',
|
||||
'attribute_id': self.dynamic_attribute.id,
|
||||
'default_extra_price': 10,
|
||||
})
|
||||
(dyn1, dyn2, dyn3) = self.dynamic_attribute.value_ids
|
||||
dyn2.default_extra_price = 5
|
||||
|
||||
product_template = self.env['product.template'].create({
|
||||
'name': 'A dynamic product',
|
||||
'taxes_id': False,
|
||||
'available_in_pos': True,
|
||||
'pos_categ_ids': [Command.set(self.pos_desk_misc_test.ids)],
|
||||
})
|
||||
self.env['product.template.attribute.line'].create({
|
||||
'product_tmpl_id': product_template.id,
|
||||
'attribute_id': self.dynamic_attribute.id,
|
||||
'value_ids': [Command.set([dyn1.id, dyn2.id, dyn3.id])],
|
||||
})
|
||||
|
||||
# Create a variant (because of dynamic attribute)
|
||||
ptav_dyn2 = self.env['product.template.attribute.value'].search([
|
||||
('attribute_line_id', '=', product_template.attribute_line_ids.id),
|
||||
('product_attribute_value_id', '=', dyn2.id)
|
||||
])
|
||||
|
||||
self.env['product.product'].create({
|
||||
'available_in_pos': True,
|
||||
'product_tmpl_id': product_template.id,
|
||||
'product_template_attribute_value_ids': [(6, 0, [ptav_dyn2.id])],
|
||||
'pos_categ_ids': [Command.set(self.pos_desk_misc_test.ids)],
|
||||
})
|
||||
self.main_pos_config.with_user(self.pos_user).open_ui()
|
||||
self.start_tour("/pos/ui?config_id=%d" % self.main_pos_config.id, 'test_integration_dynamic_variant_price', login="pos_user")
|
||||
|
||||
def test_integration_always_variant_price(self):
|
||||
"""Tests the price of products with always variant when added to cart"""
|
||||
self.size_attribute_m.default_extra_price = 5
|
||||
|
||||
product_template = self.env['product.template'].create({
|
||||
'name': 'A always product',
|
||||
'uom_id': self.env.ref('uom.product_uom_unit').id,
|
||||
'is_storable': True,
|
||||
'taxes_id': False,
|
||||
'available_in_pos': True,
|
||||
'pos_categ_ids': [Command.set(self.pos_desk_misc_test.ids)],
|
||||
})
|
||||
self.env['product.template.attribute.line'].create({
|
||||
'product_tmpl_id': product_template.id,
|
||||
'attribute_id': self.size_attribute.id,
|
||||
'value_ids': [Command.set([self.size_attribute_s.id, self.size_attribute_m.id])],
|
||||
})
|
||||
|
||||
self.main_pos_config.with_user(self.pos_user).open_ui()
|
||||
self.start_tour("/pos/ui?config_id=%d" % self.main_pos_config.id, 'test_integration_always_variant_price', login="pos_user")
|
||||
|
||||
def test_integration_never_variant_price(self):
|
||||
"""Tests the price of products with no variant(never) variant when added to cart"""
|
||||
self.no_variant_attribute_second.default_extra_price = 5
|
||||
|
||||
product_template = self.env['product.template'].create({
|
||||
'name': 'A never product',
|
||||
'uom_id': self.env.ref('uom.product_uom_unit').id,
|
||||
'is_storable': True,
|
||||
'taxes_id': False,
|
||||
'available_in_pos': True,
|
||||
'pos_categ_ids': [Command.set(self.pos_desk_misc_test.ids)],
|
||||
})
|
||||
self.env['product.template.attribute.line'].create({
|
||||
'product_tmpl_id': product_template.id,
|
||||
'attribute_id': self.no_variant_attribute.id,
|
||||
'value_ids': [Command.set([self.no_variant_attribute_extra.id, self.no_variant_attribute_second.id])],
|
||||
})
|
||||
|
||||
self.main_pos_config.with_user(self.pos_user).open_ui()
|
||||
self.start_tour("/pos/ui?config_id=%d" % self.main_pos_config.id, 'test_integration_never_variant_price', login="pos_user")
|
||||
|
||||
def test_integration_dynamic_always_variant_price(self):
|
||||
"""Tests the price of products with dynamic and always variants when added to cart"""
|
||||
self.env['product.attribute.value'].create({
|
||||
'name': 'dyn3',
|
||||
'attribute_id': self.dynamic_attribute.id,
|
||||
'default_extra_price': 20,
|
||||
})
|
||||
(dyn1, dyn2, dyn3) = self.dynamic_attribute.value_ids
|
||||
dyn2.default_extra_price = 10
|
||||
self.size_attribute_m.default_extra_price = 5
|
||||
|
||||
product_template = self.env['product.template'].create({
|
||||
'name': 'A dyn/alw product',
|
||||
'taxes_id': False,
|
||||
'available_in_pos': True,
|
||||
'pos_categ_ids': [Command.set(self.pos_desk_misc_test.ids)],
|
||||
})
|
||||
self.env['product.template.attribute.line'].create([{
|
||||
'product_tmpl_id': product_template.id,
|
||||
'attribute_id': self.dynamic_attribute.id,
|
||||
'value_ids': [Command.set([dyn1.id, dyn2.id, dyn3.id])],
|
||||
}, {
|
||||
'product_tmpl_id': product_template.id,
|
||||
'attribute_id': self.size_attribute.id,
|
||||
'value_ids': [Command.set([self.size_attribute_s.id, self.size_attribute_m.id])],
|
||||
}])
|
||||
|
||||
# Create a variant (because of dynamic attribute)
|
||||
ptav_dyn2 = self.env['product.template.attribute.value'].search([
|
||||
('attribute_line_id', '=', product_template.attribute_line_ids[0].id),
|
||||
('product_attribute_value_id', '=', dyn2.id)
|
||||
])
|
||||
ptav_always1 = self.env['product.template.attribute.value'].search([
|
||||
('attribute_line_id', '=', product_template.attribute_line_ids[1].id),
|
||||
('product_attribute_value_id', '=', self.size_attribute_s.id)
|
||||
])
|
||||
|
||||
self.env['product.product'].create({
|
||||
'available_in_pos': True,
|
||||
'product_tmpl_id': product_template.id,
|
||||
'product_template_attribute_value_ids': [(6, 0, (ptav_dyn2 + ptav_always1).ids)],
|
||||
'pos_categ_ids': [Command.set(self.pos_desk_misc_test.ids)],
|
||||
})
|
||||
self.main_pos_config.with_user(self.pos_user).open_ui()
|
||||
self.start_tour("/pos/ui?config_id=%d" % self.main_pos_config.id, 'test_integration_dynamic_always_variant_price', login="pos_user")
|
||||
|
||||
def test_integration_dynamic_never_variant_price(self):
|
||||
"""Tests the price of products with dynamic and never variants when added to cart"""
|
||||
self.env['product.attribute.value'].create({
|
||||
'name': 'dyn3',
|
||||
'attribute_id': self.dynamic_attribute.id,
|
||||
'default_extra_price': 20,
|
||||
})
|
||||
(dyn1, dyn2, dyn3) = self.dynamic_attribute.value_ids
|
||||
dyn2.default_extra_price = 10
|
||||
self.no_variant_attribute_second.default_extra_price = 5
|
||||
|
||||
product_template = self.env['product.template'].create({
|
||||
'name': 'A dyn/nev product',
|
||||
'taxes_id': False,
|
||||
'available_in_pos': True,
|
||||
'pos_categ_ids': [Command.set(self.pos_desk_misc_test.ids)],
|
||||
})
|
||||
self.env['product.template.attribute.line'].create([{
|
||||
'product_tmpl_id': product_template.id,
|
||||
'attribute_id': self.dynamic_attribute.id,
|
||||
'value_ids': [Command.set([dyn1.id, dyn2.id, dyn3.id])],
|
||||
}, {
|
||||
'product_tmpl_id': product_template.id,
|
||||
'attribute_id': self.no_variant_attribute.id,
|
||||
'value_ids': [Command.set([self.no_variant_attribute_extra.id, self.no_variant_attribute_second.id])],
|
||||
}])
|
||||
|
||||
# Create a variant (because of dynamic attribute)
|
||||
ptav_dyn2 = self.env['product.template.attribute.value'].search([
|
||||
('attribute_line_id', '=', product_template.attribute_line_ids[0].id),
|
||||
('product_attribute_value_id', '=', dyn2.id)
|
||||
])
|
||||
ptav_never1 = self.env['product.template.attribute.value'].search([
|
||||
('attribute_line_id', '=', product_template.attribute_line_ids[1].id),
|
||||
('product_attribute_value_id', '=', self.no_variant_attribute_extra.id)
|
||||
])
|
||||
|
||||
self.env['product.product'].create({
|
||||
'available_in_pos': True,
|
||||
'product_tmpl_id': product_template.id,
|
||||
'product_template_attribute_value_ids': [(6, 0, (ptav_dyn2 + ptav_never1).ids)],
|
||||
'pos_categ_ids': [Command.set(self.pos_desk_misc_test.ids)],
|
||||
})
|
||||
self.main_pos_config.with_user(self.pos_user).open_ui()
|
||||
self.start_tour("/pos/ui?config_id=%d" % self.main_pos_config.id, 'test_integration_dynamic_never_variant_price', login="pos_user")
|
||||
|
||||
def test_integration_always_never_variant_price(self):
|
||||
"""Tests the price of products with always and never variants when added to cart"""
|
||||
self.no_variant_attribute_second.default_extra_price = 5
|
||||
self.size_attribute_m.default_extra_price = 10
|
||||
|
||||
product_template = self.env['product.template'].create({
|
||||
'name': 'A alw/nev product',
|
||||
'uom_id': self.env.ref('uom.product_uom_unit').id,
|
||||
'is_storable': True,
|
||||
'taxes_id': False,
|
||||
'available_in_pos': True,
|
||||
'pos_categ_ids': [Command.set(self.pos_desk_misc_test.ids)],
|
||||
})
|
||||
self.env['product.template.attribute.line'].create([{
|
||||
'product_tmpl_id': product_template.id,
|
||||
'attribute_id': self.no_variant_attribute.id,
|
||||
'value_ids': [Command.set([self.no_variant_attribute_extra.id, self.no_variant_attribute_second.id])],
|
||||
}, {
|
||||
'product_tmpl_id': product_template.id,
|
||||
'attribute_id': self.size_attribute.id,
|
||||
'value_ids': [Command.set([self.size_attribute_s.id, self.size_attribute_m.id])],
|
||||
}])
|
||||
|
||||
self.main_pos_config.with_user(self.pos_user).open_ui()
|
||||
self.start_tour("/pos/ui?config_id=%d" % self.main_pos_config.id, 'test_integration_always_never_variant_price', login="pos_user")
|
||||
|
||||
def test_integration_dynamic_always_never_variant_price(self):
|
||||
"""Tests the price of products with all types of variants when added to cart"""
|
||||
(dyn1, dyn2) = self.dynamic_attribute.value_ids
|
||||
dyn2.default_extra_price = 10
|
||||
self.size_attribute_m.default_extra_price = 5
|
||||
self.no_variant_attribute_second.default_extra_price = 0.5
|
||||
|
||||
product_template = self.env['product.template'].create({
|
||||
'name': 'A dyn/alw/nev product',
|
||||
'taxes_id': False,
|
||||
'available_in_pos': True,
|
||||
'pos_categ_ids': [Command.set(self.pos_desk_misc_test.ids)],
|
||||
})
|
||||
self.env['product.template.attribute.line'].create([{
|
||||
'product_tmpl_id': product_template.id,
|
||||
'attribute_id': self.dynamic_attribute.id,
|
||||
'value_ids': [Command.set([dyn1.id, dyn2.id])],
|
||||
}, {
|
||||
'product_tmpl_id': product_template.id,
|
||||
'attribute_id': self.no_variant_attribute.id,
|
||||
'value_ids': [Command.set([self.no_variant_attribute_extra.id, self.no_variant_attribute_second.id])],
|
||||
}, {
|
||||
'product_tmpl_id': product_template.id,
|
||||
'attribute_id': self.size_attribute.id,
|
||||
'value_ids': [Command.set([self.size_attribute_s.id, self.size_attribute_m.id])],
|
||||
}])
|
||||
|
||||
# Create a variant (because of dynamic attribute)
|
||||
ptav_dyn2 = self.env['product.template.attribute.value'].search([
|
||||
('attribute_line_id', '=', product_template.attribute_line_ids[0].id),
|
||||
('product_attribute_value_id', '=', dyn2.id)
|
||||
])
|
||||
ptav_never1 = self.env['product.template.attribute.value'].search([
|
||||
('attribute_line_id', '=', product_template.attribute_line_ids[1].id),
|
||||
('product_attribute_value_id', '=', self.no_variant_attribute_extra.id)
|
||||
])
|
||||
ptav_always1 = self.env['product.template.attribute.value'].search([
|
||||
('attribute_line_id', '=', product_template.attribute_line_ids[1].id),
|
||||
('product_attribute_value_id', '=', self.size_attribute_s.id)
|
||||
])
|
||||
|
||||
self.env['product.product'].create({
|
||||
'available_in_pos': True,
|
||||
'product_tmpl_id': product_template.id,
|
||||
'product_template_attribute_value_ids': [(6, 0, (ptav_dyn2 + ptav_always1 + ptav_never1).ids)],
|
||||
'pos_categ_ids': [Command.set(self.pos_desk_misc_test.ids)],
|
||||
})
|
||||
self.main_pos_config.with_user(self.pos_user).open_ui()
|
||||
self.start_tour("/pos/ui?config_id=%d" % self.main_pos_config.id, 'test_integration_dynamic_always_never_variant_price', login="pos_user")
|
||||
|
||||
def test_image_variants_displayed(self):
|
||||
"""
|
||||
Tests that the user can correctly chose variants in the product_configurator_popup
|
||||
if the variant was set as Image
|
||||
"""
|
||||
image_attribute = self.env['product.attribute'].create({
|
||||
'name': 'Images',
|
||||
'display_type': 'image',
|
||||
'create_variant': 'always',
|
||||
})
|
||||
images = self.env['product.attribute.value'].create([{
|
||||
'name': 'First Image',
|
||||
'attribute_id': image_attribute.id,
|
||||
}, {
|
||||
'name': 'Second Image',
|
||||
'attribute_id': image_attribute.id,
|
||||
'default_extra_price': 20,
|
||||
}])
|
||||
product_template = self.env['product.template'].create({
|
||||
'name': 'Image Product',
|
||||
'is_storable': True,
|
||||
'taxes_id': False,
|
||||
'available_in_pos': True,
|
||||
})
|
||||
self.env['product.template.attribute.line'].create({
|
||||
'product_tmpl_id': product_template.id,
|
||||
'attribute_id': image_attribute.id,
|
||||
'value_ids': [Command.set([images[0].id, images[1].id])],
|
||||
})
|
||||
|
||||
self.main_pos_config.with_user(self.pos_user).open_ui()
|
||||
self.start_tour("/pos/ui?config_id=%d" % self.main_pos_config.id, 'test_image_variants_displayed', login="pos_user")
|
||||
|
|
@ -1,10 +1,12 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from odoo import tools
|
||||
from odoo import Command
|
||||
|
||||
import odoo
|
||||
from odoo.addons.point_of_sale.tests.common import TestPoSCommon
|
||||
from odoo.tests import Form
|
||||
from odoo.exceptions import UserError
|
||||
|
||||
|
||||
@odoo.tests.tagged('post_install', '-at_install')
|
||||
class TestPoSProductsWithTax(TestPoSCommon):
|
||||
|
|
@ -82,9 +84,9 @@ class TestPoSProductsWithTax(TestPoSCommon):
|
|||
self._run_test({
|
||||
'payment_methods': self.cash_pm1 | self.bank_pm1,
|
||||
'orders': [
|
||||
{'pos_order_lines_ui_args': [(self.product1, 10), (self.product2, 5)], 'uid': '00100-010-0001'},
|
||||
{'pos_order_lines_ui_args': [(self.product2, 7), (self.product3, 4)], 'uid': '00100-010-0002'},
|
||||
{'pos_order_lines_ui_args': [(self.product1, 1), (self.product3, 5), (self.product2, 3)], 'payments': [(self.bank_pm1, 230.25)], 'uid': '00100-010-0003'},
|
||||
{'pos_order_lines_ui_args': [(self.product1, 10), (self.product2, 5)], 'uuid': '00100-010-0001'},
|
||||
{'pos_order_lines_ui_args': [(self.product2, 7), (self.product3, 4)], 'uuid': '00100-010-0002'},
|
||||
{'pos_order_lines_ui_args': [(self.product1, 1), (self.product3, 5), (self.product2, 3)], 'payments': [(self.bank_pm1, 230.25)], 'uuid': '00100-010-0003'},
|
||||
],
|
||||
'before_closing_cb': _before_closing_cb,
|
||||
'journal_entries_before_closing': {},
|
||||
|
|
@ -96,8 +98,8 @@ class TestPoSProductsWithTax(TestPoSCommon):
|
|||
{'account_id': self.sales_account.id, 'partner_id': False, 'debit': 0, 'credit': 110, 'reconciled': False, 'display_type': 'product'},
|
||||
{'account_id': self.sales_account.id, 'partner_id': False, 'debit': 0, 'credit': 272.73, 'reconciled': False, 'display_type': 'product'},
|
||||
{'account_id': self.sales_account.id, 'partner_id': False, 'debit': 0, 'credit': 245.45, 'reconciled': False, 'display_type': 'product'},
|
||||
{'account_id': self.bank_pm1.receivable_account_id.id, 'partner_id': False, 'debit': 230.25, 'credit': 0, 'reconciled': True, 'display_type': 'product'},
|
||||
{'account_id': self.cash_pm1.receivable_account_id.id, 'partner_id': False, 'debit': 474.64, 'credit': 0, 'reconciled': True, 'display_type': 'product'},
|
||||
{'account_id': self.bank_pm1.receivable_account_id.id, 'partner_id': False, 'debit': 230.25, 'credit': 0, 'reconciled': True, 'display_type': 'payment_term'},
|
||||
{'account_id': self.cash_pm1.receivable_account_id.id, 'partner_id': False, 'debit': 474.64, 'credit': 0, 'reconciled': True, 'display_type': 'payment_term'},
|
||||
],
|
||||
},
|
||||
'cash_statement': [
|
||||
|
|
@ -175,10 +177,10 @@ class TestPoSProductsWithTax(TestPoSCommon):
|
|||
self._run_test({
|
||||
'payment_methods': self.cash_pm1 | self.bank_pm1,
|
||||
'orders': [
|
||||
{'pos_order_lines_ui_args': [(self.product3, 1), (self.product1, 6), (self.product2, 3)], 'uid': '00100-010-0001'},
|
||||
{'pos_order_lines_ui_args': [(self.product2, 20), (self.product1, 1)], 'payments': [(self.bank_pm1, 410.7)], 'uid': '00100-010-0002'},
|
||||
{'pos_order_lines_ui_args': [(self.product1, 10), (self.product3, 10)], 'payments': [(self.bank_pm1, 426.09)], 'customer': self.customer, 'is_invoiced': True, 'uid': '09876-098-0987'},
|
||||
{'pos_order_lines_ui_args': [(self.product4, 1)], 'payments': [(self.bank_pm1, 54.99)], 'customer': self.customer, 'is_invoiced': True, 'uid': '00100-010-0004'},
|
||||
{'pos_order_lines_ui_args': [(self.product3, 1), (self.product1, 6), (self.product2, 3)], 'uuid': '00100-010-0001'},
|
||||
{'pos_order_lines_ui_args': [(self.product2, 20), (self.product1, 1)], 'payments': [(self.bank_pm1, 410.7)], 'uuid': '00100-010-0002'},
|
||||
{'pos_order_lines_ui_args': [(self.product1, 10), (self.product3, 10)], 'payments': [(self.bank_pm1, 426.09)], 'customer': self.customer, 'is_invoiced': True, 'uuid': '09876-098-0987'},
|
||||
{'pos_order_lines_ui_args': [(self.product4, 1)], 'payments': [(self.bank_pm1, 54.99)], 'customer': self.customer, 'is_invoiced': True, 'uuid': '00100-010-0004'},
|
||||
],
|
||||
'before_closing_cb': _before_closing_cb,
|
||||
'journal_entries_before_closing': {
|
||||
|
|
@ -263,7 +265,7 @@ class TestPoSProductsWithTax(TestPoSCommon):
|
|||
self.assertAlmostEqual(orders_total, self.pos_session.total_payments_amount, msg='Total order amount should be equal to the total payment amount.')
|
||||
|
||||
# return order
|
||||
order_to_return = self.pos_session.order_ids.filtered(lambda order: '12345-123-1234' in order.pos_reference)
|
||||
order_to_return = self.pos_session.order_ids.filtered(lambda order: '12345-123-1234' in order.uuid)
|
||||
order_to_return.refund()
|
||||
|
||||
refund_order = self.pos_session.order_ids.filtered(lambda order: order.state == 'draft')
|
||||
|
|
@ -277,7 +279,7 @@ class TestPoSProductsWithTax(TestPoSCommon):
|
|||
self.assertAlmostEqual(refund_order.amount_paid, -104.01, msg='Amount paid for return order should be negative.')
|
||||
|
||||
def _after_closing_cb():
|
||||
manually_calculated_taxes = (4.01, 6.37) # should be positive since it is return order
|
||||
manually_calculated_taxes = (4.01, 6.36) # should be positive since it is return order
|
||||
tax_lines = self.pos_session.move_id.line_ids.filtered(lambda line: line.account_id == self.tax_received_account)
|
||||
self.assertAlmostEqual(sum(manually_calculated_taxes), sum(tax_lines.mapped('balance')))
|
||||
for t1, t2 in zip(sorted(manually_calculated_taxes), sorted(tax_lines.mapped('balance'))):
|
||||
|
|
@ -286,7 +288,7 @@ class TestPoSProductsWithTax(TestPoSCommon):
|
|||
self._run_test({
|
||||
'payment_methods': self.cash_pm1 | self.bank_pm1,
|
||||
'orders': [
|
||||
{'pos_order_lines_ui_args': [(self.product1, 3), (self.product2, 2), (self.product3, 1)], 'payments': [(self.cash_pm1, 104.01)], 'customer': self.customer, 'is_invoiced': True, 'uid': '12345-123-1234'},
|
||||
{'pos_order_lines_ui_args': [(self.product1, 3), (self.product2, 2), (self.product3, 1)], 'payments': [(self.cash_pm1, 104.01)], 'customer': self.customer, 'is_invoiced': True, 'uuid': '12345-123-1234'},
|
||||
],
|
||||
'before_closing_cb': _before_closing_cb,
|
||||
'journal_entries_before_closing': {
|
||||
|
|
@ -306,9 +308,9 @@ class TestPoSProductsWithTax(TestPoSCommon):
|
|||
'session_journal_entry': {
|
||||
'line_ids': [
|
||||
{'account_id': self.tax_received_account.id, 'partner_id': False, 'debit': 4.01, 'credit': 0, 'reconciled': False},
|
||||
{'account_id': self.tax_received_account.id, 'partner_id': False, 'debit': 6.37, 'credit': 0, 'reconciled': False},
|
||||
{'account_id': self.tax_received_account.id, 'partner_id': False, 'debit': 6.36, 'credit': 0, 'reconciled': False},
|
||||
{'account_id': self.sales_account.id, 'partner_id': False, 'debit': 30, 'credit': 0, 'reconciled': False},
|
||||
{'account_id': self.sales_account.id, 'partner_id': False, 'debit': 36.36, 'credit': 0, 'reconciled': False},
|
||||
{'account_id': self.sales_account.id, 'partner_id': False, 'debit': 36.37, 'credit': 0, 'reconciled': False},
|
||||
{'account_id': self.sales_account.id, 'partner_id': False, 'debit': 27.27, 'credit': 0, 'reconciled': False},
|
||||
{'account_id': self.pos_receivable_account.id, 'partner_id': False, 'debit': 0, 'credit': 104.01, 'reconciled': True},
|
||||
],
|
||||
|
|
@ -344,7 +346,7 @@ class TestPoSProductsWithTax(TestPoSCommon):
|
|||
tax_ids=tax_21_incl.ids,
|
||||
)
|
||||
self.open_new_session()
|
||||
self.env['pos.order'].create_from_ui([self.create_ui_order_data([
|
||||
self.env['pos.order'].sync_from_ui([self.create_ui_order_data([
|
||||
(product1, 1),
|
||||
(product2, -1),
|
||||
])])
|
||||
|
|
@ -390,7 +392,7 @@ class TestPoSProductsWithTax(TestPoSCommon):
|
|||
tax_ids=tax_21_incl.ids,
|
||||
)
|
||||
self.open_new_session()
|
||||
self.env['pos.order'].create_from_ui([self.create_ui_order_data([
|
||||
self.env['pos.order'].sync_from_ui([self.create_ui_order_data([
|
||||
(product1, 1),
|
||||
(product2, -1),
|
||||
])])
|
||||
|
|
@ -436,7 +438,7 @@ class TestPoSProductsWithTax(TestPoSCommon):
|
|||
tax_ids=tax_21_incl.ids,
|
||||
)
|
||||
self.open_new_session()
|
||||
self.env['pos.order'].create_from_ui([self.create_ui_order_data([
|
||||
self.env['pos.order'].sync_from_ui([self.create_ui_order_data([
|
||||
(product1, 1, 10),
|
||||
(product2, -1, 10),
|
||||
])])
|
||||
|
|
@ -483,7 +485,7 @@ class TestPoSProductsWithTax(TestPoSCommon):
|
|||
tax_ids=tax_21_incl.ids,
|
||||
)
|
||||
self.open_new_session()
|
||||
self.env['pos.order'].create_from_ui([self.create_ui_order_data([
|
||||
self.env['pos.order'].sync_from_ui([self.create_ui_order_data([
|
||||
(product1, 6, 5),
|
||||
(product2, -6, 5),
|
||||
])])
|
||||
|
|
@ -529,7 +531,7 @@ class TestPoSProductsWithTax(TestPoSCommon):
|
|||
})
|
||||
|
||||
self.open_new_session()
|
||||
self.env['pos.order'].create_from_ui([self.create_ui_order_data([
|
||||
self.env['pos.order'].sync_from_ui([self.create_ui_order_data([
|
||||
(zero_amount_product, 1),
|
||||
])])
|
||||
self.pos_session.action_pos_session_validate()
|
||||
|
|
@ -541,3 +543,194 @@ class TestPoSProductsWithTax(TestPoSCommon):
|
|||
{'account_id': self.sale_account.id, 'balance': 0},
|
||||
{'account_id': self.cash_pm1.receivable_account_id.id, 'balance': 1},
|
||||
])
|
||||
|
||||
def test_tax_is_used_when_in_transactions(self):
|
||||
''' Ensures that a tax is set to used when it is part of some transactions '''
|
||||
|
||||
# Call another test that uses product_1
|
||||
tax_pos = self.product1.taxes_id
|
||||
self.assertFalse(tax_pos.is_used)
|
||||
self.test_orders_no_invoiced()
|
||||
tax_pos.invalidate_model(fnames=['is_used'])
|
||||
self.assertTrue(tax_pos.is_used)
|
||||
|
||||
def test_pos_loaded_product_taxes_on_branch(self):
|
||||
""" Check loaded product taxes on branch company """
|
||||
# create the following branch hierarchy:
|
||||
# Parent company
|
||||
# |----> Branch X
|
||||
# |----> Branch XX
|
||||
company = self.config.company_id
|
||||
branch_x = self.env['res.company'].create({
|
||||
'name': 'Parent Company',
|
||||
'country_id': company.country_id.id,
|
||||
'parent_id': company.id,
|
||||
})
|
||||
branch_xx = self.env['res.company'].create({
|
||||
'name': 'Branch XX',
|
||||
'country_id': company.country_id.id,
|
||||
'parent_id': branch_x.id,
|
||||
})
|
||||
self.cr.precommit.run() # load the CoA
|
||||
# create taxes for the parent company and its branches
|
||||
tax_groups = self.env['account.tax.group'].create([{
|
||||
'name': 'Tax Group',
|
||||
'company_id': company.id,
|
||||
}, {
|
||||
'name': 'Tax Group X',
|
||||
'company_id': branch_x.id,
|
||||
}, {
|
||||
'name': 'Tax Group XX',
|
||||
'company_id': branch_xx.id,
|
||||
}])
|
||||
tax_a = self.env['account.tax'].create({
|
||||
'name': 'Tax A',
|
||||
'type_tax_use': 'sale',
|
||||
'amount_type': 'percent',
|
||||
'amount': 10,
|
||||
'tax_group_id': tax_groups[0].id,
|
||||
'company_id': company.id,
|
||||
})
|
||||
tax_b = self.env['account.tax'].create({
|
||||
'name': 'Tax B',
|
||||
'type_tax_use': 'sale',
|
||||
'amount_type': 'percent',
|
||||
'amount': 15,
|
||||
'tax_group_id': tax_groups[0].id,
|
||||
'company_id': company.id,
|
||||
})
|
||||
tax_x = self.env['account.tax'].create({
|
||||
'name': 'Tax X',
|
||||
'type_tax_use': 'sale',
|
||||
'amount_type': 'percent',
|
||||
'amount': 20,
|
||||
'tax_group_id': tax_groups[1].id,
|
||||
'company_id': branch_x.id,
|
||||
})
|
||||
tax_xx = self.env['account.tax'].create({
|
||||
'name': 'Tax XX',
|
||||
'type_tax_use': 'sale',
|
||||
'amount_type': 'percent',
|
||||
'amount': 25,
|
||||
'tax_group_id': tax_groups[2].id,
|
||||
'company_id': branch_xx.id,
|
||||
})
|
||||
# create several products with different taxes combination
|
||||
product_all_taxes = self.env['product.product'].create({
|
||||
'name': 'Product all taxes',
|
||||
'available_in_pos': True,
|
||||
'taxes_id': [odoo.Command.set((tax_a + tax_b + tax_x + tax_xx).ids)],
|
||||
})
|
||||
product_no_xx_tax = self.env['product.product'].create({
|
||||
'name': 'Product no tax from XX',
|
||||
'available_in_pos': True,
|
||||
'taxes_id': [odoo.Command.set((tax_a + tax_b + tax_x).ids)],
|
||||
})
|
||||
product_no_branch_tax = self.env['product.product'].create({
|
||||
'name': 'Product no tax from branch',
|
||||
'available_in_pos': True,
|
||||
'taxes_id': [odoo.Command.set((tax_a + tax_b).ids)],
|
||||
})
|
||||
product_no_tax = self.env['product.product'].create({
|
||||
'name': 'Product no tax',
|
||||
'available_in_pos': True,
|
||||
'taxes_id': [],
|
||||
})
|
||||
# configure a session on Branch XX
|
||||
self.xx_bank_journal = self.env['account.journal'].with_company(branch_xx).create({
|
||||
'name': 'Bank',
|
||||
'type': 'bank',
|
||||
'company_id': branch_xx.id,
|
||||
'code': 'BNK',
|
||||
'sequence': 15,
|
||||
})
|
||||
xx_config = self.env['pos.config'].with_company(branch_xx).create({
|
||||
'name': 'Branch XX config',
|
||||
'company_id': branch_xx.id,
|
||||
})
|
||||
xx_account_receivable = self.company_data['default_account_receivable'].copy({'company_ids': [Command.set(branch_xx.ids)]})
|
||||
xx_cash_journal = self.company_data['default_journal_cash'].copy({'company_id': branch_xx.id})
|
||||
xx_cash_payment_method = self.env['pos.payment.method'].create({
|
||||
'name': 'XX Cash Payment',
|
||||
'receivable_account_id': xx_account_receivable.id,
|
||||
'journal_id': xx_cash_journal.id,
|
||||
'company_id': branch_xx.id,
|
||||
})
|
||||
xx_config.write({'payment_method_ids': [
|
||||
odoo.Command.set(xx_cash_payment_method.ids),
|
||||
]})
|
||||
self.config = xx_config
|
||||
pos_session = self.open_new_session()
|
||||
# load the session data from Branch XX:
|
||||
# - Product all taxes => tax from Branch XX should be set
|
||||
# - Product no tax from XX => tax from Branch X should be set
|
||||
# - Product no tax from branch => 2 taxes from parent company should be set
|
||||
# - Product no tax => no tax should be set
|
||||
pos_data = pos_session.load_data([])
|
||||
self.assertEqual(
|
||||
next(iter(filter(lambda p: p['id'] == product_all_taxes.product_tmpl_id.id, pos_data['product.template'])))['taxes_id'],
|
||||
tax_xx.ids
|
||||
)
|
||||
self.assertEqual(
|
||||
next(iter(filter(lambda p: p['id'] == product_no_xx_tax.product_tmpl_id.id, pos_data['product.template'])))['taxes_id'],
|
||||
tax_x.ids
|
||||
)
|
||||
tax_data_no_branch = next(iter(filter(lambda p: p['id'] == product_no_branch_tax.product_tmpl_id.id, pos_data['product.template'])))['taxes_id']
|
||||
tax_data_no_branch.sort()
|
||||
self.assertEqual(
|
||||
tax_data_no_branch,
|
||||
(tax_a + tax_b).ids
|
||||
)
|
||||
self.assertEqual(
|
||||
next(iter(filter(lambda p: p['id'] == product_no_tax.product_tmpl_id.id, pos_data['product.template'])))['taxes_id'],
|
||||
[]
|
||||
)
|
||||
|
||||
pos_user = self.env['res.users'].create({
|
||||
'name': 'Joe Odoo',
|
||||
'login': 'pos_user',
|
||||
'password': 'pos_user',
|
||||
'group_ids': [
|
||||
(4, self.env.ref('base.group_user').id),
|
||||
(4, self.env.ref('point_of_sale.group_pos_user').id),
|
||||
(4, self.env.ref('stock.group_stock_user').id),
|
||||
],
|
||||
'tz': 'America/New_York',
|
||||
'company_id': branch_xx.id,
|
||||
'company_ids': [Command.set([company.id, branch_x.id, branch_xx.id])],
|
||||
})
|
||||
|
||||
def get_taxes_name_popup(product):
|
||||
product = product.product_tmpl_id
|
||||
# In order to simulate the state of the cache when we run this
|
||||
# function over RPC, we need to fetch the below data first,
|
||||
# invalidate our cache, and then enter `get_product_info_pos`
|
||||
# with the arguments already loaded. This is necessary to test
|
||||
# an access rights issue when trying to load product info.
|
||||
branch_xx_id = branch_xx.id
|
||||
xx_config_id = xx_config.id
|
||||
product_all_taxes_lst_price = product_all_taxes.lst_price
|
||||
self.env.invalidate_all()
|
||||
return [tax['name'] for tax in product.with_user(pos_user).with_context(allowed_company_ids=[branch_xx_id]).get_product_info_pos(product_all_taxes_lst_price, 1, xx_config_id)['all_prices']['tax_details']]
|
||||
|
||||
self.assertEqual(get_taxes_name_popup(product_all_taxes), ["Tax XX"])
|
||||
self.assertEqual(get_taxes_name_popup(product_no_xx_tax), ["Tax X"])
|
||||
self.assertEqual(get_taxes_name_popup(product_no_branch_tax), ["Tax A", "Tax B"])
|
||||
self.assertEqual(get_taxes_name_popup(product_no_tax), [])
|
||||
|
||||
def test_combo_product_variant_error(self):
|
||||
"""This tests make sure that product containing variants cannot change type to combo"""
|
||||
|
||||
size_attribute = self.env['product.attribute'].create({'name': 'Size'})
|
||||
a1 = self.env['product.attribute.value'].create({'name': 'V0hFCg==', 'attribute_id': size_attribute.id})
|
||||
self.variant_product = self.env["product.product"].create(
|
||||
{
|
||||
"name": "Test product",
|
||||
"attribute_line_ids": [(0, 0, {
|
||||
"attribute_id": size_attribute.id,
|
||||
"value_ids": [(6, 0, [a1.id])]
|
||||
})],
|
||||
})
|
||||
with self.assertRaises(UserError):
|
||||
with Form(self.variant_product.product_tmpl_id) as product:
|
||||
product.type = "combo"
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@ class TestPoSSetup(TestPoSCommon):
|
|||
# check basic product category
|
||||
# it is expected to have standard and manual_periodic valuation
|
||||
self.assertEqual(self.categ_basic.property_cost_method, 'standard')
|
||||
self.assertEqual(self.categ_basic.property_valuation, 'manual_periodic')
|
||||
self.assertEqual(self.categ_basic.property_valuation, 'periodic')
|
||||
# check anglo saxon product category
|
||||
# this product categ is expected to have fifo and real_time valuation
|
||||
self.assertEqual(self.categ_anglo.property_cost_method, 'fifo')
|
||||
|
|
@ -77,7 +77,14 @@ class TestPoSSetup(TestPoSCommon):
|
|||
self.assertEqual(sorted(tax_group_7_10.children_tax_ids.ids), sorted((tax7 | tax10).ids))
|
||||
|
||||
def test_archive_used_journal(self):
|
||||
journal = self.cash_pm1.journal_id
|
||||
journal = self.env['account.journal'].create({
|
||||
'name': 'BANKOS',
|
||||
'company_id': self.company.id,
|
||||
'code': 'BANKOS',
|
||||
'type': 'bank',
|
||||
'invoice_reference_type': 'invoice',
|
||||
'invoice_reference_model': 'odoo'
|
||||
})
|
||||
payment_method = self.env['pos.payment.method'].create({'name': 'Lets Pay for Tests', 'journal_id': journal.id})
|
||||
self.basic_config.write({'payment_method_ids': [payment_method.id]})
|
||||
journal.write({'pos_payment_method_ids': [payment_method.id]})
|
||||
|
|
@ -111,3 +118,11 @@ class TestPoSSetup(TestPoSCommon):
|
|||
)
|
||||
with self.assertRaises(ValidationError):
|
||||
journal.action_archive()
|
||||
|
||||
def test_card_payment_method_initialization(self):
|
||||
"""Test that the 'Card' payment method created by default has an outstanding account."""
|
||||
card_pm = self.env['pos.payment.method'].search([
|
||||
('name', '=', 'Card'), ('company_id', '=', self.env.company.id),
|
||||
], limit=1)
|
||||
self.assertTrue(card_pm)
|
||||
self.assertTrue(card_pm.outstanding_account_id)
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ class TestPosSimpleInvoicedOrders(TestPoSCommon):
|
|||
self._run_test({
|
||||
'payment_methods': self.cash_pm1,
|
||||
'orders': [
|
||||
{'pos_order_lines_ui_args': [(self.product100, 1)], 'payments': [(self.cash_pm1, 100)], 'customer': self.customer, 'is_invoiced': True, 'uid': '00100-010-0001'},
|
||||
{'pos_order_lines_ui_args': [(self.product100, 1)], 'payments': [(self.cash_pm1, 100)], 'customer': self.customer, 'is_invoiced': True, 'uuid': '00100-010-0001'},
|
||||
],
|
||||
'journal_entries_before_closing': {
|
||||
'00100-010-0001': {
|
||||
|
|
@ -65,7 +65,7 @@ class TestPosSimpleInvoicedOrders(TestPoSCommon):
|
|||
self._run_test({
|
||||
'payment_methods': self.cash_pm1 | self.bank_pm1,
|
||||
'orders': [
|
||||
{'pos_order_lines_ui_args': [(self.product100, 1)], 'payments': [(self.bank_pm1, 100)], 'customer': self.customer, 'is_invoiced': True, 'uid': '00100-010-0001'},
|
||||
{'pos_order_lines_ui_args': [(self.product100, 1)], 'payments': [(self.bank_pm1, 100)], 'customer': self.customer, 'is_invoiced': True, 'uuid': '00100-010-0001'},
|
||||
],
|
||||
'journal_entries_before_closing': {
|
||||
'00100-010-0001': {
|
||||
|
|
@ -112,7 +112,7 @@ class TestPosSimpleInvoicedOrders(TestPoSCommon):
|
|||
self._run_test({
|
||||
'payment_methods': self.cash_pm1 | self.pay_later_pm,
|
||||
'orders': [
|
||||
{'pos_order_lines_ui_args': [(self.product100, 1)], 'payments': [(self.pay_later_pm, 100)], 'customer': self.customer, 'is_invoiced': True, 'uid': '00100-010-0001'},
|
||||
{'pos_order_lines_ui_args': [(self.product100, 1)], 'payments': [(self.pay_later_pm, 100)], 'customer': self.customer, 'is_invoiced': True, 'uuid': '00100-010-0001'},
|
||||
],
|
||||
'journal_entries_before_closing': {
|
||||
'00100-010-0001': {
|
||||
|
|
@ -137,7 +137,7 @@ class TestPosSimpleInvoicedOrders(TestPoSCommon):
|
|||
self._run_test({
|
||||
'payment_methods': self.cash_pm1 | self.bank_split_pm1,
|
||||
'orders': [
|
||||
{'pos_order_lines_ui_args': [(self.product100, 1)], 'payments': [(self.bank_split_pm1, 100)], 'customer': self.customer, 'is_invoiced': True, 'uid': '00100-010-0001'},
|
||||
{'pos_order_lines_ui_args': [(self.product100, 1)], 'payments': [(self.bank_split_pm1, 100)], 'customer': self.customer, 'is_invoiced': True, 'uuid': '00100-010-0001'},
|
||||
],
|
||||
'journal_entries_before_closing': {
|
||||
'00100-010-0001': {
|
||||
|
|
@ -184,7 +184,7 @@ class TestPosSimpleInvoicedOrders(TestPoSCommon):
|
|||
self._run_test({
|
||||
'payment_methods': self.cash_split_pm1,
|
||||
'orders': [
|
||||
{'pos_order_lines_ui_args': [(self.product100, 1)], 'payments': [(self.cash_split_pm1, 100)], 'customer': self.customer, 'is_invoiced': True, 'uid': '00100-010-0001'},
|
||||
{'pos_order_lines_ui_args': [(self.product100, 1)], 'payments': [(self.cash_split_pm1, 100)], 'customer': self.customer, 'is_invoiced': True, 'uuid': '00100-010-0001'},
|
||||
],
|
||||
'journal_entries_before_closing': {
|
||||
'00100-010-0001': {
|
||||
|
|
@ -227,21 +227,20 @@ class TestPosSimpleInvoicedOrders(TestPoSCommon):
|
|||
self._run_test({
|
||||
'payment_methods': self.cash_pm1 | self.pay_later_pm,
|
||||
'orders': [
|
||||
{'pos_order_lines_ui_args': [(self.product100, 1)], 'payments': [(self.cash_pm1, 200), (self.pay_later_pm, -100)], 'customer': self.customer, 'is_invoiced': True, 'uid': '00100-010-0001'},
|
||||
{'pos_order_lines_ui_args': [(self.product100, 1)], 'payments': [(self.cash_pm1, 200), (self.pay_later_pm, -100)], 'customer': self.customer, 'is_invoiced': True, 'uuid': '00100-010-0001'},
|
||||
],
|
||||
'journal_entries_before_closing': {
|
||||
'00100-010-0001': {
|
||||
'invoice': {
|
||||
'line_ids': [
|
||||
{'account_id': self.sales_account.id, 'partner_id': self.customer.id, 'debit': 0, 'credit': 100, 'reconciled': False},
|
||||
{'account_id': self.c1_receivable.id, 'partner_id': self.customer.id, 'debit': 100, 'credit': 0, 'reconciled': True},
|
||||
{'account_id': self.c1_receivable.id, 'partner_id': self.customer.id, 'debit': 100, 'credit': 0, 'reconciled': True, 'partially_reconciled': True},
|
||||
]
|
||||
},
|
||||
'payments': [
|
||||
((self.cash_pm1, 200), {
|
||||
'line_ids': [
|
||||
# needs to check the residual because it's supposed to be partial reconciled
|
||||
{'account_id': self.c1_receivable.id, 'partner_id': self.customer.id, 'debit': 0, 'credit': 200, 'reconciled': False, 'amount_residual': -100},
|
||||
{'account_id': self.c1_receivable.id, 'partner_id': self.customer.id, 'debit': 0, 'credit': 200, 'reconciled': False, 'partially_reconciled': True, 'amount_residual': -100},
|
||||
{'account_id': self.pos_receivable_account.id, 'partner_id': False, 'debit': 200, 'credit': 0, 'reconciled': False, 'amount_residual': 200},
|
||||
]
|
||||
}),
|
||||
|
|
@ -271,21 +270,20 @@ class TestPosSimpleInvoicedOrders(TestPoSCommon):
|
|||
self._run_test({
|
||||
'payment_methods': self.cash_pm1 | self.bank_pm1 | self.pay_later_pm,
|
||||
'orders': [
|
||||
{'pos_order_lines_ui_args': [(self.product100, 1)], 'payments': [(self.bank_pm1, 200), (self.pay_later_pm, -100)], 'customer': self.customer, 'is_invoiced': True, 'uid': '00100-010-0001'},
|
||||
{'pos_order_lines_ui_args': [(self.product100, 1)], 'payments': [(self.bank_pm1, 200), (self.pay_later_pm, -100)], 'customer': self.customer, 'is_invoiced': True, 'uuid': '00100-010-0001'},
|
||||
],
|
||||
'journal_entries_before_closing': {
|
||||
'00100-010-0001': {
|
||||
'invoice': {
|
||||
'line_ids': [
|
||||
{'account_id': self.sales_account.id, 'partner_id': self.customer.id, 'debit': 0, 'credit': 100, 'reconciled': False},
|
||||
{'account_id': self.c1_receivable.id, 'partner_id': self.customer.id, 'debit': 100, 'credit': 0, 'reconciled': True},
|
||||
{'account_id': self.c1_receivable.id, 'partner_id': self.customer.id, 'debit': 100, 'credit': 0, 'reconciled': True, 'partially_reconciled': True},
|
||||
]
|
||||
},
|
||||
'payments': [
|
||||
((self.bank_pm1, 200), {
|
||||
'line_ids': [
|
||||
# needs to check the residual because it's supposed to be partial reconciled
|
||||
{'account_id': self.c1_receivable.id, 'partner_id': self.customer.id, 'debit': 0, 'credit': 200, 'reconciled': False, 'amount_residual': -100},
|
||||
{'account_id': self.c1_receivable.id, 'partner_id': self.customer.id, 'debit': 0, 'credit': 200, 'reconciled': False, 'partially_reconciled': True, 'amount_residual': -100},
|
||||
{'account_id': self.pos_receivable_account.id, 'partner_id': False, 'debit': 200, 'credit': 0, 'reconciled': False, 'amount_residual': 200},
|
||||
]
|
||||
}),
|
||||
|
|
@ -315,21 +313,20 @@ class TestPosSimpleInvoicedOrders(TestPoSCommon):
|
|||
self._run_test({
|
||||
'payment_methods': self.cash_split_pm1 | self.pay_later_pm,
|
||||
'orders': [
|
||||
{'pos_order_lines_ui_args': [(self.product100, 1)], 'payments': [(self.cash_split_pm1, 200), (self.pay_later_pm, -100)], 'customer': self.customer, 'is_invoiced': True, 'uid': '00100-010-0001'},
|
||||
{'pos_order_lines_ui_args': [(self.product100, 1)], 'payments': [(self.cash_split_pm1, 200), (self.pay_later_pm, -100)], 'customer': self.customer, 'is_invoiced': True, 'uuid': '00100-010-0001'},
|
||||
],
|
||||
'journal_entries_before_closing': {
|
||||
'00100-010-0001': {
|
||||
'invoice': {
|
||||
'line_ids': [
|
||||
{'account_id': self.sales_account.id, 'partner_id': self.customer.id, 'debit': 0, 'credit': 100, 'reconciled': False},
|
||||
{'account_id': self.c1_receivable.id, 'partner_id': self.customer.id, 'debit': 100, 'credit': 0, 'reconciled': True},
|
||||
{'account_id': self.c1_receivable.id, 'partner_id': self.customer.id, 'debit': 100, 'credit': 0, 'reconciled': True, 'partially_reconciled': True},
|
||||
]
|
||||
},
|
||||
'payments': [
|
||||
((self.cash_split_pm1, 200), {
|
||||
'line_ids': [
|
||||
# needs to check the residual because it's supposed to be partial reconciled
|
||||
{'account_id': self.c1_receivable.id, 'partner_id': self.customer.id, 'debit': 0, 'credit': 200, 'reconciled': False, 'amount_residual': -100},
|
||||
{'account_id': self.c1_receivable.id, 'partner_id': self.customer.id, 'debit': 0, 'credit': 200, 'reconciled': False, 'partially_reconciled': True, 'amount_residual': -100},
|
||||
{'account_id': self.pos_receivable_account.id, 'partner_id': False, 'debit': 200, 'credit': 0, 'reconciled': False, 'amount_residual': 200},
|
||||
]
|
||||
}),
|
||||
|
|
@ -359,21 +356,20 @@ class TestPosSimpleInvoicedOrders(TestPoSCommon):
|
|||
self._run_test({
|
||||
'payment_methods': self.cash_pm1 | self.bank_split_pm1 | self.pay_later_pm,
|
||||
'orders': [
|
||||
{'pos_order_lines_ui_args': [(self.product100, 1)], 'payments': [(self.bank_split_pm1, 200), (self.pay_later_pm, -100)], 'customer': self.customer, 'is_invoiced': True, 'uid': '00100-010-0001'},
|
||||
{'pos_order_lines_ui_args': [(self.product100, 1)], 'payments': [(self.bank_split_pm1, 200), (self.pay_later_pm, -100)], 'customer': self.customer, 'is_invoiced': True, 'uuid': '00100-010-0001'},
|
||||
],
|
||||
'journal_entries_before_closing': {
|
||||
'00100-010-0001': {
|
||||
'invoice': {
|
||||
'line_ids': [
|
||||
{'account_id': self.sales_account.id, 'partner_id': self.customer.id, 'debit': 0, 'credit': 100, 'reconciled': False},
|
||||
{'account_id': self.c1_receivable.id, 'partner_id': self.customer.id, 'debit': 100, 'credit': 0, 'reconciled': True},
|
||||
{'account_id': self.c1_receivable.id, 'partner_id': self.customer.id, 'debit': 100, 'credit': 0, 'reconciled': True, 'partially_reconciled': True},
|
||||
]
|
||||
},
|
||||
'payments': [
|
||||
((self.bank_split_pm1, 200), {
|
||||
'line_ids': [
|
||||
# needs to check the residual because it's supposed to be partial reconciled
|
||||
{'account_id': self.c1_receivable.id, 'partner_id': self.customer.id, 'debit': 0, 'credit': 200, 'reconciled': False, 'amount_residual': -100},
|
||||
{'account_id': self.c1_receivable.id, 'partner_id': self.customer.id, 'debit': 0, 'credit': 200, 'reconciled': False, 'partially_reconciled': True, 'amount_residual': -100},
|
||||
{'account_id': self.pos_receivable_account.id, 'partner_id': False, 'debit': 200, 'credit': 0, 'reconciled': False, 'amount_residual': 200},
|
||||
]
|
||||
}),
|
||||
|
|
@ -403,7 +399,7 @@ class TestPosSimpleInvoicedOrders(TestPoSCommon):
|
|||
self._run_test({
|
||||
'payment_methods': self.cash_pm1,
|
||||
'orders': [
|
||||
{'pos_order_lines_ui_args': [(self.product100, 1)], 'payments': [(self.cash_pm1, 200), (self.cash_pm1, -100)], 'customer': self.customer, 'is_invoiced': True, 'uid': '00100-010-0001'},
|
||||
{'pos_order_lines_ui_args': [(self.product100, 1)], 'payments': [(self.cash_pm1, 200), (self.cash_pm1, -100)], 'customer': self.customer, 'is_invoiced': True, 'uuid': '00100-010-0001'},
|
||||
],
|
||||
'journal_entries_before_closing': {
|
||||
'00100-010-0001': {
|
||||
|
|
@ -452,7 +448,7 @@ class TestPosSimpleInvoicedOrders(TestPoSCommon):
|
|||
self._run_test({
|
||||
'payment_methods': self.cash_pm1 | self.bank_pm1,
|
||||
'orders': [
|
||||
{'pos_order_lines_ui_args': [(self.product100, 1)], 'payments': [(self.bank_pm1, 200), (self.cash_pm1, -100)], 'customer': self.customer, 'is_invoiced': True, 'uid': '00100-010-0001'},
|
||||
{'pos_order_lines_ui_args': [(self.product100, 1)], 'payments': [(self.bank_pm1, 200), (self.cash_pm1, -100)], 'customer': self.customer, 'is_invoiced': True, 'uuid': '00100-010-0001'},
|
||||
],
|
||||
'journal_entries_before_closing': {
|
||||
'00100-010-0001': {
|
||||
|
|
@ -510,7 +506,7 @@ class TestPosSimpleInvoicedOrders(TestPoSCommon):
|
|||
self._run_test({
|
||||
'payment_methods': self.cash_pm1 | self.bank_split_pm1,
|
||||
'orders': [
|
||||
{'pos_order_lines_ui_args': [(self.product100, 1)], 'payments': [(self.bank_split_pm1, 200), (self.cash_pm1, -100)], 'customer': self.customer, 'is_invoiced': True, 'uid': '00100-010-0001'},
|
||||
{'pos_order_lines_ui_args': [(self.product100, 1)], 'payments': [(self.bank_split_pm1, 200), (self.cash_pm1, -100)], 'customer': self.customer, 'is_invoiced': True, 'uuid': '00100-010-0001'},
|
||||
],
|
||||
'journal_entries_before_closing': {
|
||||
'00100-010-0001': {
|
||||
|
|
@ -568,7 +564,7 @@ class TestPosSimpleInvoicedOrders(TestPoSCommon):
|
|||
self._run_test({
|
||||
'payment_methods': self.cash_split_pm1,
|
||||
'orders': [
|
||||
{'pos_order_lines_ui_args': [(self.product100, 1)], 'payments': [(self.cash_split_pm1, 200), (self.cash_split_pm1, -100)], 'customer': self.customer, 'is_invoiced': True, 'uid': '00100-010-0001'},
|
||||
{'pos_order_lines_ui_args': [(self.product100, 1)], 'payments': [(self.cash_split_pm1, 200), (self.cash_split_pm1, -100)], 'customer': self.customer, 'is_invoiced': True, 'uuid': '00100-010-0001'},
|
||||
],
|
||||
'journal_entries_before_closing': {
|
||||
'00100-010-0001': {
|
||||
|
|
@ -625,21 +621,20 @@ class TestPosSimpleInvoicedOrders(TestPoSCommon):
|
|||
self._run_test({
|
||||
'payment_methods': self.cash_pm1 | self.pay_later_pm,
|
||||
'orders': [
|
||||
{'pos_order_lines_ui_args': [(self.product100, 1)], 'payments': [(self.cash_pm1, 50), (self.pay_later_pm, 50)], 'customer': self.customer, 'is_invoiced': True, 'uid': '00100-010-0001'},
|
||||
{'pos_order_lines_ui_args': [(self.product100, 1)], 'payments': [(self.cash_pm1, 50), (self.pay_later_pm, 50)], 'customer': self.customer, 'is_invoiced': True, 'uuid': '00100-010-0001'},
|
||||
],
|
||||
'journal_entries_before_closing': {
|
||||
'00100-010-0001': {
|
||||
'invoice': {
|
||||
'line_ids': [
|
||||
{'account_id': self.sales_account.id, 'partner_id': self.customer.id, 'debit': 0, 'credit': 100, 'reconciled': False, 'amount_residual': 0},
|
||||
# needs to check the residual because it's supposed to be partial reconciled
|
||||
{'account_id': self.c1_receivable.id, 'partner_id': self.customer.id, 'debit': 100, 'credit': 0, 'reconciled': False, 'amount_residual': 50},
|
||||
{'account_id': self.c1_receivable.id, 'partner_id': self.customer.id, 'debit': 100, 'credit': 0, 'reconciled': False, 'partially_reconciled': True, 'amount_residual': 50},
|
||||
]
|
||||
},
|
||||
'payments': [
|
||||
((self.cash_pm1, 50), {
|
||||
'line_ids': [
|
||||
{'account_id': self.c1_receivable.id, 'partner_id': self.customer.id, 'debit': 0, 'credit': 50, 'reconciled': True},
|
||||
{'account_id': self.c1_receivable.id, 'partner_id': self.customer.id, 'debit': 0, 'credit': 50, 'reconciled': True, 'partially_reconciled': True},
|
||||
{'account_id': self.pos_receivable_account.id, 'partner_id': False, 'debit': 50, 'credit': 0, 'reconciled': False},
|
||||
]
|
||||
}),
|
||||
|
|
@ -669,21 +664,20 @@ class TestPosSimpleInvoicedOrders(TestPoSCommon):
|
|||
self._run_test({
|
||||
'payment_methods': self.cash_pm1 | self.bank_pm1 | self.pay_later_pm,
|
||||
'orders': [
|
||||
{'pos_order_lines_ui_args': [(self.product100, 1)], 'payments': [(self.bank_pm1, 50), (self.pay_later_pm, 50)], 'customer': self.customer, 'is_invoiced': True, 'uid': '00100-010-0001'},
|
||||
{'pos_order_lines_ui_args': [(self.product100, 1)], 'payments': [(self.bank_pm1, 50), (self.pay_later_pm, 50)], 'customer': self.customer, 'is_invoiced': True, 'uuid': '00100-010-0001'},
|
||||
],
|
||||
'journal_entries_before_closing': {
|
||||
'00100-010-0001': {
|
||||
'invoice': {
|
||||
'line_ids': [
|
||||
{'account_id': self.sales_account.id, 'partner_id': self.customer.id, 'debit': 0, 'credit': 100, 'reconciled': False, 'amount_residual': 0},
|
||||
# needs to check the residual because it's supposed to be partial reconciled
|
||||
{'account_id': self.c1_receivable.id, 'partner_id': self.customer.id, 'debit': 100, 'credit': 0, 'reconciled': False, 'amount_residual': 50},
|
||||
{'account_id': self.c1_receivable.id, 'partner_id': self.customer.id, 'debit': 100, 'credit': 0, 'reconciled': False, 'partially_reconciled': True, 'amount_residual': 50},
|
||||
]
|
||||
},
|
||||
'payments': [
|
||||
((self.bank_pm1, 50), {
|
||||
'line_ids': [
|
||||
{'account_id': self.c1_receivable.id, 'partner_id': self.customer.id, 'debit': 0, 'credit': 50, 'reconciled': True},
|
||||
{'account_id': self.c1_receivable.id, 'partner_id': self.customer.id, 'debit': 0, 'credit': 50, 'reconciled': True, 'partially_reconciled': True},
|
||||
{'account_id': self.pos_receivable_account.id, 'partner_id': False, 'debit': 50, 'credit': 0, 'reconciled': False},
|
||||
]
|
||||
}),
|
||||
|
|
@ -713,21 +707,20 @@ class TestPosSimpleInvoicedOrders(TestPoSCommon):
|
|||
self._run_test({
|
||||
'payment_methods': self.cash_pm1 | self.bank_split_pm1 | self.pay_later_pm,
|
||||
'orders': [
|
||||
{'pos_order_lines_ui_args': [(self.product100, 1)], 'payments': [(self.bank_split_pm1, 50), (self.pay_later_pm, 50)], 'customer': self.customer, 'is_invoiced': True, 'uid': '00100-010-0001'},
|
||||
{'pos_order_lines_ui_args': [(self.product100, 1)], 'payments': [(self.bank_split_pm1, 50), (self.pay_later_pm, 50)], 'customer': self.customer, 'is_invoiced': True, 'uuid': '00100-010-0001'},
|
||||
],
|
||||
'journal_entries_before_closing': {
|
||||
'00100-010-0001': {
|
||||
'invoice': {
|
||||
'line_ids': [
|
||||
{'account_id': self.sales_account.id, 'partner_id': self.customer.id, 'debit': 0, 'credit': 100, 'reconciled': False, 'amount_residual': 0},
|
||||
# needs to check the residual because it's supposed to be partial reconciled
|
||||
{'account_id': self.c1_receivable.id, 'partner_id': self.customer.id, 'debit': 100, 'credit': 0, 'reconciled': False, 'amount_residual': 50},
|
||||
{'account_id': self.c1_receivable.id, 'partner_id': self.customer.id, 'debit': 100, 'credit': 0, 'reconciled': False, 'partially_reconciled': True, 'amount_residual': 50},
|
||||
]
|
||||
},
|
||||
'payments': [
|
||||
((self.bank_split_pm1, 50), {
|
||||
'line_ids': [
|
||||
{'account_id': self.c1_receivable.id, 'partner_id': self.customer.id, 'debit': 0, 'credit': 50, 'reconciled': True},
|
||||
{'account_id': self.c1_receivable.id, 'partner_id': self.customer.id, 'debit': 0, 'credit': 50, 'reconciled': True, 'partially_reconciled': True},
|
||||
{'account_id': self.pos_receivable_account.id, 'partner_id': False, 'debit': 50, 'credit': 0, 'reconciled': False},
|
||||
]
|
||||
}),
|
||||
|
|
@ -757,21 +750,20 @@ class TestPosSimpleInvoicedOrders(TestPoSCommon):
|
|||
self._run_test({
|
||||
'payment_methods': self.cash_split_pm1 | self.pay_later_pm,
|
||||
'orders': [
|
||||
{'pos_order_lines_ui_args': [(self.product100, 1)], 'payments': [(self.cash_split_pm1, 50), (self.pay_later_pm, 50)], 'customer': self.customer, 'is_invoiced': True, 'uid': '00100-010-0001'},
|
||||
{'pos_order_lines_ui_args': [(self.product100, 1)], 'payments': [(self.cash_split_pm1, 50), (self.pay_later_pm, 50)], 'customer': self.customer, 'is_invoiced': True, 'uuid': '00100-010-0001'},
|
||||
],
|
||||
'journal_entries_before_closing': {
|
||||
'00100-010-0001': {
|
||||
'invoice': {
|
||||
'line_ids': [
|
||||
{'account_id': self.sales_account.id, 'partner_id': self.customer.id, 'debit': 0, 'credit': 100, 'reconciled': False, 'amount_residual': 0},
|
||||
# needs to check the residual because it's supposed to be partial reconciled
|
||||
{'account_id': self.c1_receivable.id, 'partner_id': self.customer.id, 'debit': 100, 'credit': 0, 'reconciled': False, 'amount_residual': 50},
|
||||
{'account_id': self.c1_receivable.id, 'partner_id': self.customer.id, 'debit': 100, 'credit': 0, 'reconciled': False, 'partially_reconciled': True, 'amount_residual': 50},
|
||||
]
|
||||
},
|
||||
'payments': [
|
||||
((self.cash_split_pm1, 50), {
|
||||
'line_ids': [
|
||||
{'account_id': self.c1_receivable.id, 'partner_id': self.customer.id, 'debit': 0, 'credit': 50, 'reconciled': True},
|
||||
{'account_id': self.c1_receivable.id, 'partner_id': self.customer.id, 'debit': 0, 'credit': 50, 'reconciled': True, 'partially_reconciled': True},
|
||||
{'account_id': self.pos_receivable_account.id, 'partner_id': False, 'debit': 50, 'credit': 0, 'reconciled': False},
|
||||
]
|
||||
}),
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ class TestPosSimpleOrders(TestPoSCommon):
|
|||
self._run_test({
|
||||
'payment_methods': self.cash_pm1,
|
||||
'orders': [
|
||||
{'pos_order_lines_ui_args': [(self.product100, 1)], 'payments': [(self.cash_pm1, 100)], 'customer': self.customer, 'is_invoiced': False, 'uid': '00100-010-0001'},
|
||||
{'pos_order_lines_ui_args': [(self.product100, 1)], 'payments': [(self.cash_pm1, 100)], 'customer': self.customer, 'is_invoiced': False, 'uuid': '00100-010-0001'},
|
||||
],
|
||||
'journal_entries_before_closing': {},
|
||||
'journal_entries_after_closing': {
|
||||
|
|
@ -48,7 +48,7 @@ class TestPosSimpleOrders(TestPoSCommon):
|
|||
self._run_test({
|
||||
'payment_methods': self.cash_pm1 | self.bank_pm1,
|
||||
'orders': [
|
||||
{'pos_order_lines_ui_args': [(self.product100, 1)], 'payments': [(self.bank_pm1, 100)], 'customer': self.customer, 'is_invoiced': False, 'uid': '00100-010-0001'},
|
||||
{'pos_order_lines_ui_args': [(self.product100, 1)], 'payments': [(self.bank_pm1, 100)], 'customer': self.customer, 'is_invoiced': False, 'uuid': '00100-010-0001'},
|
||||
],
|
||||
'journal_entries_before_closing': {},
|
||||
'journal_entries_after_closing': {
|
||||
|
|
@ -74,7 +74,7 @@ class TestPosSimpleOrders(TestPoSCommon):
|
|||
self._run_test({
|
||||
'payment_methods': self.cash_pm1 | self.pay_later_pm,
|
||||
'orders': [
|
||||
{'pos_order_lines_ui_args': [(self.product100, 1)], 'payments': [(self.pay_later_pm, 100)], 'customer': self.customer, 'is_invoiced': False, 'uid': '00100-010-0001'},
|
||||
{'pos_order_lines_ui_args': [(self.product100, 1)], 'payments': [(self.pay_later_pm, 100)], 'customer': self.customer, 'is_invoiced': False, 'uuid': '00100-010-0001'},
|
||||
],
|
||||
'journal_entries_before_closing': {},
|
||||
'journal_entries_after_closing': {
|
||||
|
|
@ -93,7 +93,7 @@ class TestPosSimpleOrders(TestPoSCommon):
|
|||
self._run_test({
|
||||
'payment_methods': self.cash_pm1 | self.bank_split_pm1,
|
||||
'orders': [
|
||||
{'pos_order_lines_ui_args': [(self.product100, 1)], 'payments': [(self.bank_split_pm1, 100)], 'customer': self.customer, 'is_invoiced': False, 'uid': '00100-010-0001'},
|
||||
{'pos_order_lines_ui_args': [(self.product100, 1)], 'payments': [(self.bank_split_pm1, 100)], 'customer': self.customer, 'is_invoiced': False, 'uuid': '00100-010-0001'},
|
||||
],
|
||||
'journal_entries_before_closing': {},
|
||||
'journal_entries_after_closing': {
|
||||
|
|
@ -119,7 +119,7 @@ class TestPosSimpleOrders(TestPoSCommon):
|
|||
self._run_test({
|
||||
'payment_methods': self.cash_split_pm1,
|
||||
'orders': [
|
||||
{'pos_order_lines_ui_args': [(self.product100, 1)], 'payments': [(self.cash_split_pm1, 100)], 'customer': self.customer, 'is_invoiced': False, 'uid': '00100-010-0001'},
|
||||
{'pos_order_lines_ui_args': [(self.product100, 1)], 'payments': [(self.cash_split_pm1, 100)], 'customer': self.customer, 'is_invoiced': False, 'uuid': '00100-010-0001'},
|
||||
],
|
||||
'journal_entries_before_closing': {},
|
||||
'journal_entries_after_closing': {
|
||||
|
|
@ -145,7 +145,7 @@ class TestPosSimpleOrders(TestPoSCommon):
|
|||
self._run_test({
|
||||
'payment_methods': self.cash_pm1 | self.pay_later_pm,
|
||||
'orders': [
|
||||
{'pos_order_lines_ui_args': [], 'payments': [(self.cash_pm1, 100), (self.pay_later_pm, -100)], 'customer': self.customer, 'is_invoiced': False, 'uid': '00100-010-0001'},
|
||||
{'pos_order_lines_ui_args': [], 'payments': [(self.cash_pm1, 100), (self.pay_later_pm, -100)], 'customer': self.customer, 'is_invoiced': False, 'uuid': '00100-010-0001'},
|
||||
],
|
||||
'journal_entries_before_closing': {},
|
||||
'journal_entries_after_closing': {
|
||||
|
|
@ -171,7 +171,7 @@ class TestPosSimpleOrders(TestPoSCommon):
|
|||
self._run_test({
|
||||
'payment_methods': self.cash_pm1 | self.bank_pm1 | self.pay_later_pm,
|
||||
'orders': [
|
||||
{'pos_order_lines_ui_args': [], 'payments': [(self.bank_pm1, 100), (self.pay_later_pm, -100)], 'customer': self.customer, 'is_invoiced': False, 'uid': '00100-010-0001'},
|
||||
{'pos_order_lines_ui_args': [], 'payments': [(self.bank_pm1, 100), (self.pay_later_pm, -100)], 'customer': self.customer, 'is_invoiced': False, 'uuid': '00100-010-0001'},
|
||||
],
|
||||
'journal_entries_before_closing': {},
|
||||
'journal_entries_after_closing': {
|
||||
|
|
@ -197,7 +197,7 @@ class TestPosSimpleOrders(TestPoSCommon):
|
|||
self._run_test({
|
||||
'payment_methods': self.cash_pm1 | self.bank_split_pm1 | self.pay_later_pm,
|
||||
'orders': [
|
||||
{'pos_order_lines_ui_args': [], 'payments': [(self.bank_split_pm1, 100), (self.pay_later_pm, -100)], 'customer': self.customer, 'is_invoiced': False, 'uid': '00100-010-0001'},
|
||||
{'pos_order_lines_ui_args': [], 'payments': [(self.bank_split_pm1, 100), (self.pay_later_pm, -100)], 'customer': self.customer, 'is_invoiced': False, 'uuid': '00100-010-0001'},
|
||||
],
|
||||
'journal_entries_before_closing': {},
|
||||
'journal_entries_after_closing': {
|
||||
|
|
@ -223,7 +223,7 @@ class TestPosSimpleOrders(TestPoSCommon):
|
|||
self._run_test({
|
||||
'payment_methods': self.cash_split_pm1 | self.pay_later_pm,
|
||||
'orders': [
|
||||
{'pos_order_lines_ui_args': [], 'payments': [(self.cash_split_pm1, 100), (self.pay_later_pm, -100)], 'customer': self.customer, 'is_invoiced': False, 'uid': '00100-010-0001'},
|
||||
{'pos_order_lines_ui_args': [], 'payments': [(self.cash_split_pm1, 100), (self.pay_later_pm, -100)], 'customer': self.customer, 'is_invoiced': False, 'uuid': '00100-010-0001'},
|
||||
],
|
||||
'journal_entries_before_closing': {},
|
||||
'journal_entries_after_closing': {
|
||||
|
|
@ -249,7 +249,7 @@ class TestPosSimpleOrders(TestPoSCommon):
|
|||
self._run_test({
|
||||
'payment_methods': self.cash_pm1 | self.pay_later_pm,
|
||||
'orders': [
|
||||
{'pos_order_lines_ui_args': [(self.product100, 1)], 'payments': [(self.cash_pm1, 200), (self.pay_later_pm, -100)], 'customer': self.customer, 'is_invoiced': False, 'uid': '00100-010-0001'},
|
||||
{'pos_order_lines_ui_args': [(self.product100, 1)], 'payments': [(self.cash_pm1, 200), (self.pay_later_pm, -100)], 'customer': self.customer, 'is_invoiced': False, 'uuid': '00100-010-0001'},
|
||||
],
|
||||
'journal_entries_before_closing': {},
|
||||
'journal_entries_after_closing': {
|
||||
|
|
@ -276,7 +276,7 @@ class TestPosSimpleOrders(TestPoSCommon):
|
|||
self._run_test({
|
||||
'payment_methods': self.cash_pm1 | self.bank_pm1 | self.pay_later_pm,
|
||||
'orders': [
|
||||
{'pos_order_lines_ui_args': [(self.product100, 1)], 'payments': [(self.bank_pm1, 200), (self.pay_later_pm, -100)], 'customer': self.customer, 'is_invoiced': False, 'uid': '00100-010-0001'},
|
||||
{'pos_order_lines_ui_args': [(self.product100, 1)], 'payments': [(self.bank_pm1, 200), (self.pay_later_pm, -100)], 'customer': self.customer, 'is_invoiced': False, 'uuid': '00100-010-0001'},
|
||||
],
|
||||
'journal_entries_before_closing': {},
|
||||
'journal_entries_after_closing': {
|
||||
|
|
@ -303,7 +303,7 @@ class TestPosSimpleOrders(TestPoSCommon):
|
|||
self._run_test({
|
||||
'payment_methods': self.cash_split_pm1 | self.pay_later_pm,
|
||||
'orders': [
|
||||
{'pos_order_lines_ui_args': [(self.product100, 1)], 'payments': [(self.cash_split_pm1, 200), (self.pay_later_pm, -100)], 'customer': self.customer, 'is_invoiced': False, 'uid': '00100-010-0001'},
|
||||
{'pos_order_lines_ui_args': [(self.product100, 1)], 'payments': [(self.cash_split_pm1, 200), (self.pay_later_pm, -100)], 'customer': self.customer, 'is_invoiced': False, 'uuid': '00100-010-0001'},
|
||||
],
|
||||
'journal_entries_before_closing': {},
|
||||
'journal_entries_after_closing': {
|
||||
|
|
@ -330,7 +330,7 @@ class TestPosSimpleOrders(TestPoSCommon):
|
|||
self._run_test({
|
||||
'payment_methods': self.cash_pm1 | self.bank_split_pm1 | self.pay_later_pm,
|
||||
'orders': [
|
||||
{'pos_order_lines_ui_args': [(self.product100, 1)], 'payments': [(self.bank_split_pm1, 200), (self.pay_later_pm, -100)], 'customer': self.customer, 'is_invoiced': False, 'uid': '00100-010-0001'},
|
||||
{'pos_order_lines_ui_args': [(self.product100, 1)], 'payments': [(self.bank_split_pm1, 200), (self.pay_later_pm, -100)], 'customer': self.customer, 'is_invoiced': False, 'uuid': '00100-010-0001'},
|
||||
],
|
||||
'journal_entries_before_closing': {},
|
||||
'journal_entries_after_closing': {
|
||||
|
|
@ -357,7 +357,7 @@ class TestPosSimpleOrders(TestPoSCommon):
|
|||
self._run_test({
|
||||
'payment_methods': self.cash_pm1,
|
||||
'orders': [
|
||||
{'pos_order_lines_ui_args': [(self.product100, 1)], 'payments': [(self.cash_pm1, 200), (self.cash_pm1, -100)], 'customer': self.customer, 'is_invoiced': False, 'uid': '00100-010-0001'},
|
||||
{'pos_order_lines_ui_args': [(self.product100, 1)], 'payments': [(self.cash_pm1, 200), (self.cash_pm1, -100)], 'customer': self.customer, 'is_invoiced': False, 'uuid': '00100-010-0001'},
|
||||
],
|
||||
'journal_entries_before_closing': {},
|
||||
'journal_entries_after_closing': {
|
||||
|
|
@ -383,7 +383,7 @@ class TestPosSimpleOrders(TestPoSCommon):
|
|||
self._run_test({
|
||||
'payment_methods': self.cash_pm1 | self.bank_pm1,
|
||||
'orders': [
|
||||
{'pos_order_lines_ui_args': [(self.product100, 1)], 'payments': [(self.bank_pm1, 200), (self.cash_pm1, -100)], 'customer': self.customer, 'is_invoiced': False, 'uid': '00100-010-0001'},
|
||||
{'pos_order_lines_ui_args': [(self.product100, 1)], 'payments': [(self.bank_pm1, 200), (self.cash_pm1, -100)], 'customer': self.customer, 'is_invoiced': False, 'uuid': '00100-010-0001'},
|
||||
],
|
||||
'journal_entries_before_closing': {},
|
||||
'journal_entries_after_closing': {
|
||||
|
|
@ -417,7 +417,7 @@ class TestPosSimpleOrders(TestPoSCommon):
|
|||
self._run_test({
|
||||
'payment_methods': self.cash_pm1 | self.bank_split_pm1,
|
||||
'orders': [
|
||||
{'pos_order_lines_ui_args': [(self.product100, 1)], 'payments': [(self.bank_split_pm1, 200), (self.cash_pm1, -100)], 'customer': self.customer, 'is_invoiced': False, 'uid': '00100-010-0001'},
|
||||
{'pos_order_lines_ui_args': [(self.product100, 1)], 'payments': [(self.bank_split_pm1, 200), (self.cash_pm1, -100)], 'customer': self.customer, 'is_invoiced': False, 'uuid': '00100-010-0001'},
|
||||
],
|
||||
'journal_entries_before_closing': {},
|
||||
'journal_entries_after_closing': {
|
||||
|
|
@ -451,7 +451,7 @@ class TestPosSimpleOrders(TestPoSCommon):
|
|||
self._run_test({
|
||||
'payment_methods': self.cash_split_pm1,
|
||||
'orders': [
|
||||
{'pos_order_lines_ui_args': [(self.product100, 1)], 'payments': [(self.cash_split_pm1, 200), (self.cash_split_pm1, -100)], 'customer': self.customer, 'is_invoiced': False, 'uid': '00100-010-0001'},
|
||||
{'pos_order_lines_ui_args': [(self.product100, 1)], 'payments': [(self.cash_split_pm1, 200), (self.cash_split_pm1, -100)], 'customer': self.customer, 'is_invoiced': False, 'uuid': '00100-010-0001'},
|
||||
],
|
||||
'journal_entries_before_closing': {},
|
||||
'journal_entries_after_closing': {
|
||||
|
|
@ -484,7 +484,7 @@ class TestPosSimpleOrders(TestPoSCommon):
|
|||
self._run_test({
|
||||
'payment_methods': self.cash_pm1 | self.pay_later_pm,
|
||||
'orders': [
|
||||
{'pos_order_lines_ui_args': [(self.product100, 1)], 'payments': [(self.cash_pm1, 50), (self.pay_later_pm, 50)], 'customer': self.customer, 'is_invoiced': False, 'uid': '00100-010-0001'},
|
||||
{'pos_order_lines_ui_args': [(self.product100, 1)], 'payments': [(self.cash_pm1, 50), (self.pay_later_pm, 50)], 'customer': self.customer, 'is_invoiced': False, 'uuid': '00100-010-0001'},
|
||||
],
|
||||
'journal_entries_before_closing': {},
|
||||
'journal_entries_after_closing': {
|
||||
|
|
@ -511,7 +511,7 @@ class TestPosSimpleOrders(TestPoSCommon):
|
|||
self._run_test({
|
||||
'payment_methods': self.cash_pm1 | self.bank_pm1 | self.pay_later_pm,
|
||||
'orders': [
|
||||
{'pos_order_lines_ui_args': [(self.product100, 1)], 'payments': [(self.bank_pm1, 50), (self.pay_later_pm, 50)], 'customer': self.customer, 'is_invoiced': False, 'uid': '00100-010-0001'},
|
||||
{'pos_order_lines_ui_args': [(self.product100, 1)], 'payments': [(self.bank_pm1, 50), (self.pay_later_pm, 50)], 'customer': self.customer, 'is_invoiced': False, 'uuid': '00100-010-0001'},
|
||||
],
|
||||
'journal_entries_before_closing': {},
|
||||
'journal_entries_after_closing': {
|
||||
|
|
@ -538,7 +538,7 @@ class TestPosSimpleOrders(TestPoSCommon):
|
|||
self._run_test({
|
||||
'payment_methods': self.cash_pm1 | self.bank_split_pm1 | self.pay_later_pm,
|
||||
'orders': [
|
||||
{'pos_order_lines_ui_args': [(self.product100, 1)], 'payments': [(self.bank_split_pm1, 50), (self.pay_later_pm, 50)], 'customer': self.customer, 'is_invoiced': False, 'uid': '00100-010-0001'},
|
||||
{'pos_order_lines_ui_args': [(self.product100, 1)], 'payments': [(self.bank_split_pm1, 50), (self.pay_later_pm, 50)], 'customer': self.customer, 'is_invoiced': False, 'uuid': '00100-010-0001'},
|
||||
],
|
||||
'journal_entries_before_closing': {},
|
||||
'journal_entries_after_closing': {
|
||||
|
|
@ -565,7 +565,7 @@ class TestPosSimpleOrders(TestPoSCommon):
|
|||
self._run_test({
|
||||
'payment_methods': self.cash_split_pm1 | self.pay_later_pm,
|
||||
'orders': [
|
||||
{'pos_order_lines_ui_args': [(self.product100, 1)], 'payments': [(self.cash_split_pm1, 50), (self.pay_later_pm, 50)], 'customer': self.customer, 'is_invoiced': False, 'uid': '00100-010-0001'},
|
||||
{'pos_order_lines_ui_args': [(self.product100, 1)], 'payments': [(self.cash_split_pm1, 50), (self.pay_later_pm, 50)], 'customer': self.customer, 'is_invoiced': False, 'uuid': '00100-010-0001'},
|
||||
],
|
||||
'journal_entries_before_closing': {},
|
||||
'journal_entries_after_closing': {
|
||||
|
|
|
|||
|
|
@ -1,11 +1,15 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from unittest import skip
|
||||
|
||||
from odoo import tools
|
||||
import odoo
|
||||
from odoo.addons.point_of_sale.tests.common import TestPoSCommon
|
||||
|
||||
|
||||
@odoo.tests.tagged('post_install', '-at_install')
|
||||
@skip('Temporary to fast merge new valuation')
|
||||
class TestPoSStock(TestPoSCommon):
|
||||
""" Tests for anglo saxon accounting scenario.
|
||||
"""
|
||||
|
|
@ -16,6 +20,9 @@ class TestPoSStock(TestPoSCommon):
|
|||
self.product1 = self.create_product('Product 1', self.categ_anglo, 10.0, 5.0)
|
||||
self.product2 = self.create_product('Product 2', self.categ_anglo, 20.0, 10.0)
|
||||
self.product3 = self.create_product('Product 3', self.categ_basic, 30.0, 15.0)
|
||||
self.product4 = self.create_product('Product 4', self.categ_anglo, 10.0, 5.0)
|
||||
self.product4.type = 'consu'
|
||||
self.product4.is_storable = False
|
||||
# start inventory with 10 items for each product
|
||||
self.adjust_inventory([self.product1, self.product2, self.product3], [10, 10, 10])
|
||||
|
||||
|
|
@ -53,14 +60,16 @@ class TestPoSStock(TestPoSCommon):
|
|||
| | product2 | 6 | 120.0 | 78.0 | -> 6 items at cost of 13.0, remains 2 items at cost of 13.0
|
||||
| | product3 | 6 | 180.0 | 0.0 |
|
||||
+---------+----------+-----+-------------+------------+
|
||||
| order 4 | product4 | 6 | 60.0 | 0.0 | -> consumable product cost = 0
|
||||
+---------+----------+-----+-------------+------------+
|
||||
|
||||
Expected Result
|
||||
===============
|
||||
+---------------------+---------+
|
||||
| account | balance |
|
||||
+---------------------+---------+
|
||||
| sale_account | -1010.0 |
|
||||
| pos_receivable-cash | 1010.0 |
|
||||
| sale_account | -1070.0 |
|
||||
| pos_receivable-cash | 1070.0 |
|
||||
| expense_account | 327.0 |
|
||||
| output_account | -327.0 |
|
||||
+---------------------+---------+
|
||||
|
|
@ -70,10 +79,10 @@ class TestPoSStock(TestPoSCommon):
|
|||
|
||||
def _before_closing_cb():
|
||||
# check values before closing the session
|
||||
self.assertEqual(3, self.pos_session.order_count)
|
||||
self.assertEqual(4, self.pos_session.order_count)
|
||||
orders_total = sum(order.amount_total for order in self.pos_session.order_ids)
|
||||
self.assertAlmostEqual(orders_total, self.pos_session.total_payments_amount, msg='Total order amount should be equal to the total payment amount.')
|
||||
self.assertAlmostEqual(orders_total, 1010.0, msg='The orders\'s total amount should equal the computed.')
|
||||
self.assertAlmostEqual(orders_total, 1070.0, msg='The orders\'s total amount should equal the computed.')
|
||||
|
||||
# check product qty_available after syncing the order
|
||||
self.assertEqual(self.product1.qty_available, 9)
|
||||
|
|
@ -88,26 +97,27 @@ class TestPoSStock(TestPoSCommon):
|
|||
self._run_test({
|
||||
'payment_methods': self.cash_pm1 | self.bank_pm1,
|
||||
'orders': [
|
||||
{'pos_order_lines_ui_args': [(self.product1, 10), (self.product2, 10)], 'uid': '00100-010-0001'},
|
||||
{'pos_order_lines_ui_args': [(self.product2, 7), (self.product3, 7)], 'uid': '00100-010-0002'},
|
||||
{'pos_order_lines_ui_args': [(self.product1, 6), (self.product2, 6), (self.product3, 6)], 'uid': '00100-010-0003'},
|
||||
{'pos_order_lines_ui_args': [(self.product1, 10), (self.product2, 10)], 'uuid': '00100-010-0001'},
|
||||
{'pos_order_lines_ui_args': [(self.product2, 7), (self.product3, 7)], 'uuid': '00100-010-0002'},
|
||||
{'pos_order_lines_ui_args': [(self.product1, 6), (self.product2, 6), (self.product3, 6)], 'uuid': '00100-010-0003'},
|
||||
{'pos_order_lines_ui_args': [(self.product4, 6)], 'uuid': '00100-010-0004'},
|
||||
],
|
||||
'before_closing_cb': _before_closing_cb,
|
||||
'journal_entries_before_closing': {},
|
||||
'journal_entries_after_closing': {
|
||||
'session_journal_entry': {
|
||||
'line_ids': [
|
||||
{'account_id': self.sales_account.id, 'partner_id': False, 'debit': 0, 'credit': 1010.0, 'reconciled': False},
|
||||
{'account_id': self.sales_account.id, 'partner_id': False, 'debit': 0, 'credit': 1070.0, 'reconciled': False},
|
||||
{'account_id': self.expense_account.id, 'partner_id': False, 'debit': 327, 'credit': 0, 'reconciled': False},
|
||||
{'account_id': self.cash_pm1.receivable_account_id.id, 'partner_id': False, 'debit': 1010.0, 'credit': 0, 'reconciled': True},
|
||||
{'account_id': self.cash_pm1.receivable_account_id.id, 'partner_id': False, 'debit': 1070.0, 'credit': 0, 'reconciled': True},
|
||||
{'account_id': self.output_account.id, 'partner_id': False, 'debit': 0, 'credit': 327, 'reconciled': True},
|
||||
],
|
||||
},
|
||||
'cash_statement': [
|
||||
((1010.0, ), {
|
||||
((1070.0, ), {
|
||||
'line_ids': [
|
||||
{'account_id': self.cash_pm1.journal_id.default_account_id.id, 'partner_id': False, 'debit': 1010.0, 'credit': 0, 'reconciled': False},
|
||||
{'account_id': self.cash_pm1.receivable_account_id.id, 'partner_id': False, 'debit': 0, 'credit': 1010.0, 'reconciled': True},
|
||||
{'account_id': self.cash_pm1.journal_id.default_account_id.id, 'partner_id': False, 'debit': 1070.0, 'credit': 0, 'reconciled': False},
|
||||
{'account_id': self.cash_pm1.receivable_account_id.id, 'partner_id': False, 'debit': 0, 'credit': 1070.0, 'reconciled': True},
|
||||
]
|
||||
}),
|
||||
],
|
||||
|
|
@ -157,9 +167,9 @@ class TestPoSStock(TestPoSCommon):
|
|||
self._run_test({
|
||||
'payment_methods': self.cash_pm1 | self.bank_pm1,
|
||||
'orders': [
|
||||
{'pos_order_lines_ui_args': [(self.product1, 10), (self.product2, 10)], 'uid': '00100-010-0001'},
|
||||
{'pos_order_lines_ui_args': [(self.product2, 7), (self.product3, 7)], 'uid': '00100-010-0002'},
|
||||
{'pos_order_lines_ui_args': [(self.product1, 6), (self.product2, 6), (self.product3, 6)], 'is_invoiced': True, 'customer': self.customer, 'uid': '00100-010-0003'},
|
||||
{'pos_order_lines_ui_args': [(self.product1, 10), (self.product2, 10)], 'uuid': '00100-010-0001'},
|
||||
{'pos_order_lines_ui_args': [(self.product2, 7), (self.product3, 7)], 'uuid': '00100-010-0002'},
|
||||
{'pos_order_lines_ui_args': [(self.product1, 6), (self.product2, 6), (self.product3, 6)], 'is_invoiced': True, 'customer': self.customer, 'uuid': '00100-010-0003'},
|
||||
],
|
||||
'before_closing_cb': _before_closing_cb,
|
||||
'journal_entries_before_closing': {
|
||||
|
|
@ -203,7 +213,7 @@ class TestPoSStock(TestPoSCommon):
|
|||
"""
|
||||
|
||||
group_owner = self.env.ref('stock.group_tracking_owner')
|
||||
self.env.user.write({'groups_id': [(4, group_owner.id)]})
|
||||
self.env.user.write({'group_ids': [(4, group_owner.id)]})
|
||||
self.product4 = self.create_product('Product 3', self.categ_basic, 30.0, 15.0)
|
||||
self.env['stock.quant'].with_context(inventory_mode=True).create({
|
||||
'product_id': self.product4.id,
|
||||
|
|
@ -219,7 +229,7 @@ class TestPoSStock(TestPoSCommon):
|
|||
orders.append(self.create_ui_order_data([(self.product4, 1)]))
|
||||
|
||||
# sync orders
|
||||
order = self.env['pos.order'].create_from_ui(orders)
|
||||
order = self.env['pos.order'].sync_from_ui(orders)
|
||||
|
||||
# check values before closing the session
|
||||
self.assertEqual(1, self.pos_session.order_count)
|
||||
|
|
@ -247,9 +257,9 @@ class TestPoSStock(TestPoSCommon):
|
|||
self.open_new_session()
|
||||
orders = []
|
||||
orders.append(self.create_ui_order_data([(self.product4, 1)]))
|
||||
order = self.env['pos.order'].create_from_ui(orders)
|
||||
order = self.env['pos.order'].sync_from_ui(orders)
|
||||
|
||||
refund_action = self.env['pos.order'].browse(order[0]['id']).refund()
|
||||
refund_action = self.env['pos.order'].browse(order['pos.order'][0]['id']).refund()
|
||||
refund = self.env['pos.order'].browse(refund_action['res_id'])
|
||||
|
||||
payment_context = {"active_ids": refund.ids, "active_id": refund.id}
|
||||
|
|
@ -260,5 +270,15 @@ class TestPoSStock(TestPoSCommon):
|
|||
refund_payment.with_context(**payment_context).check()
|
||||
|
||||
self.pos_session.action_pos_session_validate()
|
||||
expense_account_move_line = self.env['account.move.line'].search([('account_id', '=', self.expense_account.id)])
|
||||
expense_account_move_line = self.env['account.move.line'].search([('account_id', '=', self.expense_account.id), ('product_id', '=', False)])
|
||||
self.assertEqual(expense_account_move_line.balance, 0.0, "Expense account should be 0.0")
|
||||
|
||||
def test_stock_duplicate_warehouse_with_PoS_operation_type(self):
|
||||
wh = self.env['stock.warehouse'].create({
|
||||
'name': 'WH1',
|
||||
'code': 'WH1',
|
||||
'company_id': self.env.company.id,
|
||||
})
|
||||
wh_copy = wh.copy()
|
||||
self.assertTrue(wh_copy.pos_type_id)
|
||||
self.assertNotEqual(wh.pos_type_id, wh_copy.pos_type_id)
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from odoo import tools
|
||||
from odoo import Command
|
||||
import odoo
|
||||
from odoo.addons.point_of_sale.tests.common import TestPoSCommon
|
||||
|
||||
|
|
@ -17,6 +17,7 @@ class TestPoSWithFiscalPosition(TestPoSCommon):
|
|||
super(TestPoSWithFiscalPosition, cls).setUpClass()
|
||||
|
||||
cls.config = cls.basic_config
|
||||
cls.company.tax_calculation_rounding_method = 'round_per_line'
|
||||
|
||||
cls.new_tax_17 = cls.env['account.tax'].create({'name': 'New Tax 17%', 'amount': 17})
|
||||
cls.new_tax_17.invoice_repartition_line_ids.write({'account_id': cls.tax_received_account.id})
|
||||
|
|
@ -56,14 +57,12 @@ class TestPoSWithFiscalPosition(TestPoSCommon):
|
|||
'account_src_id': cls.sale_account.id,
|
||||
'account_dest_id': cls.other_sale_account.id,
|
||||
})
|
||||
tax_fpos = cls.env['account.fiscal.position.tax'].create({
|
||||
'position_id': fpos.id,
|
||||
'tax_src_id': cls.taxes['tax7'].id,
|
||||
'tax_dest_id': cls.new_tax_17.id,
|
||||
})
|
||||
fpos.write({
|
||||
'account_ids': [(6, 0, account_fpos.ids)],
|
||||
'tax_ids': [(6, 0, tax_fpos.ids)],
|
||||
})
|
||||
cls.new_tax_17.write({
|
||||
'fiscal_position_ids': [Command.link(fpos.id)],
|
||||
'original_tax_ids': [Command.link(cls.taxes['tax7'].id)],
|
||||
})
|
||||
return fpos
|
||||
|
||||
|
|
@ -75,13 +74,14 @@ class TestPoSWithFiscalPosition(TestPoSCommon):
|
|||
'account_src_id': cls.sale_account.id,
|
||||
'account_dest_id': cls.other_sale_account.id,
|
||||
})
|
||||
tax_fpos = cls.env['account.fiscal.position.tax'].create({
|
||||
'position_id': fpos_no_tax_dest.id,
|
||||
'tax_src_id': cls.taxes['tax7'].id,
|
||||
})
|
||||
fpos_no_tax_dest.write({
|
||||
'account_ids': [(6, 0, account_fpos.ids)],
|
||||
'tax_ids': [(6, 0, tax_fpos.ids)],
|
||||
})
|
||||
cls.env['account.tax'].create({
|
||||
'name': 'Exempt',
|
||||
'amount': 0,
|
||||
'fiscal_position_ids': [Command.link(fpos_no_tax_dest.id)],
|
||||
'original_tax_ids': [Command.link(cls.taxes['tax7'].id)],
|
||||
})
|
||||
return fpos_no_tax_dest
|
||||
|
||||
|
|
@ -134,9 +134,9 @@ class TestPoSWithFiscalPosition(TestPoSCommon):
|
|||
self._run_test({
|
||||
'payment_methods': self.cash_pm1 | self.bank_pm1,
|
||||
'orders': [
|
||||
{'pos_order_lines_ui_args': [(self.product1, 10), (self.product2, 10), (self.product3, 10)], 'customer': self.customer, 'uid': '00100-010-0001'},
|
||||
{'pos_order_lines_ui_args': [(self.product1, 5), (self.product2, 5)], 'customer': self.customer, 'uid': '00100-010-0002'},
|
||||
{'pos_order_lines_ui_args': [(self.product2, 5), (self.product3, 5)], 'payments': [(self.bank_pm1, 265.75)], 'uid': '00100-010-0003'},
|
||||
{'pos_order_lines_ui_args': [(self.product1, 10), (self.product2, 10), (self.product3, 10)], 'customer': self.customer, 'uuid': '00100-010-0001'},
|
||||
{'pos_order_lines_ui_args': [(self.product1, 5), (self.product2, 5)], 'customer': self.customer, 'uuid': '00100-010-0002'},
|
||||
{'pos_order_lines_ui_args': [(self.product2, 5), (self.product3, 5)], 'payments': [(self.bank_pm1, 265.75)], 'uuid': '00100-010-0003'},
|
||||
],
|
||||
'before_closing_cb': _before_closing_cb,
|
||||
'journal_entries_before_closing': {},
|
||||
|
|
@ -221,9 +221,9 @@ class TestPoSWithFiscalPosition(TestPoSCommon):
|
|||
self._run_test({
|
||||
'payment_methods': self.cash_pm1 | self.bank_pm1,
|
||||
'orders': [
|
||||
{'pos_order_lines_ui_args': [(self.product1, 10), (self.product2, 10), (self.product3, 10)], 'payments': [(self.bank_pm1, 619.7)], 'customer': self.customer, 'uid': '00100-010-0001'},
|
||||
{'pos_order_lines_ui_args': [(self.product1, 5), (self.product2, 5)], 'customer': self.customer, 'uid': '00100-010-0002'},
|
||||
{'pos_order_lines_ui_args': [(self.product2, 5), (self.product3, 5)], 'payments': [(self.bank_pm1, 265.75)], 'uid': '00100-010-0003'},
|
||||
{'pos_order_lines_ui_args': [(self.product1, 10), (self.product2, 10), (self.product3, 10)], 'payments': [(self.bank_pm1, 619.7)], 'customer': self.customer, 'uuid': '00100-010-0001'},
|
||||
{'pos_order_lines_ui_args': [(self.product1, 5), (self.product2, 5)], 'customer': self.customer, 'uuid': '00100-010-0002'},
|
||||
{'pos_order_lines_ui_args': [(self.product2, 5), (self.product3, 5)], 'payments': [(self.bank_pm1, 265.75)], 'uuid': '00100-010-0003'},
|
||||
],
|
||||
'before_closing_cb': _before_closing_cb,
|
||||
'journal_entries_before_closing': {},
|
||||
|
|
@ -304,8 +304,8 @@ class TestPoSWithFiscalPosition(TestPoSCommon):
|
|||
orders_total = sum(order.amount_total for order in self.pos_session.order_ids)
|
||||
self.assertAlmostEqual(orders_total, self.pos_session.total_payments_amount, msg='Total order amount should be equal to the total payment amount.')
|
||||
|
||||
invoiced_order_1 = self.pos_session.order_ids.filtered(lambda order: '00100-010-0001' in order.pos_reference)
|
||||
invoiced_order_2 = self.pos_session.order_ids.filtered(lambda order: '00100-010-0003' in order.pos_reference)
|
||||
invoiced_order_1 = self.pos_session.order_ids.filtered(lambda order: '00100-010-0001' in order.uuid)
|
||||
invoiced_order_2 = self.pos_session.order_ids.filtered(lambda order: '00100-010-0003' in order.uuid)
|
||||
|
||||
self.assertTrue(invoiced_order_1, msg='Invoiced order 1 should exist.')
|
||||
self.assertTrue(invoiced_order_2, msg='Invoiced order 2 should exist.')
|
||||
|
|
@ -315,9 +315,9 @@ class TestPoSWithFiscalPosition(TestPoSCommon):
|
|||
self._run_test({
|
||||
'payment_methods': self.cash_pm1 | self.bank_pm1,
|
||||
'orders': [
|
||||
{'pos_order_lines_ui_args': [(self.product1, 10), (self.product2, 10), (self.product3, 10)], 'payments': [(self.bank_pm1, 691.06)], 'customer': self.customer, 'is_invoiced': True, 'uid': '00100-010-0001'},
|
||||
{'pos_order_lines_ui_args': [(self.product1, 5), (self.product2, 5)], 'customer': self.customer, 'uid': '00100-010-0002'},
|
||||
{'pos_order_lines_ui_args': [(self.product2, 5), (self.product3, 5)], 'customer': self.other_customer, 'is_invoiced': True, 'uid': '00100-010-0003'},
|
||||
{'pos_order_lines_ui_args': [(self.product1, 10), (self.product2, 10), (self.product3, 10)], 'payments': [(self.bank_pm1, 691.06)], 'customer': self.customer, 'is_invoiced': True, 'uuid': '00100-010-0001'},
|
||||
{'pos_order_lines_ui_args': [(self.product1, 5), (self.product2, 5)], 'customer': self.customer, 'uuid': '00100-010-0002'},
|
||||
{'pos_order_lines_ui_args': [(self.product2, 5), (self.product3, 5)], 'customer': self.other_customer, 'is_invoiced': True, 'uuid': '00100-010-0003'},
|
||||
],
|
||||
'before_closing_cb': _before_closing_cb,
|
||||
'journal_entries_before_closing': {
|
||||
|
|
|
|||
|
|
@ -14,6 +14,8 @@ class TestReportPoSOrder(TestPoSCommon):
|
|||
def test_report_pos_order_0(self):
|
||||
"""Test the margin and price_total of a PoS Order with no taxes."""
|
||||
product1 = self.create_product('Product 1', self.categ_basic, 150)
|
||||
self.categ_all = self.env['pos.category'].search([])
|
||||
product1.write({'pos_categ_ids': [odoo.Command.set(self.categ_all.ids)]})
|
||||
|
||||
self.open_new_session()
|
||||
session = self.pos_session
|
||||
|
|
@ -38,6 +40,7 @@ class TestReportPoSOrder(TestPoSCommon):
|
|||
# PoS Orders have negative IDs to avoid conflict, so reports[0] will correspond to the newest order
|
||||
reports = self.env['report.pos.order'].sudo().search([('product_id', '=', product1.id)], order='id')
|
||||
|
||||
self.assertEqual(len(reports.ids), 1)
|
||||
self.assertEqual(reports[0].margin, 150)
|
||||
self.assertEqual(reports[0].price_total, 150)
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,392 @@
|
|||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
import odoo
|
||||
|
||||
from odoo.addons.point_of_sale.tests.common import TestPoSCommon
|
||||
from odoo.exceptions import UserError
|
||||
|
||||
@odoo.tests.tagged('post_install', '-at_install')
|
||||
class TestReportSession(TestPoSCommon):
|
||||
|
||||
def setUp(self):
|
||||
super(TestReportSession, self).setUp()
|
||||
self.config = self.basic_config
|
||||
|
||||
def test_report_session(self):
|
||||
|
||||
self.tax1 = self.env['account.tax'].create({
|
||||
'name': 'Tax 1',
|
||||
'amount': 10,
|
||||
'price_include_override': 'tax_included',
|
||||
})
|
||||
self.product1 = self.create_product('Product A', self.categ_basic, 110, self.tax1.id)
|
||||
product_to_archive = self.create_product('Product to archive', self.categ_basic, 100, self.tax1.id)
|
||||
|
||||
self.config.open_ui()
|
||||
# check that an unsed product can be archived by any user with archive rights
|
||||
self.res_users_stock_user.group_ids |= self.env.ref('product.group_product_manager')
|
||||
product_to_archive.with_user(self.res_users_stock_user).action_archive()
|
||||
|
||||
session_id = self.config.current_session_id.id
|
||||
order = self.env['pos.order'].create({
|
||||
'company_id': self.env.company.id,
|
||||
'session_id': session_id,
|
||||
'partner_id': self.partner_a.id,
|
||||
'lines': [(0, 0, {
|
||||
'name': "OL/0001",
|
||||
'product_id': self.product1.id,
|
||||
'price_unit': 110,
|
||||
'discount': 0,
|
||||
'qty': 1,
|
||||
'tax_ids': [[6, False, [self.tax1.id]]],
|
||||
'price_subtotal': 100,
|
||||
'price_subtotal_incl': 110,
|
||||
})],
|
||||
'pricelist_id': self.config.pricelist_id.id,
|
||||
'amount_paid': 110.0,
|
||||
'amount_total': 110.0,
|
||||
'amount_tax': 10.0,
|
||||
'amount_return': 0.0,
|
||||
'last_order_preparation_change': '{}',
|
||||
'to_invoice': False,
|
||||
})
|
||||
# check that an used product can not be archived
|
||||
with self.assertRaisesRegex(UserError, "Hold up! Archiving products while POS sessions are active is like pulling a plate mid-meal.\nMake sure to close all sessions first to avoid any issues."):
|
||||
self.product1.with_user(self.res_users_stock_user).action_archive()
|
||||
|
||||
self.make_payment(order, self.bank_split_pm1, 60)
|
||||
self.make_payment(order, self.bank_pm1, 50)
|
||||
|
||||
self.config.current_session_id.action_pos_session_closing_control(bank_payment_method_diffs={self.bank_split_pm1.id: 50, self.bank_pm1.id: 40})
|
||||
|
||||
# PoS Orders have negative IDs to avoid conflict, so reports[0] will correspond to the newest order
|
||||
report = self.env['report.point_of_sale.report_saledetails'].get_sale_details(session_ids=[session_id])
|
||||
split_payment_bank = [p for p in report['payments'] if p.get('id', 0) == self.bank_split_pm1.id]
|
||||
self.assertEqual(split_payment_bank[0]['cash_moves'][0]['amount'], 50)
|
||||
bank_payment = [p for p in report['payments'] if p.get('id', 0) == self.bank_pm1.id]
|
||||
# self.assertEqual(bank_payment[0]['cash_moves'][0]['amount'], 40) TODO WAN
|
||||
self.assertEqual(report['products_info']['total'], 100, "Total amount of products should be 100, as we want total without tax")
|
||||
self.assertEqual(report['products'][0]['products'][0]['base_amount'], 100, "Base amount of product should be 100, as we want price without tax")
|
||||
|
||||
def test_report_session_2(self):
|
||||
|
||||
self.product1 = self.create_product('Product A', self.categ_basic, 100)
|
||||
|
||||
self.config.open_ui()
|
||||
session_id_1 = self.config.current_session_id.id
|
||||
order_info = {'company_id': self.env.company.id,
|
||||
'session_id': session_id_1,
|
||||
'partner_id': self.partner_a.id,
|
||||
'lines': [(0, 0, {
|
||||
'name': "OL/0001",
|
||||
'product_id': self.product1.id,
|
||||
'price_unit': 100,
|
||||
'discount': 0,
|
||||
'qty': 1,
|
||||
'tax_ids': [],
|
||||
'price_subtotal': 100,
|
||||
'price_subtotal_incl': 100,
|
||||
})],
|
||||
'pricelist_id': self.config.pricelist_id.id,
|
||||
'amount_paid': 100.0,
|
||||
'amount_total': 100.0,
|
||||
'amount_tax': 0.0,
|
||||
'amount_return': 0.0,
|
||||
'to_invoice': False,
|
||||
}
|
||||
|
||||
order = self.env['pos.order'].create(order_info)
|
||||
self.make_payment(order, self.bank_pm1, 100)
|
||||
|
||||
order = self.env['pos.order'].create(order_info)
|
||||
self.make_payment(order, self.cash_pm1, 100)
|
||||
|
||||
self.config.current_session_id.action_pos_session_closing_control()
|
||||
|
||||
self.config.open_ui()
|
||||
session_id_2 = self.config.current_session_id.id
|
||||
order_info['session_id'] = session_id_2
|
||||
order = self.env['pos.order'].create(order_info)
|
||||
self.make_payment(order, self.bank_pm1, 100)
|
||||
|
||||
order = self.env['pos.order'].create(order_info)
|
||||
self.make_payment(order, self.cash_pm1, 100)
|
||||
|
||||
self.config.current_session_id.action_pos_session_closing_control()
|
||||
|
||||
report = self.env['report.point_of_sale.report_saledetails'].get_sale_details()
|
||||
for payment in report['payments']:
|
||||
session_name = self.env['pos.session'].browse(payment['session']).name
|
||||
payment_method_name = self.env['pos.payment.method'].browse(payment['id']).name
|
||||
self.assertEqual(payment['name'], payment_method_name + " " + session_name)
|
||||
|
||||
pdf = self.env['ir.actions.report']._render_qweb_pdf('point_of_sale.sale_details_report', res_ids=session_id_2)
|
||||
self.assertTrue(pdf)
|
||||
|
||||
def test_report_listing(self):
|
||||
product1 = self.create_product('Product 1', self.categ_basic, 150)
|
||||
product2 = self.create_product('Product 2', self.categ_basic, 150)
|
||||
|
||||
cash_payment_method = self.env['pos.payment.method'].create({
|
||||
'name': 'Cash',
|
||||
'receivable_account_id': self.company_data['default_account_receivable'].id,
|
||||
'journal_id': self.company_data['default_journal_cash'].id,
|
||||
'company_id': self.env.company.id,
|
||||
})
|
||||
bank_payment_method = self.env['pos.payment.method'].create({
|
||||
'name': 'Bank',
|
||||
'journal_id': self.company_data['default_journal_bank'].id,
|
||||
'receivable_account_id': self.company_data['default_account_receivable'].id,
|
||||
'company_id': self.env.company.id,
|
||||
})
|
||||
self.config.write({'payment_method_ids': [(4, bank_payment_method.id), (4, cash_payment_method.id)]})
|
||||
|
||||
self.open_new_session()
|
||||
session = self.pos_session
|
||||
|
||||
self.tax_sale_a['amount'] = 10
|
||||
order = self.env['pos.order'].create({
|
||||
'session_id': session.id,
|
||||
'lines': [(0, 0, {
|
||||
'name': "TR/0001",
|
||||
'product_id': product1.id,
|
||||
'price_unit': 150,
|
||||
'discount': 0,
|
||||
'qty': 1.0,
|
||||
'price_subtotal': 150,
|
||||
'tax_ids': [(6, 0, self.tax_sale_a.ids)],
|
||||
'price_subtotal_incl': 165,
|
||||
}), (0, 0, {
|
||||
'name': "TR/0001",
|
||||
'product_id': product2.id,
|
||||
'price_unit': 150,
|
||||
'discount': 0,
|
||||
'qty': 1.0,
|
||||
'price_subtotal': 150,
|
||||
'tax_ids': [(6, 0, self.tax_sale_a.ids)],
|
||||
'price_subtotal_incl': 165,
|
||||
})],
|
||||
'amount_total': 330.0,
|
||||
'amount_tax': 30.0,
|
||||
'amount_paid': 0.0,
|
||||
'amount_return': 0.0,
|
||||
})
|
||||
payment_context = {"active_ids": order.ids, "active_id": order.id}
|
||||
|
||||
order_payment = self.env['pos.make.payment'].with_context(**payment_context).create([{
|
||||
'amount': am,
|
||||
'payment_method_id': pm
|
||||
} for am in [65, 100] for pm in [cash_payment_method.id, bank_payment_method.id]])
|
||||
for payment in order_payment:
|
||||
payment.with_context(**payment_context).check()
|
||||
|
||||
order_report_lines = self.env['report.pos.order'].sudo().search([('order_id', '=', order.id)])
|
||||
|
||||
self.assertEqual(len(order_report_lines), 2)
|
||||
self.assertEqual(order_report_lines[0].payment_method_id.id, order_report_lines[1].payment_method_id.id)
|
||||
|
||||
for order in order_report_lines:
|
||||
self.assertEqual(order.price_total, 165.0)
|
||||
self.assertEqual(order.nbr_lines, 1)
|
||||
self.assertEqual(order.product_qty, 1)
|
||||
|
||||
order_report_lines_count_product1 = self.env['report.pos.order'].sudo().search_count([('product_id', '=', product1.id)])
|
||||
order_report_lines_count_product2 = self.env['report.pos.order'].sudo().search_count([('product_id', '=', product2.id)])
|
||||
|
||||
self.assertEqual(order_report_lines_count_product1, 1)
|
||||
self.assertEqual(order_report_lines_count_product2, 1)
|
||||
|
||||
def test_report_session_3(self):
|
||||
self.product1 = self.create_product('Product A', self.categ_basic, 100)
|
||||
self.config.open_ui()
|
||||
session_id = self.config.current_session_id.id
|
||||
order_info = {'company_id': self.env.company.id,
|
||||
'session_id': session_id,
|
||||
'partner_id': self.partner_a.id,
|
||||
'lines': [(0, 0, {
|
||||
'name': "OL/0001",
|
||||
'product_id': self.product1.id,
|
||||
'price_unit': 0,
|
||||
'discount': 0,
|
||||
'qty': 14.9,
|
||||
'tax_ids': [],
|
||||
'price_subtotal': 0,
|
||||
'price_subtotal_incl': 0,
|
||||
})],
|
||||
'pricelist_id': self.config.pricelist_id.id,
|
||||
'amount_paid': 0.0,
|
||||
'amount_total': 0.0,
|
||||
'amount_tax': 0.0,
|
||||
'amount_return': 0.0,
|
||||
'to_invoice': False,
|
||||
}
|
||||
order = self.env['pos.order'].create(order_info)
|
||||
self.make_payment(order, self.bank_pm1, 0)
|
||||
order_info['lines'][0][2]['qty'] = 59.7
|
||||
order = self.env['pos.order'].create(order_info)
|
||||
self.make_payment(order, self.bank_pm1, 0)
|
||||
self.config.current_session_id.action_pos_session_closing_control()
|
||||
report = self.env['report.point_of_sale.report_saledetails'].get_sale_details()
|
||||
self.assertEqual(report['products'][0]['products'][0]['quantity'], 74.6, "Quantity of product should be 74.6, as we want the sum of the quantity of the two orders")
|
||||
|
||||
def test_report_bank_expected_different_than_counted(self):
|
||||
"""
|
||||
Test that in the pos session report, the difference between the expected and counted bank payment is correct.
|
||||
Test both with a default outstanding account on the payment and without.
|
||||
"""
|
||||
self.tax1 = self.env['account.tax'].create({
|
||||
'name': 'Tax 1',
|
||||
'amount': 10,
|
||||
'price_include_override': 'tax_included',
|
||||
})
|
||||
self.product1 = self.create_product('Product A', self.categ_basic, 100, self.tax1.id)
|
||||
|
||||
self.bank_pm1.outstanding_account_id = self.outstanding_bank.id
|
||||
self.config.open_ui()
|
||||
|
||||
session1_id = self.config.current_session_id.id
|
||||
order1 = self.env['pos.order'].create({
|
||||
'company_id': self.env.company.id,
|
||||
'session_id': session1_id,
|
||||
'partner_id': self.partner_a.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': 100,
|
||||
})],
|
||||
'pricelist_id': self.config.pricelist_id.id,
|
||||
'amount_paid': 100.0,
|
||||
'amount_total': 100.0,
|
||||
'amount_tax': 10.0,
|
||||
'amount_return': 0.0,
|
||||
'last_order_preparation_change': '{}',
|
||||
'to_invoice': False,
|
||||
})
|
||||
|
||||
self.make_payment(order1, self.bank_pm1, 100)
|
||||
|
||||
self.config.current_session_id.action_pos_session_closing_control(
|
||||
bank_payment_method_diffs={self.bank_pm1.id: -20})
|
||||
report = self.env['report.point_of_sale.report_saledetails'].get_sale_details(session_ids=[session1_id])
|
||||
self.assertEqual(report['payments'][1]['money_difference'], -20)
|
||||
|
||||
self.bank_pm1.outstanding_account_id = False
|
||||
self.config.open_ui()
|
||||
|
||||
session2_id = self.config.current_session_id.id
|
||||
order2 = self.env['pos.order'].create({
|
||||
'company_id': self.env.company.id,
|
||||
'session_id': session2_id,
|
||||
'partner_id': self.partner_a.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': 100,
|
||||
})],
|
||||
'pricelist_id': self.config.pricelist_id.id,
|
||||
'amount_paid': 100.0,
|
||||
'amount_total': 100.0,
|
||||
'amount_tax': 10.0,
|
||||
'amount_return': 0.0,
|
||||
'last_order_preparation_change': '{}',
|
||||
'to_invoice': False,
|
||||
})
|
||||
|
||||
self.make_payment(order2, self.bank_pm1, 100)
|
||||
|
||||
self.config.current_session_id.action_pos_session_closing_control(bank_payment_method_diffs={self.bank_pm1.id: -20})
|
||||
report = self.env['report.point_of_sale.report_saledetails'].get_sale_details(session_ids=[session2_id])
|
||||
self.assertEqual(report['payments'][1]['money_difference'], -20)
|
||||
|
||||
def test_report_session_4(self):
|
||||
self.tax1 = self.env['account.tax'].create({
|
||||
'name': 'Tax 1',
|
||||
'amount': 10,
|
||||
'price_include': True,
|
||||
})
|
||||
|
||||
self.tax2 = self.env['account.tax'].create({
|
||||
'name': 'Tax 2',
|
||||
'amount': 15,
|
||||
'price_include': True,
|
||||
})
|
||||
self.product1 = self.create_product('Product A', self.categ_basic, 125, self.tax1.id)
|
||||
|
||||
self.config.open_ui()
|
||||
session_id = self.config.current_session_id.id
|
||||
order_info = {
|
||||
'company_id': self.env.company.id,
|
||||
'session_id': session_id,
|
||||
'partner_id': self.partner_a.id,
|
||||
'lines': [(0, 0, {
|
||||
'name': "OL/0001",
|
||||
'product_id': self.product1.id,
|
||||
'price_unit': 125,
|
||||
'discount': 0,
|
||||
'qty': 1,
|
||||
'tax_ids': [[6, False, [self.tax1.id, self.tax2.id]]],
|
||||
'price_subtotal': 100,
|
||||
'price_subtotal_incl': 125,
|
||||
})],
|
||||
'pricelist_id': self.config.pricelist_id.id,
|
||||
'amount_paid': 125.0,
|
||||
'amount_total': 156.25,
|
||||
'amount_tax': 25.0,
|
||||
'amount_return': 0.0,
|
||||
'last_order_preparation_change': '{}',
|
||||
'to_invoice': False,
|
||||
}
|
||||
order = self.env['pos.order'].create(order_info)
|
||||
self.make_payment(order, self.bank_pm1, 156.25)
|
||||
self.config.current_session_id.action_pos_session_closing_control()
|
||||
report = self.env['report.point_of_sale.report_saledetails'].get_sale_details()
|
||||
self.assertEqual(report["taxes_info"]["base_amount"], 100, "Base amount should be equal to 100")
|
||||
|
||||
def test_report_sum_taxes_base_amounts(self):
|
||||
tax_included = self.env['account.tax'].create({
|
||||
'name': 'Tax Included',
|
||||
'amount': 5,
|
||||
'price_include_override': 'tax_included',
|
||||
})
|
||||
product = self.create_product('Product A', self.categ_basic, 110, tax_included.id)
|
||||
|
||||
self.config.open_ui()
|
||||
session_id = self.config.current_session_id.id
|
||||
order_info = [{
|
||||
'company_id': self.env.company.id,
|
||||
'session_id': session_id,
|
||||
'lines': [(0, 0, {
|
||||
'name': "OL/0001",
|
||||
'product_id': product.id,
|
||||
'price_unit': 100,
|
||||
'discount': 0,
|
||||
'qty': 1,
|
||||
'tax_ids': [[6, False, [tax_included.id]]],
|
||||
'price_subtotal': 100,
|
||||
'price_subtotal_incl': 100,
|
||||
})],
|
||||
'pricelist_id': self.config.pricelist_id.id,
|
||||
'amount_paid': 100.0,
|
||||
'amount_total': 100.0,
|
||||
'amount_tax': 4.76,
|
||||
'amount_return': 0.0,
|
||||
'last_order_preparation_change': '{}',
|
||||
'to_invoice': False,
|
||||
} for _ in range(5)]
|
||||
|
||||
for order_data in order_info:
|
||||
order = self.env['pos.order'].create(order_data)
|
||||
self.make_payment(order, self.bank_pm1, 100.0)
|
||||
|
||||
self.config.current_session_id.action_pos_session_closing_control()
|
||||
report = self.env['report.point_of_sale.report_saledetails'].get_sale_details()
|
||||
self.assertAlmostEqual(report["taxes"][0]["base_amount"], 95.24 * 5, msg="Base amount should be equal to 476.20")
|
||||
|
|
@ -2,8 +2,9 @@
|
|||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
import odoo
|
||||
|
||||
from odoo import Command
|
||||
from odoo.addons.point_of_sale.tests.common import TestPoSCommon
|
||||
from odoo.tests.common import Form
|
||||
|
||||
|
||||
@odoo.tests.tagged('post_install', '-at_install')
|
||||
|
|
@ -31,47 +32,61 @@ class TestConfigureShops(TestPoSCommon):
|
|||
('company_id', '=', self.env.company.id), ('tax_exigibility', '=', 'on_payment')
|
||||
]).unlink()
|
||||
|
||||
def test_should_not_affect_other_pos_config(self):
|
||||
""" Change in one pos.config should not reflect to the other.
|
||||
"""
|
||||
def test_properly_set_pos_config_x2many_fields(self):
|
||||
"""Simulate what is done from the res.config.settings view when editing x2 many fields."""
|
||||
|
||||
self._remove_on_payment_taxes()
|
||||
|
||||
pos_config1 = self.env['pos.config'].create({'name': 'Shop 1'})
|
||||
pos_config2 = self.env['pos.config'].create({'name': 'Shop 2'})
|
||||
self.assertEqual(pos_config1.receipt_header, False)
|
||||
self.assertEqual(pos_config2.receipt_header, False)
|
||||
|
||||
# Modify Shop 1.
|
||||
with Form(self.env['res.config.settings']) as form:
|
||||
form.pos_config_id = pos_config1
|
||||
form.pos_is_header_or_footer = True
|
||||
form.pos_receipt_header = 'xxxxx'
|
||||
|
||||
self.assertEqual(pos_config1.receipt_header, 'xxxxx')
|
||||
self.assertEqual(pos_config2.receipt_header, False)
|
||||
|
||||
# Modify Shop 2.
|
||||
with Form(self.env['res.config.settings']) as form:
|
||||
form.pos_config_id = pos_config2
|
||||
form.pos_is_header_or_footer = True
|
||||
form.pos_receipt_header = 'yyyyy'
|
||||
|
||||
self.assertEqual(pos_config1.receipt_header, 'xxxxx')
|
||||
self.assertEqual(pos_config2.receipt_header, 'yyyyy')
|
||||
|
||||
def test_is_header_or_footer_to_false(self):
|
||||
self._remove_on_payment_taxes()
|
||||
|
||||
pos_config = self.env['pos.config'].create({
|
||||
'name': 'Shop',
|
||||
'is_header_or_footer': True,
|
||||
'receipt_header': 'header val',
|
||||
'receipt_footer': 'footer val',
|
||||
'name': 'Shop 1',
|
||||
'module_pos_restaurant': False,
|
||||
'payment_method_ids': [
|
||||
Command.create({
|
||||
'name': 'Bank 1',
|
||||
'receivable_account_id': self.env.company.account_default_pos_receivable_account_id.id,
|
||||
'is_cash_count': False,
|
||||
'split_transactions': False,
|
||||
'company_id': self.env.company.id,
|
||||
}),
|
||||
Command.create({
|
||||
'name': 'Bank 2',
|
||||
'receivable_account_id': self.env.company.account_default_pos_receivable_account_id.id,
|
||||
'is_cash_count': False,
|
||||
'split_transactions': False,
|
||||
'company_id': self.env.company.id,
|
||||
}),
|
||||
Command.create({
|
||||
'name': 'Cash',
|
||||
'receivable_account_id': self.env.company.account_default_pos_receivable_account_id.id,
|
||||
'is_cash_count': True,
|
||||
'company_id': self.env.company.id,
|
||||
})
|
||||
]
|
||||
})
|
||||
|
||||
with Form(self.env['res.config.settings']) as form:
|
||||
form.pos_config_id = pos_config
|
||||
form.pos_is_header_or_footer = False
|
||||
# Manually simulate the unlinking of the second record and then save the settings.
|
||||
# It will be a set of link commands except the one we want to delete.
|
||||
linked_ids = pos_config.payment_method_ids.ids
|
||||
second_id = linked_ids[1]
|
||||
commands = [Command.link(_id) for _id in linked_ids if _id != second_id]
|
||||
|
||||
self.assertEqual(pos_config.receipt_header, False)
|
||||
self.assertEqual(pos_config.receipt_footer, False)
|
||||
pos_config.with_context(from_settings_view=True).write({
|
||||
'payment_method_ids': commands
|
||||
})
|
||||
|
||||
self.assertTrue(second_id not in pos_config.payment_method_ids.ids)
|
||||
self.assertTrue(len(pos_config.payment_method_ids) == 2)
|
||||
|
||||
def test_write_default_and_available_presets_on_multiple_pos_configs(self):
|
||||
preset = self.env['pos.preset'].create({'name': 'Preset 1'})
|
||||
|
||||
pos_config1 = self.env['pos.config'].create({'name': 'Shop 1', 'module_pos_restaurant': False})
|
||||
pos_config2 = self.env['pos.config'].create({'name': 'Shop 2', 'module_pos_restaurant': False})
|
||||
pos_config3 = self.env['pos.config'].create({'name': 'Shop 3', 'module_pos_restaurant': False})
|
||||
|
||||
pos_configs = pos_config1 | pos_config2 | pos_config3
|
||||
|
||||
pos_configs.write({
|
||||
'use_presets': True,
|
||||
'available_preset_ids': [(6, 0, [preset.id])],
|
||||
'default_preset_id': preset.id,
|
||||
})
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue