mirror of
https://github.com/bringout/oca-ocb-core.git
synced 2026-04-21 03:32:05 +02:00
19.0 vanilla
This commit is contained in:
parent
d1963a3c3a
commit
2d3ee4855a
7430 changed files with 2687981 additions and 2965473 deletions
|
|
@ -2,9 +2,13 @@
|
|||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from . import test_purchase
|
||||
from . import test_purchase_downpayment
|
||||
from . import test_purchase_flow
|
||||
from . import test_purchase_order_product_catalog
|
||||
from . import test_purchase_order_report
|
||||
from . import test_purchase_invoice
|
||||
from . import test_access_rights
|
||||
from . import test_accrued_purchase_orders
|
||||
from . import test_purchase_tax_totals
|
||||
from . import test_purchase_dashboard
|
||||
from . import test_import_files
|
||||
from . import test_purchase_product_catalog
|
||||
|
|
|
|||
|
|
@ -1,16 +1,18 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
from odoo.addons.account.tests.common import AccountTestInvoicingCommon
|
||||
from odoo.tests import Form, tagged
|
||||
|
||||
from odoo import Command
|
||||
from odoo.exceptions import AccessError
|
||||
from odoo.tests import Form, tagged
|
||||
|
||||
from odoo.addons.account.tests.common import AccountTestInvoicingCommon
|
||||
|
||||
|
||||
@tagged('post_install', '-at_install')
|
||||
class TestPurchaseInvoice(AccountTestInvoicingCommon):
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls, chart_template_ref=None):
|
||||
super().setUpClass(chart_template_ref=chart_template_ref)
|
||||
def setUpClass(cls):
|
||||
super().setUpClass()
|
||||
|
||||
# Create a users
|
||||
group_purchase_user = cls.env.ref('purchase.group_purchase_user')
|
||||
|
|
@ -23,7 +25,7 @@ class TestPurchaseInvoice(AccountTestInvoicingCommon):
|
|||
'name': 'Purchase user',
|
||||
'login': 'purchaseUser',
|
||||
'email': 'pu@odoo.com',
|
||||
'groups_id': [(6, 0, [group_purchase_user.id, group_employee.id, group_partner_manager.id])],
|
||||
'group_ids': [(6, 0, [group_purchase_user.id, group_employee.id, group_partner_manager.id])],
|
||||
})
|
||||
|
||||
cls.vendor = cls.env['res.partner'].create({
|
||||
|
|
@ -69,7 +71,8 @@ class TestPurchaseInvoice(AccountTestInvoicingCommon):
|
|||
|
||||
def test_read_purchase_order(self):
|
||||
""" Check that a purchase user can read all purchase order and 'in' invoices"""
|
||||
purchase_user_2 = self.purchase_user.copy({
|
||||
self.purchase_user.write({'group_ids': [(4, self.env.ref('account.group_account_readonly').id)]})
|
||||
purchase_user_2 = self.purchase_user.sudo().copy({
|
||||
'name': 'Purchase user 2',
|
||||
'login': 'purchaseUser2',
|
||||
'email': 'pu2@odoo.com',
|
||||
|
|
@ -116,12 +119,46 @@ class TestPurchaseInvoice(AccountTestInvoicingCommon):
|
|||
self.purchase_user.write({
|
||||
'company_ids': [(4, company.id)],
|
||||
'company_id': company.id,
|
||||
'groups_id': [(3, group_purchase_manager.id)],
|
||||
'group_ids': [(3, group_purchase_manager.id)],
|
||||
})
|
||||
order.with_user(self.purchase_user).button_confirm()
|
||||
self.assertEqual(order.state, 'to approve')
|
||||
order.with_user(self.purchase_user).button_approve()
|
||||
self.assertEqual(order.state, 'to approve')
|
||||
self.purchase_user.groups_id += group_purchase_manager
|
||||
self.purchase_user.group_ids += group_purchase_manager
|
||||
order.with_user(self.purchase_user).button_approve()
|
||||
self.assertEqual(order.state, 'purchase')
|
||||
|
||||
def test_create_product_purchase_user(self):
|
||||
uom = self.env.ref('uom.product_uom_gram')
|
||||
self.purchase_user.group_ids += self.env.ref('product.group_product_manager')
|
||||
product = self.env['product.template'].with_user(self.purchase_user).create({
|
||||
'name': 'Test Product UOM Default',
|
||||
'type': 'consu',
|
||||
'uom_id': uom.id,
|
||||
})
|
||||
self.assertTrue(product, "The default purchase UOM should be in the same category as the sale UOM.")
|
||||
|
||||
def test_prepare_purchase_order_line_from_branch_company(self):
|
||||
"""Check that a purchase order line can be created from a nested branch company."""
|
||||
self.env.company.child_ids = [Command.create({
|
||||
'name': "Test Branch",
|
||||
'child_ids': [Command.create({'name': "Nested Branch"})],
|
||||
})]
|
||||
nested_branch = self.env.company.child_ids.child_ids
|
||||
self.purchase_user.write({
|
||||
'company_ids': [Command.set(nested_branch.ids)],
|
||||
'company_id': nested_branch.id,
|
||||
})
|
||||
|
||||
PurchaseOrder = self.env['purchase.order'].with_user(self.purchase_user)
|
||||
order = PurchaseOrder.create({'partner_id': self.vendor.id})
|
||||
nested_branch = nested_branch.with_env(PurchaseOrder.env)
|
||||
product = self.product.with_env(PurchaseOrder.env)
|
||||
vendor = self.vendor.with_env(PurchaseOrder.env)
|
||||
|
||||
self.env.invalidate_all()
|
||||
po_line_vals = PurchaseOrder.order_line._prepare_purchase_order_line(
|
||||
product, 1, product.uom_id, nested_branch, vendor, order,
|
||||
)
|
||||
self.assertTrue(PurchaseOrder.order_line.create(po_line_vals))
|
||||
|
|
|
|||
|
|
@ -9,14 +9,15 @@ from odoo.exceptions import UserError
|
|||
class TestAccruedPurchaseOrders(AccountTestInvoicingCommon):
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls, chart_template_ref=None):
|
||||
super().setUpClass(chart_template_ref=chart_template_ref)
|
||||
def setUpClass(cls):
|
||||
super().setUpClass()
|
||||
cls.other_currency = cls.setup_other_currency('XAF')
|
||||
cls.alt_exp_account = cls.company_data['default_account_expense'].copy()
|
||||
# set 'type' to 'service' to allow manualy set 'qty_delivered' even with purchase_stock installed
|
||||
cls.product_a.update({'type': 'service', 'purchase_method': 'receive'})
|
||||
cls.product_b.update({'type': 'service', 'purchase_method': 'receive'})
|
||||
#analytic distribution
|
||||
cls.default_plan = cls.env['account.analytic.plan'].create({'name': 'Default', 'company_id': False})
|
||||
cls.default_plan = cls.env['account.analytic.plan'].create({'name': 'Default'})
|
||||
cls.analytic_account_a = cls.env['account.analytic.account'].create({
|
||||
'name': 'analytic_account_a',
|
||||
'plan_id': cls.default_plan.id,
|
||||
|
|
@ -35,9 +36,9 @@ class TestAccruedPurchaseOrders(AccountTestInvoicingCommon):
|
|||
'name': cls.product_a.name,
|
||||
'product_id': cls.product_a.id,
|
||||
'product_qty': 10.0,
|
||||
'product_uom': cls.product_a.uom_id.id,
|
||||
'product_uom_id': cls.product_a.uom_id.id,
|
||||
'price_unit': cls.product_a.list_price,
|
||||
'taxes_id': False,
|
||||
'tax_ids': False,
|
||||
'analytic_distribution': {
|
||||
cls.analytic_account_a.id : 80.0,
|
||||
cls.analytic_account_b.id : 20.0,
|
||||
|
|
@ -47,9 +48,9 @@ class TestAccruedPurchaseOrders(AccountTestInvoicingCommon):
|
|||
'name': cls.product_b.name,
|
||||
'product_id': cls.product_b.id,
|
||||
'product_qty': 10.0,
|
||||
'product_uom': cls.product_b.uom_id.id,
|
||||
'product_uom_id': cls.product_b.uom_id.id,
|
||||
'price_unit': cls.product_b.list_price,
|
||||
'taxes_id': False,
|
||||
'tax_ids': False,
|
||||
'analytic_distribution': {
|
||||
cls.analytic_account_b.id : 100.0,
|
||||
},
|
||||
|
|
@ -90,13 +91,13 @@ class TestAccruedPurchaseOrders(AccountTestInvoicingCommon):
|
|||
move.action_post()
|
||||
|
||||
with self.assertRaises(UserError):
|
||||
self.wizard.create_entries()
|
||||
self.wizard.with_context(accrual_entry_date='2020-01-30').create_entries()
|
||||
|
||||
def test_multi_currency_accrued_order(self):
|
||||
# 5 qty of each product billeable
|
||||
self.purchase_order.order_line.qty_received = 5
|
||||
# set currency != company currency
|
||||
self.purchase_order.currency_id = self.currency_data['currency']
|
||||
self.purchase_order.currency_id = self.other_currency
|
||||
moves = self.env['account.move'].search(self.wizard.create_entries()['domain'])
|
||||
for move in moves:
|
||||
self.assertEqual(move.currency_id, self.purchase_order.currency_id)
|
||||
|
|
@ -130,9 +131,9 @@ class TestAccruedPurchaseOrders(AccountTestInvoicingCommon):
|
|||
'name': 'Tax 10% included',
|
||||
'amount': 10.0,
|
||||
'type_tax_use': 'purchase',
|
||||
'price_include': True,
|
||||
'price_include_override': 'tax_included',
|
||||
})
|
||||
self.purchase_order.order_line.taxes_id = tax_10_included
|
||||
self.purchase_order.order_line.tax_ids = tax_10_included
|
||||
self.purchase_order.order_line.qty_received = 5
|
||||
self.assertRecordValues(self.env['account.move'].search(self.wizard.create_entries()['domain']).line_ids, [
|
||||
# reverse move lines
|
||||
|
|
@ -172,15 +173,15 @@ class TestAccruedPurchaseOrders(AccountTestInvoicingCommon):
|
|||
res = self.env['account.move'].search(self.wizard.create_entries()['domain']).line_ids
|
||||
self.assertRecordValues(res, [
|
||||
# reverse move lines
|
||||
{'account_id': self.account_expense.id, 'debit': 5000.0, 'credit': 0.0},
|
||||
{'account_id': self.alt_exp_account.id, 'debit': 1000.0, 'credit': 0.0},
|
||||
{'account_id': self.account_revenue.id, 'debit': 0.0, 'credit': 6000.0},
|
||||
{'account_id': self.account_expense.id, 'debit': 10000.0, 'credit': 0.0},
|
||||
{'account_id': self.alt_exp_account.id, 'debit': 2000.0, 'credit': 0.0},
|
||||
{'account_id': self.account_revenue.id, 'debit': 0.0, 'credit': 12000.0},
|
||||
# move lines
|
||||
{'account_id': self.account_expense.id, 'debit': 0.0, 'credit': 5000.0},
|
||||
{'account_id': self.alt_exp_account.id, 'debit': 0.0, 'credit': 1000.0},
|
||||
{'account_id': self.account_revenue.id, 'debit': 6000.0, 'credit': 0.0},
|
||||
{'account_id': self.account_expense.id, 'debit': 0.0, 'credit': 10000.0},
|
||||
{'account_id': self.alt_exp_account.id, 'debit': 0.0, 'credit': 2000.0},
|
||||
{'account_id': self.account_revenue.id, 'debit': 12000.0, 'credit': 0.0},
|
||||
])
|
||||
|
||||
|
||||
def test_error_when_different_currencies_accrued(self):
|
||||
"""
|
||||
Tests that if two Purchase Orders with different currencies are selected for Accrued Expense Entry,
|
||||
|
|
@ -193,7 +194,7 @@ class TestAccruedPurchaseOrders(AccountTestInvoicingCommon):
|
|||
},
|
||||
{
|
||||
'partner_id': self.partner_a.id,
|
||||
'currency_id': self.currency_data['currency'].id,
|
||||
'currency_id': self.other_currency.id,
|
||||
}
|
||||
])
|
||||
purchase_orders.button_confirm()
|
||||
|
|
|
|||
|
|
@ -0,0 +1,61 @@
|
|||
import unittest
|
||||
|
||||
from odoo.tests import TransactionCase, can_import, loaded_demo_data, tagged
|
||||
from odoo.tools.misc import file_open
|
||||
|
||||
|
||||
@tagged("post_install", "-at_install")
|
||||
class TestImportFiles(TransactionCase):
|
||||
|
||||
@unittest.skipUnless(
|
||||
can_import("xlrd.xlsx") or can_import("openpyxl"), "XLRD/XLSX not available",
|
||||
)
|
||||
def test_import_requests_for_quotation_template_xls(self):
|
||||
if not loaded_demo_data(self.env):
|
||||
self.skipTest('Needs demo data to be able to import those files')
|
||||
model = "purchase.order"
|
||||
filename = "requests_for_quotation_import_template.xlsx"
|
||||
|
||||
file_content = file_open(f"purchase/static/xls/{filename}", "rb").read()
|
||||
import_wizard = self.env["base_import.import"].create(
|
||||
{
|
||||
"res_model": model,
|
||||
"file": file_content,
|
||||
"file_type": "application/vnd.ms-excel",
|
||||
},
|
||||
)
|
||||
|
||||
result = import_wizard.parse_preview(
|
||||
{
|
||||
"has_headers": True,
|
||||
},
|
||||
)
|
||||
self.assertIsNone(result.get("error"))
|
||||
field_names = ['/'.join(v) for v in result["matches"].values()]
|
||||
results = import_wizard.execute_import(
|
||||
field_names,
|
||||
[r.lower() for r in result["headers"]],
|
||||
{
|
||||
"import_skip_records": [],
|
||||
"import_set_empty_fields": [],
|
||||
"fallback_values": {},
|
||||
"name_create_enabled_fields": {},
|
||||
"encoding": "",
|
||||
"separator": "",
|
||||
"quoting": '"',
|
||||
"date_format": "",
|
||||
"datetime_format": "",
|
||||
"float_thousand_separator": ",",
|
||||
"float_decimal_separator": ".",
|
||||
"advanced": True,
|
||||
"has_headers": True,
|
||||
"keep_matches": False,
|
||||
"limit": 2000,
|
||||
"skip": 0,
|
||||
"tracking_disable": True,
|
||||
},
|
||||
)
|
||||
self.assertFalse(
|
||||
results["messages"],
|
||||
"results should be empty on successful import of ",
|
||||
)
|
||||
File diff suppressed because it is too large
Load diff
|
|
@ -11,8 +11,8 @@ from odoo import fields
|
|||
class TestPurchaseDashboard(AccountTestInvoicingCommon, MailCase):
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls, chart_template_ref=None):
|
||||
super().setUpClass(chart_template_ref=chart_template_ref)
|
||||
def setUpClass(cls):
|
||||
super().setUpClass()
|
||||
|
||||
# Create two new users
|
||||
cls.user_a = new_test_user(cls.env, login='purchaseusera', groups='purchase.group_purchase_user')
|
||||
|
|
@ -26,10 +26,14 @@ class TestPurchaseDashboard(AccountTestInvoicingCommon, MailCase):
|
|||
cls.product_100 = cls.env['product.product'].create({**product_data, 'standard_price': 100})
|
||||
cls.product_250 = cls.env['product.product'].create({**product_data, 'standard_price': 250})
|
||||
|
||||
@classmethod
|
||||
def default_env_context(cls):
|
||||
# OVERRIDE
|
||||
return {}
|
||||
|
||||
@mute_logger('odoo.addons.mail.models.mail_mail')
|
||||
def test_purchase_dashboard(self):
|
||||
'''
|
||||
Test purchase dashboard values with multiple users.
|
||||
''' Test purchase dashboard values with multiple users.
|
||||
'''
|
||||
|
||||
# Create 3 Request for Quotations with lines.
|
||||
|
|
@ -62,6 +66,7 @@ class TestPurchaseDashboard(AccountTestInvoicingCommon, MailCase):
|
|||
'partner_id': self.partner_a.id,
|
||||
'company_id': self.user_a.company_id.id,
|
||||
'currency_id': self.user_a.company_id.currency_id.id,
|
||||
'priority': '1',
|
||||
'date_order': fields.Date().today() + timedelta(days=7)
|
||||
}])
|
||||
|
||||
|
|
@ -83,12 +88,10 @@ class TestPurchaseDashboard(AccountTestInvoicingCommon, MailCase):
|
|||
|
||||
# Check dashboard values
|
||||
currency_id = self.env.company.currency_id
|
||||
zero_value_keys = ['all_waiting', 'my_waiting', 'my_late']
|
||||
self.assertListEqual([dashboard_result[key] for key in zero_value_keys], [0]*len(zero_value_keys))
|
||||
self.assertEqual(dashboard_result['all_to_send'], 2)
|
||||
self.assertEqual(dashboard_result['my_to_send'], 1)
|
||||
self.assertEqual(dashboard_result['all_late'], 1)
|
||||
self.assertEqual(dashboard_result['all_avg_order_value'], format_amount(self.env, self.tax_purchase_a.compute_all(700.0)['total_included'], currency_id))
|
||||
self.assertEqual(dashboard_result['all_avg_days_to_purchase'], 0)
|
||||
self.assertEqual(dashboard_result['all_total_last_7_days'], format_amount(self.env, self.tax_purchase_a.compute_all(2100.0)['total_included'], currency_id))
|
||||
self.assertEqual(dashboard_result['all_sent_rfqs'], 2)
|
||||
|
||||
self.assertFalse(dashboard_result['global']['sent']['all'])
|
||||
self.assertFalse(dashboard_result['my']['late']['all'])
|
||||
self.assertEqual(dashboard_result['global']['draft']['all'], 2)
|
||||
self.assertEqual(dashboard_result['global']['draft']['priority'], 1)
|
||||
self.assertEqual(dashboard_result['my']['draft']['all'], 1)
|
||||
self.assertEqual(dashboard_result['global']['late']['all'], 1)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,138 @@
|
|||
from odoo import Command, fields
|
||||
|
||||
from odoo.addons.purchase.tests.test_purchase_invoice import TestPurchaseToInvoiceCommon
|
||||
from odoo.tests import tagged
|
||||
|
||||
|
||||
@tagged('-at_install', 'post_install')
|
||||
class TestPurchaseDownpayment(TestPurchaseToInvoiceCommon):
|
||||
|
||||
def test_downpayment_basic(self):
|
||||
po = self.init_purchase(confirm=False, products=[self.product_order])
|
||||
po.order_line.product_qty = 10.0
|
||||
po.button_confirm()
|
||||
|
||||
dp_bill = self.init_invoice('in_invoice', amounts=[69.00], post=True)
|
||||
|
||||
match_lines = self.env['purchase.bill.line.match'].search([('partner_id', '=', self.partner_a.id)])
|
||||
action = match_lines.action_add_to_po()
|
||||
|
||||
wizard = self.env['bill.to.po.wizard'].with_context({**action['context'], 'active_ids': match_lines.ids}).create({})
|
||||
wizard.action_add_downpayment()
|
||||
|
||||
po_dp_section_line = po.order_line.filtered(lambda l: l.display_type == 'line_section' and l.is_downpayment)
|
||||
self.assertEqual(len(po_dp_section_line), 1)
|
||||
po_dp_line = po.order_line.filtered(lambda l: l.display_type != 'line_section' and l.is_downpayment)
|
||||
self.assertEqual(po_dp_line.name, 'Down Payment (ref: %s)' % dp_bill.invoice_line_ids.display_name)
|
||||
self.assertEqual(po_dp_line.sequence, po_dp_section_line.sequence + 1)
|
||||
|
||||
# This is not the normal flow, but we test the deduction of the downpayment
|
||||
action_view_bill = po.action_create_invoice()
|
||||
generated_bill = self.env['account.move'].browse(action_view_bill['res_id'])
|
||||
|
||||
self.assertRecordValues(generated_bill.invoice_line_ids, [
|
||||
# pylint: disable=C0326
|
||||
{'product_id': self.product_order.id, 'display_type': 'product', 'quantity': 10, 'is_downpayment': False, 'balance': 10.0 * self.product_order.standard_price},
|
||||
{'product_id': False, 'display_type': 'line_section', 'quantity': 0, 'is_downpayment': True, 'balance': 0.0},
|
||||
{'product_id': False, 'display_type': 'product', 'quantity': -1, 'is_downpayment': True, 'balance': -69.0},
|
||||
])
|
||||
|
||||
# Normal flow: New bill with negative down payment line
|
||||
final_bill = generated_bill.copy()
|
||||
generated_bill.button_cancel()
|
||||
generated_bill.unlink()
|
||||
final_bill.invoice_date = fields.Date.from_string('2019-01-02')
|
||||
self.assertFalse(final_bill.line_ids.purchase_line_id)
|
||||
|
||||
self.env['account.move'].flush_model()
|
||||
match_lines = self.env['purchase.bill.line.match'].search([('partner_id', '=', self.partner_a.id)])
|
||||
match_lines.action_match_lines()
|
||||
|
||||
self.assertEqual(final_bill.invoice_line_ids.purchase_order_id.invoice_status, 'invoiced')
|
||||
self.assertRecordValues(po_dp_line, [{
|
||||
'qty_invoiced': 0,
|
||||
'invoice_lines': dp_bill.invoice_line_ids.ids + final_bill.invoice_line_ids[-1:].ids,
|
||||
}])
|
||||
self.env.flush_all()
|
||||
self.assertFalse(self.env['purchase.bill.line.match'].search([('partner_id', '=', self.partner_a.id)]))
|
||||
|
||||
def test_product_supplierinfo_downpayment(self):
|
||||
"""Check that the creation of a downpayment does not affect already existing lines"""
|
||||
self.product_a.seller_ids = [Command.create({
|
||||
'partner_id': self.partner_a.id,
|
||||
'price': 750.0,
|
||||
'min_qty': 10
|
||||
})]
|
||||
|
||||
down_po = self.env['purchase.order'].create({
|
||||
'partner_id': self.partner_a.id,
|
||||
'order_line': [Command.create({
|
||||
'product_id': self.product_a.id,
|
||||
'product_qty': 10,
|
||||
})]
|
||||
})
|
||||
|
||||
product_line = down_po.order_line
|
||||
self.assertEqual(product_line.price_unit, 750.0)
|
||||
down_po.order_line.price_unit = 800
|
||||
down_po.button_confirm()
|
||||
|
||||
self.init_invoice('in_invoice', amounts=[1600.00], post=True)
|
||||
|
||||
match_lines = self.env['purchase.bill.line.match'].search([('partner_id', '=', self.partner_a.id)])
|
||||
action = match_lines.action_add_to_po()
|
||||
|
||||
wizard = self.env['bill.to.po.wizard'].with_context({**action['context'], 'active_ids': match_lines.ids}).create({})
|
||||
wizard.action_add_downpayment()
|
||||
|
||||
self.assertEqual(product_line.price_unit, 800.0)
|
||||
|
||||
def test_downpayment_in_accrued_expense_entry(self):
|
||||
"""Check that the downpayment is not included in the accrued expense entry"""
|
||||
po = self.init_purchase(confirm=True, products=[self.product_order])
|
||||
|
||||
self.init_invoice('in_invoice', amounts=[1600.00], post=True)
|
||||
|
||||
match_lines = self.env['purchase.bill.line.match'].search([('partner_id', '=', self.partner_a.id)])
|
||||
action = match_lines.action_add_to_po()
|
||||
|
||||
wizard = self.env['bill.to.po.wizard'].with_context({**action['context'], 'active_ids': match_lines.ids}).create({})
|
||||
wizard.action_add_downpayment()
|
||||
|
||||
account_expense = self.company_data['default_account_expense']
|
||||
accrued_wizard = self.env['account.accrued.orders.wizard'].with_context(
|
||||
active_model='purchase.order',
|
||||
active_ids=po.ids,
|
||||
).create({
|
||||
'account_id': self.company_data['default_account_expense'].id,
|
||||
'date': fields.Date.today(),
|
||||
})
|
||||
|
||||
# Receive 1 qty to have something to accrual.
|
||||
po.order_line.qty_received = 1
|
||||
|
||||
self.assertRecordValues(self.env['account.move'].search(accrued_wizard.create_entries()['domain']).line_ids, [
|
||||
# reverse move lines
|
||||
{'account_id': account_expense.id, 'debit': 0, 'credit': 235.0},
|
||||
{'account_id': accrued_wizard.account_id.id, 'debit': 235.0, 'credit': 0},
|
||||
# move lines
|
||||
{'account_id': account_expense.id, 'debit': 235.0, 'credit': 0},
|
||||
{'account_id': accrued_wizard.account_id.id, 'debit': 0, 'credit': 235.0},
|
||||
])
|
||||
self.assertFalse(self.env['account.move'].search(accrued_wizard.create_entries()['domain']).line_ids.filtered(lambda l: l.is_downpayment))
|
||||
|
||||
def test_downpayment_exchange_rate(self):
|
||||
self.env['res.currency.rate'].create({'currency_id': self.other_currency.id, 'rate': 1.5})
|
||||
|
||||
po = self.init_purchase(products=[self.product_order])
|
||||
po.button_confirm()
|
||||
self.init_invoice('in_invoice', amounts=[100.00], post=True, currency=self.other_currency)
|
||||
|
||||
match_lines = self.env['purchase.bill.line.match'].search([('partner_id', '=', self.partner_a.id)])
|
||||
action = match_lines.action_add_to_po()
|
||||
|
||||
wizard = self.env['bill.to.po.wizard'].with_context({**action['context'], 'active_ids': match_lines.ids}).create({})
|
||||
wizard.action_add_downpayment()
|
||||
|
||||
po_dp_line = po.order_line.filtered(lambda l: l.display_type != 'line_section' and l.is_downpayment)
|
||||
self.assertEqual(po_dp_line.price_unit, 66.67)
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from odoo import Command
|
||||
from odoo.tests import HttpCase, tagged
|
||||
|
||||
from odoo.addons.account.tests.common import AccountTestInvoicingCommon
|
||||
|
||||
|
||||
@tagged('-at_install', 'post_install')
|
||||
class TestPurchaseFlowTourPostInstall(AccountTestInvoicingCommon, HttpCase):
|
||||
|
||||
def test_basic_purchase_flow_with_minimal_access_rights(self):
|
||||
"""
|
||||
Test that a purchase user with minimal access rights can open both the list and form view,
|
||||
create and process a purchase order, upload and open the associated vendor bill.
|
||||
"""
|
||||
purchase_user = self.env['res.users'].create({
|
||||
'name': 'Super Purchase Woman',
|
||||
'login': 'SuperPurchaseWoman',
|
||||
'group_ids': [Command.set([self.ref('purchase.group_purchase_user')])],
|
||||
})
|
||||
# create and confirm a PO to populate the list view
|
||||
purchase_order = self.env['purchase.order'].with_user(purchase_user.id).create({
|
||||
'partner_id': self.partner_a.id,
|
||||
'order_line': [Command.create({
|
||||
'name': self.product.name,
|
||||
'product_id': self.product.id,
|
||||
'product_uom_qty': 1,
|
||||
})],
|
||||
})
|
||||
purchase_order.button_approve()
|
||||
self.start_tour('/odoo', 'test_basic_purchase_flow_with_minimal_access_rights', login='SuperPurchaseWoman')
|
||||
|
|
@ -3,8 +3,8 @@
|
|||
from datetime import timedelta
|
||||
|
||||
from odoo.addons.account.tests.common import AccountTestInvoicingCommon
|
||||
from odoo.tests import tagged
|
||||
from odoo.tests.common import Form
|
||||
from odoo.exceptions import UserError
|
||||
from odoo.tests import Form, tagged
|
||||
from odoo import Command, fields
|
||||
|
||||
|
||||
|
|
@ -13,6 +13,8 @@ class TestPurchaseToInvoiceCommon(AccountTestInvoicingCommon):
|
|||
@classmethod
|
||||
def setUpClass(cls):
|
||||
super(TestPurchaseToInvoiceCommon, cls).setUpClass()
|
||||
cls.other_currency = cls.setup_other_currency('EUR')
|
||||
cls.env.user.group_ids += cls.env.ref('uom.group_uom')
|
||||
uom_unit = cls.env.ref('uom.product_uom_unit')
|
||||
uom_hour = cls.env.ref('uom.product_uom_hour')
|
||||
cls.product_order = cls.env['product.product'].create({
|
||||
|
|
@ -21,18 +23,36 @@ class TestPurchaseToInvoiceCommon(AccountTestInvoicingCommon):
|
|||
'list_price': 280.0,
|
||||
'type': 'consu',
|
||||
'uom_id': uom_unit.id,
|
||||
'uom_po_id': uom_unit.id,
|
||||
'purchase_method': 'purchase',
|
||||
'default_code': 'PROD_ORDER',
|
||||
'taxes_id': False,
|
||||
})
|
||||
cls.product_order_other_price = cls.env['product.product'].create({
|
||||
'name': "Zed+ Antivirus",
|
||||
'standard_price': 240.0,
|
||||
'list_price': 290.0,
|
||||
'type': 'consu',
|
||||
'uom_id': uom_unit.id,
|
||||
'purchase_method': 'purchase',
|
||||
'default_code': 'PROD_ORDER',
|
||||
'taxes_id': False,
|
||||
})
|
||||
cls.product_order_var_name = cls.env['product.product'].create({
|
||||
'name': "Zed+ Antivirus Var Name",
|
||||
'standard_price': 235.0,
|
||||
'list_price': 280.0,
|
||||
'type': 'consu',
|
||||
'uom_id': uom_unit.id,
|
||||
'purchase_method': 'purchase',
|
||||
'default_code': 'PROD_ORDER_VAR_NAME',
|
||||
'taxes_id': False,
|
||||
})
|
||||
cls.service_deliver = cls.env['product.product'].create({
|
||||
'name': "Cost-plus Contract",
|
||||
'standard_price': 200.0,
|
||||
'list_price': 180.0,
|
||||
'type': 'service',
|
||||
'uom_id': uom_unit.id,
|
||||
'uom_po_id': uom_unit.id,
|
||||
'purchase_method': 'receive',
|
||||
'default_code': 'SERV_DEL',
|
||||
'taxes_id': False,
|
||||
|
|
@ -43,7 +63,6 @@ class TestPurchaseToInvoiceCommon(AccountTestInvoicingCommon):
|
|||
'list_price': 90.0,
|
||||
'type': 'service',
|
||||
'uom_id': uom_hour.id,
|
||||
'uom_po_id': uom_hour.id,
|
||||
'purchase_method': 'purchase',
|
||||
'default_code': 'PRE-PAID',
|
||||
'taxes_id': False,
|
||||
|
|
@ -54,7 +73,6 @@ class TestPurchaseToInvoiceCommon(AccountTestInvoicingCommon):
|
|||
'list_price': 70.0,
|
||||
'type': 'consu',
|
||||
'uom_id': uom_unit.id,
|
||||
'uom_po_id': uom_unit.id,
|
||||
'purchase_method': 'receive',
|
||||
'default_code': 'PROD_DEL',
|
||||
'taxes_id': False,
|
||||
|
|
@ -72,9 +90,8 @@ class TestPurchaseToInvoiceCommon(AccountTestInvoicingCommon):
|
|||
for product in (products or []):
|
||||
with po_form.order_line.new() as line_form:
|
||||
line_form.product_id = product
|
||||
line_form.price_unit = product.list_price
|
||||
line_form.product_qty = 1
|
||||
line_form.product_uom = product.uom_id
|
||||
line_form.product_uom_id = product.uom_id
|
||||
line_form.date_planned = date_planned
|
||||
if taxes:
|
||||
line_form.tax_ids.clear()
|
||||
|
|
@ -103,19 +120,19 @@ class TestPurchaseToInvoice(TestPurchaseToInvoiceCommon):
|
|||
'name': self.product_deliver.name,
|
||||
'product_id': self.product_deliver.id,
|
||||
'product_qty': 10.0,
|
||||
'product_uom': self.product_deliver.uom_id.id,
|
||||
'product_uom_id': self.product_deliver.uom_id.id,
|
||||
'price_unit': self.product_deliver.list_price,
|
||||
'order_id': purchase_order.id,
|
||||
'taxes_id': False,
|
||||
'tax_ids': False,
|
||||
})
|
||||
pol_serv_deliver = PurchaseOrderLine.create({
|
||||
'name': self.service_deliver.name,
|
||||
'product_id': self.service_deliver.id,
|
||||
'product_qty': 10.0,
|
||||
'product_uom': self.service_deliver.uom_id.id,
|
||||
'product_uom_id': self.service_deliver.uom_id.id,
|
||||
'price_unit': self.service_deliver.list_price,
|
||||
'order_id': purchase_order.id,
|
||||
'taxes_id': False,
|
||||
'tax_ids': False,
|
||||
})
|
||||
purchase_order.button_confirm()
|
||||
|
||||
|
|
@ -136,6 +153,12 @@ class TestPurchaseToInvoice(TestPurchaseToInvoiceCommon):
|
|||
self.assertEqual(line.qty_to_invoice, 0.0)
|
||||
self.assertEqual(line.qty_invoiced, 5)
|
||||
|
||||
purchase_order.invoice_ids.button_cancel()
|
||||
self.assertEqual(purchase_order.invoice_status, "to invoice")
|
||||
for line in purchase_order.order_line:
|
||||
self.assertEqual(line.qty_to_invoice, 5)
|
||||
self.assertEqual(line.qty_invoiced, 0.0)
|
||||
|
||||
def test_vendor_bill_ordered(self):
|
||||
"""Test if a order of product invoiced by ordered quantity can be
|
||||
correctly invoiced."""
|
||||
|
|
@ -147,19 +170,19 @@ class TestPurchaseToInvoice(TestPurchaseToInvoiceCommon):
|
|||
'name': self.product_order.name,
|
||||
'product_id': self.product_order.id,
|
||||
'product_qty': 10.0,
|
||||
'product_uom': self.product_order.uom_id.id,
|
||||
'product_uom_id': self.product_order.uom_id.id,
|
||||
'price_unit': self.product_order.list_price,
|
||||
'order_id': purchase_order.id,
|
||||
'taxes_id': False,
|
||||
'tax_ids': False,
|
||||
})
|
||||
pol_serv_order = PurchaseOrderLine.create({
|
||||
'name': self.service_order.name,
|
||||
'product_id': self.service_order.id,
|
||||
'product_qty': 10.0,
|
||||
'product_uom': self.service_order.uom_id.id,
|
||||
'product_uom_id': self.service_order.uom_id.id,
|
||||
'price_unit': self.service_order.list_price,
|
||||
'order_id': purchase_order.id,
|
||||
'taxes_id': False,
|
||||
'tax_ids': False,
|
||||
})
|
||||
purchase_order.button_confirm()
|
||||
|
||||
|
|
@ -191,19 +214,19 @@ class TestPurchaseToInvoice(TestPurchaseToInvoiceCommon):
|
|||
'name': self.product_deliver.name,
|
||||
'product_id': self.product_deliver.id,
|
||||
'product_qty': 10.0,
|
||||
'product_uom': self.product_deliver.uom_id.id,
|
||||
'product_uom_id': self.product_deliver.uom_id.id,
|
||||
'price_unit': self.product_deliver.list_price,
|
||||
'order_id': purchase_order.id,
|
||||
'taxes_id': False,
|
||||
'tax_ids': False,
|
||||
})
|
||||
pol_serv_deliver = PurchaseOrderLine.create({
|
||||
'name': self.service_deliver.name,
|
||||
'product_id': self.service_deliver.id,
|
||||
'product_qty': 10.0,
|
||||
'product_uom': self.service_deliver.uom_id.id,
|
||||
'product_uom_id': self.service_deliver.uom_id.id,
|
||||
'price_unit': self.service_deliver.list_price,
|
||||
'order_id': purchase_order.id,
|
||||
'taxes_id': False,
|
||||
'tax_ids': False,
|
||||
})
|
||||
purchase_order.button_confirm()
|
||||
|
||||
|
|
@ -236,19 +259,19 @@ class TestPurchaseToInvoice(TestPurchaseToInvoiceCommon):
|
|||
'name': self.product_order.name,
|
||||
'product_id': self.product_order.id,
|
||||
'product_qty': 10.0,
|
||||
'product_uom': self.product_order.uom_id.id,
|
||||
'product_uom_id': self.product_order.uom_id.id,
|
||||
'price_unit': self.product_order.list_price,
|
||||
'order_id': purchase_order.id,
|
||||
'taxes_id': False,
|
||||
'tax_ids': False,
|
||||
})
|
||||
pol_serv_order = PurchaseOrderLine.create({
|
||||
'name': self.service_order.name,
|
||||
'product_id': self.service_order.id,
|
||||
'product_qty': 10.0,
|
||||
'product_uom': self.service_order.uom_id.id,
|
||||
'product_uom_id': self.service_order.uom_id.id,
|
||||
'price_unit': self.service_order.list_price,
|
||||
'order_id': purchase_order.id,
|
||||
'taxes_id': False,
|
||||
'tax_ids': False,
|
||||
})
|
||||
purchase_order.button_confirm()
|
||||
|
||||
|
|
@ -289,10 +312,10 @@ class TestPurchaseToInvoice(TestPurchaseToInvoiceCommon):
|
|||
'name': self.product_order.name,
|
||||
'product_id': self.product_order.id,
|
||||
'product_qty': 1,
|
||||
'product_uom': self.product_order.uom_id.id,
|
||||
'product_uom_id': self.product_order.uom_id.id,
|
||||
'price_unit': 1000,
|
||||
'order_id': po.id,
|
||||
'taxes_id': False,
|
||||
'tax_ids': False,
|
||||
})
|
||||
po.button_confirm()
|
||||
pol_prod_order.write({'qty_received': 1})
|
||||
|
|
@ -305,13 +328,13 @@ class TestPurchaseToInvoice(TestPurchaseToInvoiceCommon):
|
|||
|
||||
self.assertInvoiceValues(move, [
|
||||
{
|
||||
'display_type': 'product',
|
||||
'amount_currency': 1000,
|
||||
'balance': 1000,
|
||||
}, {
|
||||
'display_type': 'product',
|
||||
'amount_currency': 500,
|
||||
'balance': 500,
|
||||
}, {
|
||||
'display_type': 'product',
|
||||
'amount_currency': 1000,
|
||||
'balance': 1000,
|
||||
}, {
|
||||
'display_type': 'payment_term',
|
||||
'amount_currency': -1500,
|
||||
|
|
@ -332,9 +355,9 @@ class TestPurchaseToInvoice(TestPurchaseToInvoiceCommon):
|
|||
'name': self.product_a.name,
|
||||
'product_id': self.product_a.id,
|
||||
'product_qty': 12,
|
||||
'product_uom': self.product_a.uom_id.id,
|
||||
'product_uom_id': self.product_a.uom_id.id,
|
||||
'price_unit': 0.001,
|
||||
'taxes_id': False,
|
||||
'tax_ids': False,
|
||||
})]
|
||||
})
|
||||
po.button_confirm()
|
||||
|
|
@ -351,8 +374,8 @@ class TestPurchaseToInvoice(TestPurchaseToInvoiceCommon):
|
|||
the po, it is the same that is mentioned in the bill.
|
||||
"""
|
||||
# Required for `analytic.group_analytic_accounting` to be visible in the view
|
||||
self.env.user.groups_id += self.env.ref('analytic.group_analytic_accounting')
|
||||
analytic_plan = self.env['account.analytic.plan'].create({'name': 'Plan Test', 'company_id': False})
|
||||
self.env.user.group_ids += self.env.ref('analytic.group_analytic_accounting')
|
||||
analytic_plan = self.env['account.analytic.plan'].create({'name': 'Plan Test'})
|
||||
analytic_account_default = self.env['account.analytic.account'].create({'name': 'default', 'plan_id': analytic_plan.id})
|
||||
analytic_account_manual = self.env['account.analytic.account'].create({'name': 'manual', 'plan_id': analytic_plan.id})
|
||||
|
||||
|
|
@ -379,10 +402,10 @@ class TestPurchaseToInvoice(TestPurchaseToInvoiceCommon):
|
|||
self.assertRecordValues(aml, [{'analytic_distribution': analytic_distribution_manual}])
|
||||
|
||||
def test_purchase_order_analytic_account_product_change(self):
|
||||
self.env.user.groups_id += self.env.ref('account.group_account_readonly')
|
||||
self.env.user.groups_id += self.env.ref('analytic.group_analytic_accounting')
|
||||
self.env.user.group_ids += self.env.ref('account.group_account_readonly')
|
||||
self.env.user.group_ids += self.env.ref('analytic.group_analytic_accounting')
|
||||
|
||||
analytic_plan = self.env['account.analytic.plan'].create({'name': 'Plan Test', 'company_id': False})
|
||||
analytic_plan = self.env['account.analytic.plan'].create({'name': 'Plan Test'})
|
||||
analytic_account_super = self.env['account.analytic.account'].create({'name': 'Super Account', 'plan_id': analytic_plan.id})
|
||||
analytic_account_great = self.env['account.analytic.account'].create({'name': 'Great Account', 'plan_id': analytic_plan.id})
|
||||
|
||||
|
|
@ -427,9 +450,10 @@ class TestPurchaseToInvoice(TestPurchaseToInvoiceCommon):
|
|||
"""
|
||||
Test whether, when an analytic plan is set within the scope (applicability) of purchase
|
||||
and with an account prefix set in the distribution model,
|
||||
the default analytic account is correctly set during the conversion from po to invoice
|
||||
the default analytic account is correctly set during the conversion from po to invoice.
|
||||
An additional analytic account set manually in another plan is also passed to the invoice.
|
||||
"""
|
||||
self.env.user.groups_id += self.env.ref('analytic.group_analytic_accounting')
|
||||
self.env.user.group_ids += self.env.ref('analytic.group_analytic_accounting')
|
||||
analytic_plan_default = self.env['account.analytic.plan'].create({
|
||||
'name': 'default',
|
||||
'applicability_ids': [Command.create({
|
||||
|
|
@ -438,6 +462,10 @@ class TestPurchaseToInvoice(TestPurchaseToInvoiceCommon):
|
|||
})]
|
||||
})
|
||||
analytic_account_default = self.env['account.analytic.account'].create({'name': 'default', 'plan_id': analytic_plan_default.id})
|
||||
# Create an additional analytic account in another plan
|
||||
analytic_plan_2 = self.env['account.analytic.plan'].create({'name': 'Plan Test'})
|
||||
analytic_account_2 = self.env['account.analytic.account'].create({'name': 'manual', 'plan_id': analytic_plan_2.id})
|
||||
analytic_distribution_manual = {str(analytic_account_2.id): 100}
|
||||
|
||||
analytic_distribution_model = self.env['account.analytic.distribution.model'].create({
|
||||
'account_prefix': '600',
|
||||
|
|
@ -452,11 +480,14 @@ class TestPurchaseToInvoice(TestPurchaseToInvoiceCommon):
|
|||
'product_id': self.product_a.id
|
||||
})
|
||||
self.assertFalse(po.order_line.analytic_distribution, "There should be no analytic set.")
|
||||
# Add another analytic account to the line. It should be passed to the invoice
|
||||
po.order_line.analytic_distribution = analytic_distribution_manual
|
||||
po.button_confirm()
|
||||
po.order_line.qty_received = 1
|
||||
po.action_create_invoice()
|
||||
self.assertRecordValues(po.invoice_ids.invoice_line_ids,
|
||||
[{'analytic_distribution': analytic_distribution_model.analytic_distribution}])
|
||||
self.assertRecordValues(po.invoice_ids.invoice_line_ids, [{
|
||||
'analytic_distribution': analytic_distribution_model.analytic_distribution | analytic_distribution_manual
|
||||
}])
|
||||
|
||||
def test_sequence_invoice_lines_from_multiple_purchases(self):
|
||||
"""Test if the invoice lines are sequenced by purchase order when creating an invoice
|
||||
|
|
@ -469,9 +500,9 @@ class TestPurchaseToInvoice(TestPurchaseToInvoiceCommon):
|
|||
'name': self.product_order.name,
|
||||
'product_id': self.product_order.id,
|
||||
'product_qty': 10.0,
|
||||
'product_uom': self.product_order.uom_id.id,
|
||||
'product_uom_id': self.product_order.uom_id.id,
|
||||
'price_unit': self.product_order.list_price,
|
||||
'taxes_id': False,
|
||||
'tax_ids': False,
|
||||
'sequence': sequence_number,
|
||||
}) for sequence_number in range(10, 13)]
|
||||
purchase_order = self.env['purchase.order'].with_context(tracking_disable=True).create({
|
||||
|
|
@ -503,9 +534,9 @@ class TestPurchaseToInvoice(TestPurchaseToInvoiceCommon):
|
|||
'name': self.product_order.name,
|
||||
'product_id': self.product_order.id,
|
||||
'product_qty': 10.0,
|
||||
'product_uom': self.product_order.uom_id.id,
|
||||
'product_uom_id': self.product_order.uom_id.id,
|
||||
'price_unit': self.product_order.list_price,
|
||||
'taxes_id': False,
|
||||
'tax_ids': False,
|
||||
'sequence': sequence_number,
|
||||
}) for sequence_number in range(10, 13)]
|
||||
purchase_order = self.env['purchase.order'].with_context(tracking_disable=True).create({
|
||||
|
|
@ -545,9 +576,9 @@ class TestPurchaseToInvoice(TestPurchaseToInvoiceCommon):
|
|||
'name': self.product_deliver.name,
|
||||
'product_id': self.product_deliver.id,
|
||||
'product_qty': 20.0,
|
||||
'product_uom': self.product_deliver.uom_id.id,
|
||||
'product_uom_id': self.product_deliver.uom_id.id,
|
||||
'price_unit': self.product_deliver.list_price,
|
||||
'taxes_id': False,
|
||||
'tax_ids': False,
|
||||
}),
|
||||
],
|
||||
})
|
||||
|
|
@ -627,6 +658,118 @@ class TestPurchaseToInvoice(TestPurchaseToInvoiceCommon):
|
|||
po_line.write({'product_qty': 4})
|
||||
self.assertEqual(40.0, po_line.price_unit, "Unit price should be set to 40.0 for 4 quantity")
|
||||
|
||||
def test_supplier_discounted_price(self):
|
||||
""" Check the lower price (discount included) is used.
|
||||
"""
|
||||
uom_dozen = self.env.ref('uom.product_uom_dozen')
|
||||
supplierinfo_common_vals = {
|
||||
'partner_id': self.partner_a.id,
|
||||
'product_id': self.product_order.id,
|
||||
'product_tmpl_id': self.product_order.product_tmpl_id.id,
|
||||
}
|
||||
supplierinfo = self.env['product.supplierinfo'].create([
|
||||
{
|
||||
**supplierinfo_common_vals,
|
||||
'price': 100.0,
|
||||
'discount': 0, # Real price by unit: 100.00
|
||||
}, {
|
||||
**supplierinfo_common_vals,
|
||||
'price': 120.0,
|
||||
'discount': 20, # Real price by unit: 96.00
|
||||
}, {
|
||||
**supplierinfo_common_vals,
|
||||
'min_qty': 10,
|
||||
'price': 140.0,
|
||||
'discount': 50, # Real price by unit: 70.00
|
||||
},
|
||||
])
|
||||
self.assertRecordValues(supplierinfo, [
|
||||
{'price_discounted': 100},
|
||||
{'price_discounted': 96},
|
||||
{'price_discounted': 70},
|
||||
])
|
||||
|
||||
po_form = Form(self.env['purchase.order'])
|
||||
po_form.partner_id = self.partner_a
|
||||
with po_form.order_line.new() as po_line_form:
|
||||
po_line_form.product_id = self.product_order
|
||||
po_line_form.product_qty = 1
|
||||
po = po_form.save()
|
||||
po_line = po.order_line[0]
|
||||
self.assertEqual(120.0, po_line.price_unit)
|
||||
self.assertEqual(20, po_line.discount)
|
||||
self.assertEqual(96.0, po_line.price_unit_discounted)
|
||||
self.assertEqual(96.0, po_line.price_subtotal)
|
||||
|
||||
# Increase the PO line quantity: it should take another price if min. qty. is reached.
|
||||
po_form = Form(po)
|
||||
with po_form.order_line.edit(0) as po_line_form:
|
||||
po_line_form.product_uom_id = uom_dozen
|
||||
po_line_form.product_qty = 3
|
||||
po = po_form.save()
|
||||
po_line = po.order_line[0]
|
||||
|
||||
self.assertEqual(1680.0, po_line.price_unit, "140.0 * 12 = 1680.0")
|
||||
self.assertEqual(50, po_line.discount)
|
||||
self.assertEqual(840.0, po_line.price_unit_discounted, "1680.0 * 0.5 = 840.0")
|
||||
self.assertEqual(2520.0, po_line.price_subtotal, "840.0 * 3 = 2520.0")
|
||||
|
||||
def test_invoice_line_name_has_product_name(self):
|
||||
""" Testing that when invoicing a sales order, the invoice line name ALWAYS contains the product name. """
|
||||
# Create a purchase order with different descriptions
|
||||
po = self.env['purchase.order'].with_context(tracking_disable=True).create({
|
||||
'partner_id': self.partner_a.id,
|
||||
})
|
||||
PurchaseOrderLine = self.env['purchase.order.line'].with_context(tracking_disable=True)
|
||||
pol_prod_no_redundancy = PurchaseOrderLine.create({
|
||||
'name': "just a description",
|
||||
'product_id': self.product_deliver.id,
|
||||
'product_qty': 1,
|
||||
'product_uom_id': self.product_deliver.uom_id.id,
|
||||
'price_unit': self.product_deliver.list_price,
|
||||
'order_id': po.id,
|
||||
'tax_ids': False,
|
||||
})
|
||||
pol_prod_same = PurchaseOrderLine.create({
|
||||
'name': self.product_deliver.display_name,
|
||||
'product_id': self.product_deliver.id,
|
||||
'product_qty': 1,
|
||||
'product_uom_id': self.product_deliver.uom_id.id,
|
||||
'price_unit': self.product_deliver.list_price,
|
||||
'order_id': po.id,
|
||||
'tax_ids': False,
|
||||
})
|
||||
pol_prod_product_in_name = PurchaseOrderLine.create({
|
||||
'name': f"{self.product_deliver.display_name} with more description",
|
||||
'product_id': self.product_deliver.id,
|
||||
'product_qty': 1,
|
||||
'product_uom_id': self.product_deliver.uom_id.id,
|
||||
'price_unit': self.product_deliver.list_price,
|
||||
'order_id': po.id,
|
||||
'tax_ids': False,
|
||||
})
|
||||
pol_prod_name_in_product = PurchaseOrderLine.create({
|
||||
'name': "Switch",
|
||||
'product_id': self.product_deliver.id,
|
||||
'product_qty': 1,
|
||||
'product_uom_id': self.product_deliver.uom_id.id,
|
||||
'price_unit': self.product_deliver.list_price,
|
||||
'order_id': po.id,
|
||||
'tax_ids': False,
|
||||
})
|
||||
|
||||
# Invoice the purchase order
|
||||
po.button_confirm()
|
||||
po.order_line.qty_received = 4
|
||||
po.action_create_invoice()
|
||||
inv = po.invoice_ids
|
||||
|
||||
# Check the invoice line names
|
||||
self.assertEqual(inv.invoice_line_ids[0].name, f"{pol_prod_no_redundancy.product_id.display_name}\n{pol_prod_no_redundancy.name}", "When the description doesn't contain the product name, it should be added to the invoice line name")
|
||||
self.assertEqual(inv.invoice_line_ids[1].name, f"{pol_prod_same.name}", "When the description is the product name, the invoice line name should only be the description")
|
||||
self.assertEqual(inv.invoice_line_ids[2].name, f"{pol_prod_product_in_name.name}", "When description contains the product name, the invoice line name should only be the description")
|
||||
self.assertEqual(inv.invoice_line_ids[3].name, f"{pol_prod_name_in_product.product_id.display_name}\n{pol_prod_name_in_product.name}", "When the product name contains the description, the invoice line name should be the product name and the description")
|
||||
|
||||
|
||||
@tagged('post_install', '-at_install')
|
||||
class TestInvoicePurchaseMatch(TestPurchaseToInvoiceCommon):
|
||||
|
|
@ -651,57 +794,281 @@ class TestInvoicePurchaseMatch(TestPurchaseToInvoiceCommon):
|
|||
self.assertTrue(invoice.id in po.invoice_ids.ids)
|
||||
self.assertEqual(invoice.amount_total, po.amount_total)
|
||||
|
||||
def test_subset_total_match_prefer_purchase(self):
|
||||
def test_subset_total_match_from_ocr(self):
|
||||
po = self.init_purchase(confirm=True, products=[self.product_order, self.service_order])
|
||||
invoice = self.init_invoice('in_invoice', partner=self.partner_a, products=[self.product_order])
|
||||
|
||||
invoice._find_and_set_purchase_orders(
|
||||
['my_match_reference'], invoice.partner_id.id, invoice.amount_total, prefer_purchase_line=True)
|
||||
['my_match_reference'], invoice.partner_id.id, invoice.amount_total, from_ocr=True)
|
||||
additional_unmatch_po_line = po.order_line.filtered(lambda l: l.product_id == self.service_order)
|
||||
|
||||
self.assertTrue(invoice.id in po.invoice_ids.ids)
|
||||
self.assertTrue(additional_unmatch_po_line.id in invoice.line_ids.purchase_line_id.ids)
|
||||
self.assertTrue(invoice.line_ids.filtered(lambda l: l.purchase_line_id == additional_unmatch_po_line).quantity == 0)
|
||||
|
||||
def test_subset_total_match_reject_purchase(self):
|
||||
def test_subset_match_from_edi_full(self):
|
||||
"""An invoice totally matches a purchase order line by line
|
||||
"""
|
||||
po = self.init_purchase(confirm=True, products=[self.product_order, self.service_order])
|
||||
invoice = self.init_invoice('in_invoice', partner=self.partner_a, products=[self.product_order, self.service_order])
|
||||
|
||||
invoice._find_and_set_purchase_orders(
|
||||
['my_match_reference'], invoice.partner_id.id, invoice.amount_total, from_ocr=False)
|
||||
|
||||
self.assertTrue(invoice.id in po.invoice_ids.ids)
|
||||
invoice_lines = invoice.line_ids.filtered(lambda l: l.price_unit)
|
||||
self.assertEqual(len(invoice_lines), 2)
|
||||
for line in invoice_lines:
|
||||
self.assertTrue(line.purchase_line_id in po.order_line)
|
||||
self.assertEqual(invoice.amount_total, po.amount_total)
|
||||
|
||||
def test_subset_match_from_edi_partial_po(self):
|
||||
"""A line of the invoice totally matches a 1-line purchase order
|
||||
"""
|
||||
po = self.init_purchase(confirm=True, products=[self.product_order])
|
||||
invoice = self.init_invoice('in_invoice', partner=self.partner_a, products=[self.product_order, self.service_order])
|
||||
|
||||
invoice._find_and_set_purchase_orders(
|
||||
['my_match_reference'], invoice.partner_id.id, invoice.amount_total, from_ocr=False)
|
||||
|
||||
self.assertTrue(invoice.id in po.invoice_ids.ids)
|
||||
invoice_lines = invoice.line_ids.filtered(lambda l: l.price_unit)
|
||||
self.assertEqual(len(invoice_lines), 2)
|
||||
for line in po.order_line:
|
||||
self.assertTrue(line in invoice_lines.purchase_line_id)
|
||||
|
||||
def test_subset_match_from_edi_partial_inv(self):
|
||||
"""An invoice totally matches some purchase order line
|
||||
"""
|
||||
po = self.init_purchase(confirm=True, products=[self.product_order, self.service_order])
|
||||
invoice = self.init_invoice('in_invoice', partner=self.partner_a, products=[self.product_order])
|
||||
|
||||
invoice._find_and_set_purchase_orders(
|
||||
['my_match_reference'], invoice.partner_id.id, invoice.amount_total, prefer_purchase_line=False)
|
||||
additional_unmatch_po_line = po.order_line.filtered(lambda l: l.product_id == self.service_order)
|
||||
['my_match_reference'], invoice.partner_id.id, invoice.amount_total, from_ocr=False)
|
||||
|
||||
self.assertTrue(invoice.id in po.invoice_ids.ids)
|
||||
self.assertTrue(additional_unmatch_po_line.id not in invoice.line_ids.purchase_line_id.ids)
|
||||
invoice_lines = invoice.line_ids.filtered(lambda l: l.price_unit)
|
||||
self.assertEqual(len(invoice_lines), 1)
|
||||
for line in invoice_lines:
|
||||
self.assertTrue(line.purchase_line_id in po.order_line)
|
||||
|
||||
def test_po_match_prefer_purchase(self):
|
||||
def test_subset_match_from_edi_same_unit_price(self):
|
||||
"""An invoice matches some purchase order line by unit price
|
||||
"""
|
||||
po = self.init_purchase(confirm=True, products=[self.product_order_var_name, self.product_order])
|
||||
invoice = self.init_invoice('in_invoice', partner=self.partner_a, products=[self.product_order])
|
||||
|
||||
invoice._find_and_set_purchase_orders(
|
||||
['my_match_reference'], invoice.partner_id.id, invoice.amount_total, from_ocr=False)
|
||||
|
||||
self.assertTrue(invoice.id in po.invoice_ids.ids)
|
||||
invoice_lines = invoice.line_ids.filtered(lambda l: l.price_unit)
|
||||
self.assertEqual(len(invoice_lines), 1)
|
||||
for line in invoice_lines:
|
||||
self.assertTrue(line.purchase_line_id in po.order_line)
|
||||
|
||||
def test_subset_match_from_edi_and_diff_unit_price(self):
|
||||
"""An invoice matches some purchase order line but not another one because of a unit price difference
|
||||
"""
|
||||
po = self.init_purchase(confirm=True, products=[self.product_order_var_name, self.product_order])
|
||||
invoice = self.init_invoice('in_invoice', partner=self.partner_a, products=[self.product_order, self.product_order_other_price])
|
||||
|
||||
invoice._find_and_set_purchase_orders(
|
||||
['my_match_reference'], invoice.partner_id.id, invoice.amount_total, from_ocr=False)
|
||||
|
||||
self.assertTrue(invoice.id in po.invoice_ids.ids)
|
||||
invoice_lines = invoice.line_ids.filtered(lambda l: l.price_unit)
|
||||
self.assertEqual(len(invoice_lines), 2)
|
||||
for line in invoice_lines:
|
||||
if (line.product_id == self.product_order):
|
||||
self.assertTrue(line.purchase_line_id in po.order_line)
|
||||
else:
|
||||
self.assertFalse(line.purchase_line_id in po.order_line)
|
||||
|
||||
def test_subset_not_match_non_invoice_lines(self):
|
||||
"""Test that a purchase line with a line of 0 as unit price won't match
|
||||
with a non-invoice-lines (not an invoice_line_ids)
|
||||
"""
|
||||
uom_unit = self.env.ref('uom.product_uom_unit')
|
||||
product_order_zero_price = self.env['product.product'].create({
|
||||
'name': "A zero price product",
|
||||
'standard_price': 0.0,
|
||||
'list_price': 0.0,
|
||||
'type': 'consu',
|
||||
'uom_id': uom_unit.id,
|
||||
'purchase_method': 'purchase',
|
||||
'default_code': 'PROD_ORDER',
|
||||
'taxes_id': False,
|
||||
})
|
||||
po = self.init_purchase(confirm=True, products=[product_order_zero_price])
|
||||
invoice = self.init_invoice('in_invoice', partner=self.partner_a, products=[self.product_order])
|
||||
invoice._find_and_set_purchase_orders(
|
||||
['my_match_reference'], invoice.partner_id.id, invoice.amount_total, from_ocr=False)
|
||||
|
||||
self.assertFalse(invoice.id in po.invoice_ids.ids)
|
||||
|
||||
def test_po_match_from_ocr(self):
|
||||
po = self.init_purchase(confirm=True, products=[self.product_order, self.service_order])
|
||||
invoice = self.init_invoice('in_invoice', products=[self.product_a])
|
||||
|
||||
invoice._find_and_set_purchase_orders(
|
||||
['my_match_reference'], invoice.partner_id.id, invoice.amount_total, prefer_purchase_line=True)
|
||||
['my_match_reference'], invoice.partner_id.id, invoice.amount_total, from_ocr=True)
|
||||
|
||||
self.assertTrue(invoice.id in po.invoice_ids.ids)
|
||||
|
||||
def test_po_match_reject_purchase(self):
|
||||
def test_no_match_same_reference(self):
|
||||
po = self.init_purchase(confirm=True, products=[self.product_order, self.service_order])
|
||||
invoice = self.init_invoice('in_invoice', products=[self.product_a])
|
||||
|
||||
invoice._find_and_set_purchase_orders(
|
||||
['my_match_reference'], invoice.partner_id.id, invoice.amount_total, prefer_purchase_line=False)
|
||||
['my_match_reference'], invoice.partner_id.id, invoice.amount_total, from_ocr=False)
|
||||
|
||||
self.assertTrue(invoice.id not in po.invoice_ids.ids)
|
||||
self.assertNotEqual(invoice.amount_total, po.amount_total)
|
||||
|
||||
def test_no_match(self):
|
||||
po = self.init_purchase(confirm=True, products=[self.product_order, self.service_order])
|
||||
invoice = self.init_invoice('in_invoice', products=[self.product_a])
|
||||
|
||||
invoice._find_and_set_purchase_orders(
|
||||
['other_reference'], invoice.partner_id.id, invoice.amount_total, prefer_purchase_line=False)
|
||||
['other_reference'], invoice.partner_id.id, invoice.amount_total, from_ocr=False)
|
||||
|
||||
self.assertTrue(invoice.id not in po.invoice_ids.ids)
|
||||
|
||||
def test_manual_matching(self):
|
||||
po = self.init_purchase(confirm=True, products=[self.product_order])
|
||||
bill = self.init_invoice('in_invoice', partner=self.partner_a, products=[self.product_order])
|
||||
|
||||
self.env['account.move.line'].flush_model() # necessary to get the bill lines
|
||||
match_lines = self.env['purchase.bill.line.match'].search([('partner_id', '=', self.partner_a.id)])
|
||||
|
||||
expected_ids = po.order_line.ids + [-lid for lid in bill.invoice_line_ids.ids]
|
||||
self.assertListEqual(match_lines.ids, expected_ids)
|
||||
|
||||
match_lines.action_match_lines()
|
||||
self.assertEqual(bill.invoice_line_ids.purchase_line_id, po.order_line)
|
||||
self.assertEqual(po.order_line.qty_invoiced, bill.invoice_line_ids.quantity)
|
||||
|
||||
def test_manual_matching_restrict_no_pol(self):
|
||||
""" raises when there's no POL found """
|
||||
with self.assertRaisesRegex(UserError, "must select at least one Purchase Order line"):
|
||||
match_lines = self.env['purchase.bill.line.match'].search([('partner_id', '=', self.partner_a.id)])
|
||||
match_lines.action_match_lines()
|
||||
|
||||
def test_manual_matching_allow_multi_bill(self):
|
||||
""" test matching with multiple bills """
|
||||
po = self.init_purchase(partner=self.partner_a, confirm=True, products=[
|
||||
self.product_order,
|
||||
self.product_order_other_price,
|
||||
self.product_order_var_name
|
||||
])
|
||||
po.order_line[0].product_qty = 2
|
||||
po.order_line[0].qty_received = 2
|
||||
po.order_line[1].qty_received = 1
|
||||
po.order_line[2].qty_received = 1
|
||||
|
||||
bill_1 = self.init_invoice(move_type='in_invoice', partner=self.partner_a, products=[self.product_order, self.product_order_other_price])
|
||||
bill_2 = self.init_invoice(move_type='in_invoice', partner=self.partner_a, products=[self.product_order, self.product_order_var_name])
|
||||
bill_2.invoice_line_ids[1].product_id = None
|
||||
|
||||
match_lines = self.env['purchase.bill.line.match'].search([('partner_id', '=', self.partner_a.id)])
|
||||
match_lines.action_match_lines() # Match by product and leave residual bill and po lines unmatched because multiple bills
|
||||
|
||||
self.assertEqual(po.order_line[0], bill_1.invoice_line_ids[0].purchase_line_id)
|
||||
self.assertEqual(po.order_line[0], bill_2.invoice_line_ids[0].purchase_line_id)
|
||||
self.assertEqual(po.order_line[1], bill_1.invoice_line_ids[1].purchase_line_id)
|
||||
self.assertFalse(bill_2.invoice_line_ids[1].purchase_line_id)
|
||||
self.assertFalse(self.env['account.move.line'].search([('purchase_line_id', '=', po.order_line[2].id)]))
|
||||
self.env['purchase.order.line'].flush_model()
|
||||
match_lines = self.env['purchase.bill.line.match'].search([('partner_id', '=', self.partner_a.id)])
|
||||
self.assertEqual(len(match_lines), 2)
|
||||
|
||||
match_lines.action_match_lines() # Can't match by product but delete residual bill line and create new bill line for residual po line as only one bill
|
||||
self.assertEqual(po.order_line[2], bill_2.invoice_line_ids[1].purchase_line_id)
|
||||
self.env['purchase.order.line'].flush_model()
|
||||
match_lines = self.env['purchase.bill.line.match'].search([('partner_id', '=', self.partner_a.id)])
|
||||
self.assertEqual(len(match_lines), 0)
|
||||
|
||||
def test_manual_matching_create_bill(self):
|
||||
""" Selecting POL without AML will create bill with the selected POL as the lines """
|
||||
prev_moves = self.env['account.move'].search([])
|
||||
self.init_purchase(confirm=True, products=[self.product_order, self.product_order_var_name])
|
||||
self.env['purchase.order.line'].flush_model()
|
||||
self.env['purchase.order'].flush_model()
|
||||
|
||||
match_lines = self.env['purchase.bill.line.match'].search([('partner_id', '=', self.partner_a.id)])
|
||||
match_lines.action_match_lines()
|
||||
|
||||
new_move = self.env['account.move'].search([]) - prev_moves
|
||||
self.assertEqual(new_move.partner_id, self.partner_a)
|
||||
self.assertRecordValues(new_move.invoice_line_ids, [
|
||||
{'product_id': self.product_order.id},
|
||||
{'product_id': self.product_order_var_name.id},
|
||||
])
|
||||
|
||||
def test_manual_matching_multi_po(self):
|
||||
""" All POL are matched/added into the bill, and all unmatched AML are discarded """
|
||||
po_1 = self.init_purchase(confirm=True, products=[self.product_order, self.product_order_var_name])
|
||||
po_2 = self.init_purchase(confirm=True, products=[self.service_deliver])
|
||||
po_3 = self.init_purchase(confirm=True, products=[self.service_order])
|
||||
bill = self.init_invoice(move_type='in_invoice', partner=self.partner_a,
|
||||
products=[self.product_order, self.product_order_other_price])
|
||||
|
||||
self.env['account.move.line'].flush_model()
|
||||
match_lines = self.env['purchase.bill.line.match'].search([('partner_id', '=', self.partner_a.id)])
|
||||
match_lines.action_match_lines()
|
||||
|
||||
self.env.flush_all()
|
||||
self.assertEqual(bill.invoice_line_ids.purchase_line_id, (po_1 + po_2 + po_3).order_line)
|
||||
self.assertRecordValues(bill.invoice_line_ids, [
|
||||
{'product_id': self.product_order.id},
|
||||
{'product_id': self.service_order.id},
|
||||
{'product_id': self.product_order_var_name.id},
|
||||
{'product_id': self.service_deliver.id},
|
||||
])
|
||||
|
||||
def test_add_bill_to_po(self):
|
||||
bill = self.init_invoice('in_invoice', partner=self.partner_a, products=[self.product_order_var_name, self.service_deliver], post=True)
|
||||
self.env['account.move.line'].flush_model()
|
||||
|
||||
match_lines = self.env['purchase.bill.line.match'].search([('partner_id', '=', self.partner_a.id)])
|
||||
|
||||
# Use wizard to create a new PO
|
||||
action = match_lines.action_add_to_po()
|
||||
wizard = self.env['bill.to.po.wizard'].with_context({**action['context'], 'active_ids': match_lines.ids}).create({})
|
||||
self.assertEqual(wizard.partner_id, self.partner_a)
|
||||
self.assertFalse(wizard.purchase_order_id)
|
||||
|
||||
action = wizard.action_add_to_po()
|
||||
po = self.env['purchase.order'].browse(action['res_id'])
|
||||
self.assertEqual(po.partner_id, self.partner_a)
|
||||
self.assertTrue(po.order_line.tax_ids)
|
||||
self.assertEqual(po.order_line.tax_ids, bill.invoice_line_ids.tax_ids)
|
||||
self.assertEqual(po.order_line.product_id, bill.invoice_line_ids.product_id)
|
||||
self.assertEqual(po.order_line.product_id, self.product_order_var_name + self.service_deliver)
|
||||
|
||||
bill_2 = self.init_invoice('in_invoice', partner=self.partner_a, products=[self.product_order_other_price], post=False)
|
||||
bill_2.invoice_line_ids.write({
|
||||
'discount': 2.0,
|
||||
'product_uom_id': self.env.ref('uom.product_uom_dozen').id,
|
||||
})
|
||||
bill_2.action_post()
|
||||
self.env['account.move.line'].flush_model()
|
||||
|
||||
match_lines = self.env['purchase.bill.line.match'].search([('partner_id', '=', self.partner_a.id)])
|
||||
|
||||
# Use wizard to add lines to existing PO
|
||||
match_lines.action_add_to_po()
|
||||
wizard = self.env['bill.to.po.wizard'].with_context({
|
||||
'default_purchase_order_id': po.id,
|
||||
'active_ids': match_lines.ids
|
||||
}).create({})
|
||||
|
||||
action = wizard.action_add_to_po()
|
||||
self.assertEqual(action['res_id'], po.id)
|
||||
self.assertEqual(len(po.order_line), 3)
|
||||
self.assertEqual(po.order_line[-1:].product_id, self.product_order_other_price)
|
||||
self.assertListEqual(po.order_line.mapped('price_total'), (bill + bill_2).invoice_line_ids.mapped('price_total'))
|
||||
|
||||
def test_onchange_partner_currency(self):
|
||||
"""
|
||||
Test that the currency of the Bill is correctly set when the partner is changed
|
||||
|
|
@ -774,7 +1141,7 @@ class TestInvoicePurchaseMatch(TestPurchaseToInvoiceCommon):
|
|||
self.assertEqual(bill.currency_id, self.env.ref('base.EUR'), "The currency of the Bill should be the one set on the Bill")
|
||||
self.assertEqual(bill.invoice_line_ids.currency_id, self.env.ref('base.EUR'), "The currency of the Bill lines should be the same as the currency of the Bill")
|
||||
|
||||
ctx['default_currency_id'] = self.currency_data['currency'].id
|
||||
ctx['default_currency_id'] = self.other_currency.id
|
||||
move_form_currency_in_context = Form(self.env['account.move'].with_context(ctx))
|
||||
move_form_currency_in_context.currency_id = self.env.ref('base.EUR')
|
||||
with move_form_currency_in_context.invoice_line_ids.new() as line_form:
|
||||
|
|
@ -785,65 +1152,8 @@ class TestInvoicePurchaseMatch(TestPurchaseToInvoiceCommon):
|
|||
move_form_currency_in_context.partner_id = vendor_a
|
||||
bill = move_form_currency_in_context.save()
|
||||
|
||||
self.assertEqual(bill.currency_id, self.currency_data['currency'], "The currency of the Bill should be the one of the context")
|
||||
self.assertEqual(bill.invoice_line_ids.currency_id, self.currency_data['currency'], "The currency of the Bill lines should be the same as the currency of the Bill")
|
||||
|
||||
def test_payment_reference_autocomplete_invoice(self):
|
||||
"""
|
||||
Test that the payment_reference field is not replaced when selected a purchase order
|
||||
We test the flow for 8 use cases:
|
||||
- Purchase order with partner ref:
|
||||
- Bill with ref:
|
||||
- Bill with payment_reference -> should not be replaced
|
||||
- Bill without payment_reference -> should be the po.partner_ref
|
||||
- Bill without ref:
|
||||
- Bill with payment_reference -> should not be replaced
|
||||
- Bill without payment_reference -> should be the po.partner_ref
|
||||
- Purchase order without partner ref:
|
||||
- Bill with ref
|
||||
- Bill with payment_reference -> should not be replaced
|
||||
- Bill without payment_reference -> should be the bill ref
|
||||
- Bill with ref
|
||||
- Bill with payment_reference -> should not be replaced
|
||||
- Bill without payment_reference -> should be empty
|
||||
"""
|
||||
purchase_order_w_ref, purchase_order_wo_ref = self.env['purchase.order'].with_context(tracking_disable=True).create([
|
||||
{
|
||||
'partner_id': self.partner_a.id,
|
||||
'partner_ref': partner_ref,
|
||||
'order_line': [
|
||||
Command.create({
|
||||
'product_id': self.product_order.id,
|
||||
'product_qty': 1.0,
|
||||
'price_unit': self.product_order.list_price,
|
||||
'taxes_id': False,
|
||||
}),
|
||||
]
|
||||
} for partner_ref in ('PO-001', False)
|
||||
])
|
||||
(purchase_order_w_ref + purchase_order_wo_ref).button_confirm()
|
||||
|
||||
expected_values_dict = {
|
||||
purchase_order_w_ref: {
|
||||
'w_bill_ref': {'w_payment_reference': '222', 'wo_payment_reference': purchase_order_w_ref.partner_ref},
|
||||
'wo_bill_ref': {'w_payment_reference': '222', 'wo_payment_reference': purchase_order_w_ref.partner_ref},
|
||||
},
|
||||
purchase_order_wo_ref: {
|
||||
'w_bill_ref': {'w_payment_reference': '222', 'wo_payment_reference': '111'},
|
||||
'wo_bill_ref': {'w_payment_reference': '222', 'wo_payment_reference': ''},
|
||||
}
|
||||
}
|
||||
|
||||
for purchase_order, purchase_expected_values in expected_values_dict.items():
|
||||
for w_bill_ref, expected_values in purchase_expected_values.items():
|
||||
for w_payment_reference, expected_value in expected_values.items():
|
||||
with self.subTest(po_partner_ref=purchase_order.partner_ref, w_bill_ref=w_bill_ref, w_payment_reference=w_payment_reference, expected_value=expected_value):
|
||||
move_form = Form(self.env['account.move'].with_context(default_move_type='in_invoice'))
|
||||
move_form.ref = '111' if w_bill_ref == 'w_bill_ref' else ''
|
||||
move_form.payment_reference = '222' if w_payment_reference == 'w_payment_reference' else ''
|
||||
move_form.purchase_vendor_bill_id = self.env['purchase.bill.union'].browse(-purchase_order.id).exists()
|
||||
payment_reference = move_form._values['payment_reference']
|
||||
self.assertEqual(payment_reference, expected_value, "The payment reference should be %s" % expected_value)
|
||||
self.assertEqual(bill.currency_id, self.other_currency, "The currency of the Bill should be the one of the context")
|
||||
self.assertEqual(bill.invoice_line_ids.currency_id, self.other_currency, "The currency of the Bill lines should be the same as the currency of the Bill")
|
||||
|
||||
def test_invoice_user_id_on_bill(self):
|
||||
"""
|
||||
|
|
@ -857,7 +1167,7 @@ class TestInvoicePurchaseMatch(TestPurchaseToInvoiceCommon):
|
|||
'name': 'Purchase user',
|
||||
'login': 'purchaseUser',
|
||||
'email': 'pu@odoo.com',
|
||||
'groups_id': [Command.set([group_purchase_user.id, group_employee.id, group_partner_manager.id])],
|
||||
'group_ids': [Command.set([group_purchase_user.id, group_employee.id, group_partner_manager.id])],
|
||||
})
|
||||
po1 = self.env['purchase.order'].with_context(tracking_disable=True).create({
|
||||
'partner_id': self.partner_a.id,
|
||||
|
|
@ -867,7 +1177,7 @@ class TestInvoicePurchaseMatch(TestPurchaseToInvoiceCommon):
|
|||
'product_id': self.product_order.id,
|
||||
'product_qty': 1.0,
|
||||
'price_unit': self.product_order.list_price,
|
||||
'taxes_id': False,
|
||||
'tax_ids': False,
|
||||
}),
|
||||
]
|
||||
})
|
||||
|
|
@ -884,3 +1194,85 @@ class TestInvoicePurchaseMatch(TestPurchaseToInvoiceCommon):
|
|||
move_form.purchase_vendor_bill_id = self.env['purchase.bill.union'].browse(-po2.id)
|
||||
invoice2 = move_form.save()
|
||||
self.assertFalse(invoice2.invoice_user_id)
|
||||
|
||||
def test_create_invoice_from_multiple_purchase_orders(self):
|
||||
""" Test that invoices can be created from purchase orders with different
|
||||
vendors without raising errors and with correct vendor mapping per invoice.
|
||||
"""
|
||||
purchase_orders = self.env['purchase.order'].with_context(tracking_disable=True).create([
|
||||
{
|
||||
'partner_id': self.partner_a.id,
|
||||
'order_line': [
|
||||
Command.create({
|
||||
'product_id': self.product_order.id,
|
||||
'product_qty': 1.0,
|
||||
'price_unit': self.product_order.list_price,
|
||||
'tax_ids': False,
|
||||
}),
|
||||
],
|
||||
},
|
||||
{
|
||||
'partner_id': self.partner_b.id,
|
||||
'order_line': [
|
||||
Command.create({
|
||||
'product_id': self.product_deliver.id,
|
||||
'product_qty': 2.0,
|
||||
'price_unit': self.product_deliver.list_price,
|
||||
'tax_ids': False,
|
||||
}),
|
||||
],
|
||||
},
|
||||
])
|
||||
purchase_orders.button_confirm()
|
||||
purchase_orders.action_create_invoice()
|
||||
|
||||
self.assertEqual(len(purchase_orders.invoice_ids), 2, "Each PO should generate one invoice")
|
||||
self.assertEqual(
|
||||
set(purchase_orders.invoice_ids.partner_id.ids),
|
||||
set(purchase_orders.partner_id.ids),
|
||||
"Each invoice should be linked to the correct vendor"
|
||||
)
|
||||
|
||||
def test_link_bill_origin_to_purchase_orders(self):
|
||||
"""
|
||||
Test if the corresponding purchase orders are linked if the bill when there is multiple origin purchase orders
|
||||
"""
|
||||
po = self.init_purchase(confirm=True, products=[self.product_order])
|
||||
po_2 = self.init_purchase(confirm=True, products=[self.service_order])
|
||||
|
||||
bill = self.init_invoice('in_invoice', partner=self.partner_a, products=[self.product_order, self.service_order])
|
||||
bill.invoice_origin = po.name + ', ' + po_2.name
|
||||
|
||||
bill._link_bill_origin_to_purchase_orders()
|
||||
|
||||
self.assertTrue(bill.id in po.invoice_ids.ids)
|
||||
self.assertTrue(bill.id in po_2.invoice_ids.ids)
|
||||
self.assertEqual(bill.amount_total, po.amount_total + po_2.amount_total)
|
||||
|
||||
def test_po_matching_credit_note(self):
|
||||
po = self.init_purchase(partner=self.partner_a, products=[self.product_deliver])
|
||||
pol = po.order_line
|
||||
pol.product_qty = 3
|
||||
po.button_confirm()
|
||||
|
||||
bill = self.init_invoice(move_type='in_invoice', partner=self.partner_a, products=[self.product_deliver])
|
||||
bill.invoice_line_ids.quantity = 3
|
||||
|
||||
match_lines = self.env['purchase.bill.line.match'].search([('partner_id', '=', self.partner_a.id)])
|
||||
match_lines.action_match_lines()
|
||||
|
||||
bill.action_post()
|
||||
pol.qty_received = 2
|
||||
|
||||
credit_note = self.init_invoice(move_type='in_refund', partner=self.partner_a, amounts=[0])
|
||||
|
||||
self.env['purchase.order.line'].flush_model()
|
||||
match_lines = self.env['purchase.bill.line.match'].search([('partner_id', '=', self.partner_a.id)])
|
||||
self.assertEqual(match_lines.pol_id, pol)
|
||||
self.assertEqual(match_lines.aml_id, credit_note.invoice_line_ids)
|
||||
|
||||
match_lines.action_match_lines()
|
||||
self.assertRecordValues(credit_note.invoice_line_ids, [{
|
||||
'quantity': 1,
|
||||
'product_id': pol.product_id.id,
|
||||
}])
|
||||
|
|
|
|||
|
|
@ -0,0 +1,23 @@
|
|||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from odoo.tests import HttpCase, tagged
|
||||
|
||||
|
||||
@tagged('-at_install', 'post_install')
|
||||
class TestPurchaseOrderProductCatalog(HttpCase):
|
||||
|
||||
def test_add_section_from_product_catalog_on_purchase_order_tour(self):
|
||||
vendor = self.env['res.partner'].create({'name': 'Test Vendor'})
|
||||
self.env['product.template'].create({
|
||||
'name': "Test Product",
|
||||
'seller_ids': [(0, 0, {
|
||||
'partner_id': vendor.id,
|
||||
'min_qty': 1.0,
|
||||
'price': 1.0,
|
||||
})],
|
||||
})
|
||||
self.start_tour(
|
||||
'/web#action=purchase.purchase_rfq',
|
||||
'test_add_section_from_product_catalog_on_purchase_order',
|
||||
login='admin',
|
||||
)
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
from odoo.addons.account.tests.common import AccountTestInvoicingCommon
|
||||
from odoo.fields import Command
|
||||
from odoo.tests import Form, tagged
|
||||
|
||||
from datetime import datetime, timedelta
|
||||
|
|
@ -9,30 +10,35 @@ from datetime import datetime, timedelta
|
|||
@tagged('post_install', '-at_install')
|
||||
class TestPurchaseOrderReport(AccountTestInvoicingCommon):
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
super().setUpClass()
|
||||
cls.other_currency = cls.setup_other_currency('EUR')
|
||||
|
||||
def test_00_purchase_order_report(self):
|
||||
uom_dozen = self.env.ref('uom.product_uom_dozen')
|
||||
|
||||
po = self.env['purchase.order'].create({
|
||||
'partner_id': self.partner_a.id,
|
||||
'currency_id': self.currency_data['currency'].id,
|
||||
'currency_id': self.other_currency.id,
|
||||
'order_line': [
|
||||
(0, 0, {
|
||||
'name': self.product_a.name,
|
||||
'product_id': self.product_a.id,
|
||||
'product_qty': 1.0,
|
||||
'product_uom': uom_dozen.id,
|
||||
'product_uom_id': uom_dozen.id,
|
||||
'price_unit': 100.0,
|
||||
'date_planned': datetime.today(),
|
||||
'taxes_id': False,
|
||||
'tax_ids': False,
|
||||
}),
|
||||
(0, 0, {
|
||||
'name': self.product_b.name,
|
||||
'product_id': self.product_b.id,
|
||||
'product_qty': 1.0,
|
||||
'product_uom': uom_dozen.id,
|
||||
'product_uom_id': uom_dozen.id,
|
||||
'price_unit': 200.0,
|
||||
'date_planned': datetime.today(),
|
||||
'taxes_id': False,
|
||||
'tax_ids': False,
|
||||
}),
|
||||
],
|
||||
})
|
||||
|
|
@ -44,11 +50,11 @@ class TestPurchaseOrderReport(AccountTestInvoicingCommon):
|
|||
# <field name="invoice_vendor_bill_id" position="after">
|
||||
# <field name="purchase_id" invisible="1"/>
|
||||
# <label for="purchase_vendor_bill_id" string="Auto-Complete" class="oe_edit_only"
|
||||
# attrs="{'invisible': ['|', ('state','!=','draft'), ('move_type', '!=', 'in_invoice')]}" />
|
||||
# invisible="state != 'draft' or move_type != 'in_invoice'" />
|
||||
# <field name="purchase_vendor_bill_id" nolabel="1"
|
||||
# attrs="{'invisible': ['|', ('state','!=','draft'), ('move_type', '!=', 'in_invoice')]}"
|
||||
# invisible="state != 'draft' or move_type != 'in_invoice'"
|
||||
# class="oe_edit_only"
|
||||
# domain="partner_id and [('company_id', '=', company_id), ('partner_id.commercial_partner_id', '=', commercial_partner_id)] or [('company_id', '=', company_id)]"
|
||||
# domain="('company_id', '=', company_id), ('partner_id.commercial_partner_id', '=', commercial_partner_id)] if partner_id else [('company_id', '=', company_id)]"
|
||||
# placeholder="Select a purchase order or an old bill"
|
||||
# context="{'show_total_amount': True}"
|
||||
# options="{'no_create': True, 'no_open': True}"/>
|
||||
|
|
@ -113,36 +119,36 @@ class TestPurchaseOrderReport(AccountTestInvoicingCommon):
|
|||
po.button_confirm()
|
||||
|
||||
po.flush_model()
|
||||
report = self.env['purchase.report'].read_group(
|
||||
report = self.env['purchase.report'].formatted_read_group(
|
||||
[('order_id', '=', po.id)],
|
||||
['order_id', 'delay', 'delay_pass'],
|
||||
['order_id'],
|
||||
['delay:avg', 'delay_pass:avg'],
|
||||
)
|
||||
self.assertEqual(round(report[0]['delay']), -10, msg="The PO has been confirmed 10 days in advance")
|
||||
self.assertEqual(round(report[0]['delay_pass']), 5, msg="There are 5 days between the order date and the planned date")
|
||||
self.assertEqual(round(report[0]['delay:avg']), -10, msg="The PO has been confirmed 10 days in advance")
|
||||
self.assertEqual(round(report[0]['delay_pass:avg']), 5, msg="There are 5 days between the order date and the planned date")
|
||||
|
||||
def test_02_po_report_note_section_filter(self):
|
||||
po = self.env['purchase.order'].create({
|
||||
'partner_id': self.partner_a.id,
|
||||
'currency_id': self.currency_data['currency'].id,
|
||||
'currency_id': self.other_currency.id,
|
||||
'order_line': [
|
||||
(0, 0, {
|
||||
'name': 'This is a note',
|
||||
'display_type': 'line_note',
|
||||
'product_id': False,
|
||||
'product_qty': 0.0,
|
||||
'product_uom': False,
|
||||
'product_uom_id': False,
|
||||
'price_unit': 0.0,
|
||||
'taxes_id': False,
|
||||
'tax_ids': False,
|
||||
}),
|
||||
(0, 0, {
|
||||
'name': 'This is a section',
|
||||
'display_type': 'line_section',
|
||||
'product_id': False,
|
||||
'product_qty': 0.0,
|
||||
'product_uom': False,
|
||||
'product_uom_id': False,
|
||||
'price_unit': 0.0,
|
||||
'taxes_id': False,
|
||||
'tax_ids': False,
|
||||
}),
|
||||
],
|
||||
})
|
||||
|
|
@ -157,7 +163,7 @@ class TestPurchaseOrderReport(AccountTestInvoicingCommon):
|
|||
"""
|
||||
po = self.env['purchase.order'].create({
|
||||
'partner_id': self.partner_a.id,
|
||||
'currency_id': self.currency_data['currency'].id,
|
||||
'currency_id': self.other_currency.id,
|
||||
'order_line': [
|
||||
(0, 0, {
|
||||
'product_id': self.product_a.id,
|
||||
|
|
@ -166,9 +172,11 @@ class TestPurchaseOrderReport(AccountTestInvoicingCommon):
|
|||
}),
|
||||
],
|
||||
})
|
||||
currency_eur_id = self.env.ref("base.EUR")
|
||||
currency_eur_id.active = True
|
||||
po_2 = self.env['purchase.order'].create({
|
||||
'partner_id': self.partner_a.id,
|
||||
'currency_id': self.env['res.currency'].search([('name', '=', 'EUR')], limit=1).id,
|
||||
'currency_id': currency_eur_id.id,
|
||||
'order_line': [
|
||||
(0, 0, {
|
||||
'product_id': self.product_a.id,
|
||||
|
|
@ -209,10 +217,62 @@ class TestPurchaseOrderReport(AccountTestInvoicingCommon):
|
|||
})
|
||||
po.button_confirm()
|
||||
po.flush_model()
|
||||
report = self.env['purchase.report'].read_group(
|
||||
report = self.env['purchase.report'].formatted_read_group(
|
||||
[('product_id', '=', self.product_a.id)],
|
||||
['qty_ordered', 'price_average:avg'],
|
||||
['product_id'],
|
||||
['qty_ordered:sum', 'price_average:avg'],
|
||||
)
|
||||
self.assertEqual(report[0]['qty_ordered'], 11)
|
||||
self.assertEqual(round(report[0]['price_average'], 2), 46.36)
|
||||
self.assertEqual(report[0]['qty_ordered:sum'], 11)
|
||||
self.assertEqual(round(report[0]['price_average:avg'], 2), 46.36)
|
||||
|
||||
def test_purchase_report_multi_uom(self):
|
||||
"""
|
||||
PO:
|
||||
- 2 Pairs of P1 @ 200
|
||||
- 1 Dozen of P2 @ 2400
|
||||
"""
|
||||
|
||||
uom_units = self.env.ref('uom.product_uom_unit')
|
||||
uom_dozens = self.env.ref('uom.product_uom_dozen')
|
||||
uom_pairs = self.env['uom.uom'].create({
|
||||
'name': 'Pairs',
|
||||
'relative_factor': 2,
|
||||
'relative_uom_id': uom_units.id,
|
||||
})
|
||||
|
||||
product_01, product_02 = self.env['product.product'].create([{
|
||||
'name': name,
|
||||
'type': 'consu',
|
||||
'volume': 10,
|
||||
'weight': 10,
|
||||
'standard_price': 200,
|
||||
'uom_id': uom_pairs.id,
|
||||
'purchase_method': 'purchase',
|
||||
} for name in ['SuperProduct 01', 'SuperProduct 02']])
|
||||
|
||||
po = self.env['purchase.order'].create([{
|
||||
'partner_id': self.partner_a.id,
|
||||
'order_line': [
|
||||
Command.create({
|
||||
'product_id': product_01.id,
|
||||
'product_qty': 2.0,
|
||||
'product_uom_id': uom_pairs.id,
|
||||
'price_unit': 200.0,
|
||||
}),
|
||||
Command.create({
|
||||
'product_id': product_02.id,
|
||||
'product_qty': 1.0,
|
||||
'product_uom_id': uom_dozens.id,
|
||||
'price_unit': 2400.0,
|
||||
}),
|
||||
],
|
||||
}])
|
||||
po.button_confirm()
|
||||
|
||||
self.env['uom.uom'].flush_model()
|
||||
self.env['purchase.order.line'].flush_model()
|
||||
report = self.env['purchase.report'].search([('product_id', 'in', [product_01.id, product_02.id])], order="product_id.id")
|
||||
self.assertRecordValues(report, [
|
||||
{'product_id': product_01.id, 'volume': 20.0, 'weight': 20.0, 'price_average': 200.0, 'qty_to_be_billed': 2.0},
|
||||
{'product_id': product_02.id, 'volume': 60.0, 'weight': 60.0, 'price_average': 400.0, 'qty_to_be_billed': 6.0},
|
||||
])
|
||||
|
|
|
|||
|
|
@ -0,0 +1,187 @@
|
|||
from odoo import Command, fields
|
||||
from odoo.addons.account.tests.common import AccountTestInvoicingCommon
|
||||
from odoo.tests import HttpCase, tagged
|
||||
|
||||
import json
|
||||
|
||||
|
||||
@tagged('-at_install', 'post_install')
|
||||
class TestPurchaseProductCatalog(AccountTestInvoicingCommon, HttpCase):
|
||||
|
||||
def test_catalog_price(self):
|
||||
"""
|
||||
Products having a SupplierInfo record in a foreign currency should have their price
|
||||
converted in the product catalog
|
||||
When it's the same currency, the price shouldn't be changed
|
||||
"""
|
||||
self.authenticate(self.env.user.login, self.env.user.login)
|
||||
company_currency = self.env.company.currency_id
|
||||
other_currency = self.setup_other_currency('HRK', rates=[(fields.Date.today(), 0.5)])
|
||||
|
||||
other_product_price = 100
|
||||
company_product_price = 150
|
||||
other_product_price_converted = other_product_price / 0.5
|
||||
|
||||
other_product = self.env['product.product'].create({
|
||||
'name': 'Other Product',
|
||||
'seller_ids': [
|
||||
Command.create({
|
||||
'partner_id': self.partner_a.id,
|
||||
'min_qty': 1,
|
||||
'price': other_product_price,
|
||||
'currency_id': other_currency.id,
|
||||
}),
|
||||
]
|
||||
})
|
||||
company_product = self.env['product.product'].create({
|
||||
'name': 'Company Product',
|
||||
'seller_ids': [
|
||||
Command.create({
|
||||
'partner_id': self.partner_a.id,
|
||||
'min_qty': 1,
|
||||
'price': company_product_price,
|
||||
'currency_id': company_currency.id,
|
||||
}),
|
||||
]
|
||||
})
|
||||
|
||||
purchase_order = self.env['purchase.order'].create({
|
||||
'partner_id': self.partner_a.id,
|
||||
'currency_id': company_currency.id,
|
||||
})
|
||||
self.assertNotEqual(other_product.seller_ids[0].currency_id.id, purchase_order.currency_id.id)
|
||||
|
||||
resp = self.url_open(
|
||||
url='/product/catalog/order_lines_info',
|
||||
data=json.dumps({
|
||||
'params': {
|
||||
'child_field': 'order_line',
|
||||
'order_id': purchase_order.id,
|
||||
'product_ids': other_product.ids + company_product.ids,
|
||||
'res_model': 'purchase.order'
|
||||
}
|
||||
}),
|
||||
headers={'Content-Type': 'application/json'},
|
||||
)
|
||||
self.assertEqual(resp.status_code, 200)
|
||||
catalog_price_other_cur = resp.json()['result'][str(other_product.id)]['price']
|
||||
self.assertEqual(catalog_price_other_cur, other_product_price_converted)
|
||||
catalog_price_company_cur = resp.json()['result'][str(company_product.id)]['price']
|
||||
self.assertEqual(catalog_price_company_cur, company_product_price)
|
||||
|
||||
# The prices are recalculated on product order line update
|
||||
resp = self.url_open(
|
||||
url='/product/catalog/update_order_line_info',
|
||||
data=json.dumps({
|
||||
'params': {
|
||||
'child_field': 'order_line',
|
||||
'order_id': purchase_order.id,
|
||||
'product_id': other_product.id,
|
||||
'quantity': 1,
|
||||
'res_model': 'purchase.order'
|
||||
}
|
||||
}),
|
||||
headers={'Content-Type': 'application/json'},
|
||||
)
|
||||
self.assertEqual(resp.status_code, 200)
|
||||
self.assertEqual(resp.json()['result'], other_product_price_converted)
|
||||
|
||||
resp = self.url_open(
|
||||
url='/product/catalog/update_order_line_info',
|
||||
data=json.dumps({
|
||||
'params': {
|
||||
'child_field': 'order_line',
|
||||
'order_id': purchase_order.id,
|
||||
'product_id': company_product.id,
|
||||
'quantity': 1,
|
||||
'res_model': 'purchase.order'
|
||||
}
|
||||
}),
|
||||
headers={'Content-Type': 'application/json'},
|
||||
)
|
||||
self.assertEqual(resp.status_code, 200)
|
||||
self.assertEqual(resp.json()['result'], company_product_price)
|
||||
|
||||
# === TOUR TESTS ===#
|
||||
def test_catalog_vendor_uom(self):
|
||||
"""Check the product's UoM matches the one set on the vendor line."""
|
||||
# Enable units of measure and create two partners using different UoM.
|
||||
self._enable_uom()
|
||||
uom_liter = self.env.ref('uom.product_uom_litre')
|
||||
vendor_by_liter, vendor_by_unit = self.env['res.partner'].create([
|
||||
{'name': 'Vendor A (l)'},
|
||||
{'name': 'Vendor B (unit)'},
|
||||
])
|
||||
# Create a product and configure some vendor's prices.
|
||||
self.env['product.template'].create({
|
||||
'name': "Crab Juice",
|
||||
'seller_ids': [
|
||||
Command.create({
|
||||
'partner_id': vendor_by_liter.id,
|
||||
'product_uom_id': uom_liter.id,
|
||||
'price': 2,
|
||||
'discount': 22.5
|
||||
}),
|
||||
Command.create({
|
||||
'partner_id': vendor_by_unit.id,
|
||||
'product_uom_id': self.uom_unit.id,
|
||||
'price': 2.5,
|
||||
}),
|
||||
Command.create({
|
||||
'partner_id': vendor_by_unit.id,
|
||||
'product_uom_id': self.uom_unit.id,
|
||||
'min_qty': 6,
|
||||
'price': 2.45,
|
||||
}),
|
||||
Command.create({
|
||||
'partner_id': vendor_by_unit.id,
|
||||
'product_uom_id': self.uom_unit.id,
|
||||
'min_qty': 12,
|
||||
'price': 2.45,
|
||||
'discount': 10.2,
|
||||
}),
|
||||
],
|
||||
})
|
||||
# Create two PO and rename them to find them easily in the tour.
|
||||
purchase_orders = self.env['purchase.order'].create([{
|
||||
'partner_id': vendor.id
|
||||
} for vendor in (vendor_by_liter, vendor_by_unit)])
|
||||
purchase_orders[0].name = "PO/TEST/00001"
|
||||
purchase_orders[1].name = "PO/TEST/00002"
|
||||
self.start_tour('/odoo/purchase', 'test_catalog_vendor_uom', login='accountman')
|
||||
|
||||
def test_seller_price_discounted_with_template(self):
|
||||
ProductAttribute = self.env['product.attribute']
|
||||
ProductAttributeValue = self.env['product.attribute.value']
|
||||
|
||||
# Product Attribute
|
||||
att_color = ProductAttribute.create({'name': 'Color', 'sequence': 1})
|
||||
|
||||
# Product Attribute color Value
|
||||
att_color_red = ProductAttributeValue.create({'name': 'red', 'attribute_id': att_color.id, 'sequence': 1})
|
||||
att_color_blue = ProductAttributeValue.create({'name': 'blue', 'attribute_id': att_color.id, 'sequence': 2})
|
||||
|
||||
product_template = self.env['product.template'].create({
|
||||
'name': 'Test Product Template',
|
||||
'uom_id': self.env.ref('uom.product_uom_unit').id,
|
||||
'standard_price': 200.0,
|
||||
'attribute_line_ids': [
|
||||
Command.create({
|
||||
'attribute_id': att_color.id,
|
||||
'value_ids': [Command.link(att_color_red.id), Command.link(att_color_blue.id)]
|
||||
}),
|
||||
]
|
||||
})
|
||||
|
||||
supplier_info = self.env['product.supplierinfo'].create({
|
||||
'partner_id': self.partner_a.id,
|
||||
'product_tmpl_id': product_template.id,
|
||||
'product_uom_id': self.env.ref('uom.product_uom_pack_6').id,
|
||||
'price': 100.0,
|
||||
})
|
||||
|
||||
purchase_order = self.env['purchase.order'].create({
|
||||
'partner_id': self.partner_a.id,
|
||||
})
|
||||
catalog_info = purchase_order._get_product_price_and_data(supplier_info.product_tmpl_id.product_variant_ids[0])
|
||||
self.assertEqual(catalog_info['price'], 100.0)
|
||||
|
|
@ -1,59 +0,0 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from odoo.addons.account.tests.test_invoice_tax_totals import TestTaxTotals
|
||||
from odoo.tests import tagged
|
||||
|
||||
|
||||
@tagged('post_install', '-at_install')
|
||||
class PurchaseTestTaxTotals(TestTaxTotals):
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls, chart_template_ref=None):
|
||||
super().setUpClass(chart_template_ref=chart_template_ref)
|
||||
|
||||
cls.po_product = cls.env['product.product'].create({
|
||||
'name': 'Odoo course',
|
||||
'type': 'service',
|
||||
})
|
||||
|
||||
def _create_document_for_tax_totals_test(self, lines_data):
|
||||
# Overridden in order to run the inherited tests with purchase.order's
|
||||
# tax_totals field instead of account.move's
|
||||
|
||||
lines_vals = [
|
||||
(0, 0, {
|
||||
'name': 'test',
|
||||
'product_id': self.po_product.id,
|
||||
'product_qty': 1,
|
||||
'product_uom': self.po_product.uom_po_id.id,
|
||||
'price_unit': amount,
|
||||
'taxes_id': [(6, 0, taxes.ids)],
|
||||
})
|
||||
for amount, taxes in lines_data]
|
||||
|
||||
return self.env['purchase.order'].create({
|
||||
'partner_id': self.partner_a.id,
|
||||
'order_line': lines_vals,
|
||||
})
|
||||
|
||||
def test_archived_tax_totals(self):
|
||||
tax_10 = self.env['account.tax'].create({
|
||||
'name': "tax_10",
|
||||
'amount_type': 'percent',
|
||||
'amount': 10.0,
|
||||
'tax_group_id': self.tax_group1.id,
|
||||
})
|
||||
|
||||
po = self._create_document_for_tax_totals_test([
|
||||
(100.0, tax_10),
|
||||
])
|
||||
po.button_confirm()
|
||||
po.order_line.qty_received = 1
|
||||
po.action_create_invoice()
|
||||
|
||||
invoice = po.invoice_ids
|
||||
invoice.invoice_date = '2020-01-01'
|
||||
invoice.action_post()
|
||||
|
||||
old_ammount = po.amount_total
|
||||
tax_10.active = False
|
||||
self.assertEqual(po.amount_total, old_ammount)
|
||||
Loading…
Add table
Add a link
Reference in a new issue