1
0
forked from Mapan/odoo17e
odoo17e-kedaikipas58/addons/l10n_ke_edi_oscu_stock/tests/test_live.py
2024-12-10 09:04:09 +07:00

480 lines
21 KiB
Python

# Part of Odoo. See LICENSE file for full copyright and licensing details.
import datetime
from odoo import fields, Command
from odoo.tests import tagged
from odoo.addons.l10n_ke_edi_oscu.tests.common import TestKeEdiCommon
class TestKeEdiStock(TestKeEdiCommon):
@classmethod
def setUpClass(cls, chart_template_ref='ke'):
super().setUpClass(chart_template_ref=chart_template_ref)
cls.partner_import = cls.env['res.partner'].create([{
'name': 'OPW Fluid Transfer Group EU B.V',
'street': 'Roggestraat 38',
'city': 'Nieuw-Vennep',
'zip': '2153 GC',
'country_id': cls.env.ref('base.nl').id,
'vat': 'NL800672835B01',
}])
# Set up products
cls.product_a.write({
'name': 'Zaxxon machine',
'type': 'product',
'taxes_id': [Command.set(cls.standard_rate_sales_tax.ids)],
'supplier_taxes_id': [Command.set(cls.standard_rate_purchase_tax.ids)],
'standard_price': 30,
'l10n_ke_product_type_code': '2',
'l10n_ke_origin_country_id': cls.env.ref('base.be').id,
'unspsc_code_id': cls.env['product.unspsc.code'].search([
('code', '=', '52161557'),
], limit=1).id,
'l10n_ke_packaging_unit_id': cls.env.ref('l10n_ke_edi_oscu.code_17_SK').id,
'l10n_ke_packaging_quantity': 5,
})
cls.product_b.write({
'name': 'Windowpane',
'type': 'product',
'taxes_id': [Command.set(cls.reduced_rate_sales_tax.ids)],
'supplier_taxes_id': [Command.set(cls.reduced_rate_purchase_tax.ids)],
'standard_price': 30,
'l10n_ke_product_type_code': '1',
'l10n_ke_origin_country_id': cls.env.ref('base.be').id,
'unspsc_code_id': cls.env['product.unspsc.code'].search([
('code', '=', '30171613'),
], limit=1).id,
'l10n_ke_packaging_unit_id': cls.env.ref('l10n_ke_edi_oscu.code_17_CR').id,
'l10n_ke_packaging_quantity': 1,
})
cls.product_import = cls.env['product.product'].create([{
'name': 'Bottom loading adaptor AL handle',
'type': 'product',
'taxes_id': [Command.set(cls.standard_rate_sales_tax.ids)],
'supplier_taxes_id': [Command.set(cls.standard_rate_purchase_tax.ids)],
'standard_price': 500,
'l10n_ke_product_type_code': '1',
'l10n_ke_origin_country_id': cls.env.ref('base.nl').id,
'unspsc_code_id': cls.env['product.unspsc.code'].search([
('code', '=', '25181700'),
], limit=1).id,
'l10n_ke_packaging_unit_id': cls.env.ref('l10n_ke_edi_oscu.code_17_CR').id,
'l10n_ke_packaging_quantity': 1,
}])
# Create initial quants
cls.customer_location = cls.env.ref('stock.stock_location_customers')
cls.supplier_location = cls.env.ref('stock.stock_location_suppliers')
cls.warehouse = cls.env['stock.warehouse'].search([('company_id', '=', cls.company_data['company'].id)], limit=1)
cls.stock_location = cls.warehouse.lot_stock_id
cls.env['stock.quant'].create({
'product_id': cls.product_a.id,
'location_id': cls.stock_location.id,
'quantity': 20.0,
})
cls.env['stock.quant'].create({
'product_id': cls.product_b.id,
'location_id': cls.stock_location.id,
'quantity': 20.0,
})
def _test_send_invoice_and_credit_note(self):
""" Send an invoice and a credit note.
We do this sequentially (first the invoice, its stock IO and stock master,
then the credit note, its stock IO and stock master).
"""
# Step 1: create invoice
invoice = self.init_invoice(
'out_invoice',
partner=self.partner_a,
invoice_date='2024-01-28',
products=[self.product_a, self.product_b]
)
invoice.invoice_line_ids[0].discount = 10
# Step 2: create sale order from invoice
action = invoice.action_l10n_ke_create_sale_order()
so = self.env['sale.order'].browse(action['res_id'])
so.action_confirm()
# Step 3: validate picking
picking = so.picking_ids
picking.button_validate()
# Step 4: send invoice
self.assertFalse(invoice.l10n_ke_validation_message)
invoice.action_post()
send_and_print = self.create_send_and_print(invoice, l10n_ke_checkbox_oscu=True)
with self.set_invoice_number(invoice), self.patch_cron_trigger() as mocked_trigger:
send_and_print.action_send_and_print()
self.assertTrue(invoice.l10n_ke_oscu_invoice_number)
self.assertTrue(invoice.l10n_ke_oscu_receipt_number)
self.assertTrue(invoice.l10n_ke_oscu_internal_data)
# Step 5: picking cron should get called.
mocked_trigger.assert_called()
# Step 6: create and validate return pickings
wizard_return = self.env['stock.return.picking'].with_context(active_id=picking.id, active_model='stock.picking').create({})
action = wizard_return.create_returns()
return_pickings = self.env['stock.picking'].browse(action['res_id'])
return_pickings.button_validate()
# Step 7: create credit note
credit_note = self.create_reversal(invoice)
self.assertFalse(credit_note.l10n_ke_validation_message)
credit_note.action_post()
# Step 8: send credit note
send_and_print = self.create_send_and_print(credit_note, l10n_ke_checkbox_oscu=True)
with self.set_invoice_number(credit_note), self.patch_cron_trigger() as mocked_trigger:
send_and_print.action_send_and_print()
self.assertTrue(credit_note.l10n_ke_oscu_invoice_number)
self.assertTrue(credit_note.l10n_ke_oscu_receipt_number)
self.assertTrue(credit_note.l10n_ke_oscu_internal_data)
# Step 9: picking cron should get called.
mocked_trigger.assert_called()
def _test_send_invoiced_stock_moves(self):
""" This test ensures that the Stock IO and Stock Master reflect the invoices that have been sent.
1) Create Sale Order & Invoice n.1, with 2 of each product, receive the products but don't send the invoice.
2) Create Sale Order & Invoice n.2, with 1 of each product, receive the products and send the invoice.
3) Stock IO and Stock Master should be sent with the quantities in Sale Order n.2.
4) Now send Invoice n.1.
5) Stock IO and Stock Master should be sent with the quantities in Sale Order n.1.
"""
# Step 1: create invoice 1 and sale order, and validate picking.
invoice_1 = self.init_invoice(
'out_invoice',
partner=self.partner_a,
invoice_date='2024-01-28',
products=[self.product_a, self.product_b],
)
invoice_1.invoice_line_ids.write({
'quantity': 2,
'discount': 10,
})
action = invoice_1.action_l10n_ke_create_sale_order()
so_1 = self.env['sale.order'].browse(action['res_id'])
so_1.action_confirm()
picking_1 = so_1.picking_ids
picking_1.button_validate()
self.assertFalse(invoice_1.l10n_ke_validation_message)
# Step 2: create invoice 2 and sale order, and validate picking.
invoice_2 = self.init_invoice(
'out_invoice',
partner=self.partner_a,
invoice_date='2024-01-28',
products=[self.product_a, self.product_b],
)
invoice_2.invoice_line_ids[0].discount = 10
action = invoice_2.action_l10n_ke_create_sale_order()
so_2 = self.env['sale.order'].browse(action['res_id'])
so_2.action_confirm()
picking_2 = so_2.picking_ids
picking_2.button_validate()
self.assertFalse(invoice_2.l10n_ke_validation_message)
# Step 3: Send invoice 2.
invoice_2.action_post()
send_and_print = self.create_send_and_print(invoice_2, l10n_ke_checkbox_oscu=True)
with self.set_invoice_number(invoice_2), self.patch_cron_trigger() as mocked_trigger:
send_and_print.action_send_and_print()
self.assertTrue(invoice_2.l10n_ke_oscu_invoice_number)
self.assertTrue(invoice_2.l10n_ke_oscu_receipt_number)
self.assertTrue(invoice_2.l10n_ke_oscu_internal_data)
# Step 4: Picking cron should get called for (and only for) the stock move related to invoice 2.
mocked_trigger.assert_called()
# Step 5: Send invoice 1.
invoice_1.action_post()
send_and_print = self.create_send_and_print(invoice_1, l10n_ke_checkbox_oscu=True)
with self.set_invoice_number(invoice_1), self.patch_cron_trigger() as mocked_trigger:
send_and_print.action_send_and_print()
self.assertTrue(invoice_1.l10n_ke_oscu_invoice_number)
self.assertTrue(invoice_1.l10n_ke_oscu_receipt_number)
self.assertTrue(invoice_1.l10n_ke_oscu_internal_data)
# Step 6: Picking cron should get called for (and only for) the stock move related to invoice 1.
mocked_trigger.assert_called()
def _test_get_vendor_bill(self):
# Step 1: Retrieve vendor bill
vendor_bill = self.env['account.move']._l10n_ke_oscu_fetch_purchases(self.company_data['company'])
expected_vendor_bill = {
'partner_id': self.partner_a.id,
'move_type': 'in_invoice',
'invoice_date': fields.Date.from_string('2023-12-12'),
}
expected_vendor_bill_lines = [
{
'name': 'Zaxxon machine',
'product_id': self.product_a.id,
'product_uom_id': self.env.ref('uom.product_uom_unit').id,
'quantity': 1,
'tax_ids': [self.standard_rate_purchase_tax.id],
'balance': 17499,
}, {
'name': 'window pane',
'product_id': self.product_b.id,
# In this case, the UoM in the JSON is unrecognized, so we take the product's default UoM.
# In general, that should be a good guess. However, because in this test we deliberately configured product_b
# to use dozens (in order to test conversions in other tests) it gives this nonsensical '12 dozens' result here.
'product_uom_id': self.env.ref('uom.product_uom_dozen').id,
'quantity': 12,
'tax_ids': [self.reduced_rate_purchase_tax.id],
'balance': 54000,
}, {
'name': '16%',
'product_id': None,
'product_uom_id': False,
'quantity': 0,
'tax_ids': [],
'balance': 2799.84,
}, {
'name': '8%',
'product_id': None,
'product_uom_id': False,
'quantity': 0,
'tax_ids': [],
'balance': 4320.00,
}, {
'name': '',
'product_id': None,
'product_uom_id': False,
'quantity': 0,
'tax_ids': [],
'balance': -78618.84,
}
]
self.assertInvoiceValues(vendor_bill, expected_vendor_bill_lines, expected_vendor_bill)
# Manually adjust the quantity and UoM of the 'Window Pane' line to 12 units.
vendor_bill.invoice_line_ids.filtered(lambda l: l.product_id == self.product_b).write({
'product_uom_id': self.env.ref('uom.product_uom_unit').id,
'quantity': 12,
})
return vendor_bill
def _test_confirm_vendor_bill(self, vendor_bill):
# Step 2: create purchase order from vendor bill
action = vendor_bill.action_l10n_ke_create_purchase_order()
po = self.env['purchase.order'].browse(action['res_id'])
po.button_confirm()
# Step 3: validate picking
po.picking_ids.button_validate()
# Step 4: send vendor bill confirmation
vendor_bill.l10n_ke_payment_method_id = self.env.ref('l10n_ke_edi_oscu.code_07_05')
self.assertFalse(vendor_bill.l10n_ke_validation_message)
vendor_bill.action_post()
with self.patch_cron_trigger() as mocked_trigger:
vendor_bill.action_l10n_ke_oscu_confirm_vendor_bill()
# Step 5: picking cron should get called
mocked_trigger.assert_called()
def _test_get_custom_import(self):
# Step 1: Retrieve custom import
self.env['l10n_ke_edi.customs.import'].sudo()._receive_customs_import(self.company_data['company'])
custom_import = self.env['l10n_ke_edi.customs.import'].search([('company_id', '=', self.company_data['company'].id)])
expected_import_values = [{
'declaration_date': datetime.date(2023, 2, 1),
'declaration_number': '23NBOIM401172243',
'task_code': '20230208667984',
'item_seq': 1,
'supplier_name': 'OPW FLUID TRANSFER GROUP EUROPE B.V',
'item_name': 'TANKER TRAILER PARTS & ACCESSORIES API BOTTOM LOADING ADAPTOR AL HANDLE',
'number_packages': 17,
'package_unit_code_id': self.env.ref('l10n_ke_edi_oscu.code_17_CR').id,
'quantity': 2,
'uom_code_id': self.env.ref('l10n_ke_edi_oscu.code_10_U').id,
'hs_code': '87169000',
'origin_country_id': self.env.ref('base.nl').id,
'export_country_id': self.env.ref('base.nl').id,
}]
self.assertRecordValues(custom_import, expected_import_values)
return custom_import
def _test_confirm_custom_import(self, custom_import):
# Step 2: Add partner and product on custom import
custom_import.write({
'product_id': self.product_import.id,
'partner_id': self.partner_import.id,
})
self.assertRecordValues(custom_import, [{'warning_msg': False}])
# Step 3: create purchase order from custom import
action = custom_import.action_create_purchase_order()
po = self.env['purchase.order'].browse(action['res_id'])
po.button_confirm()
# Step 4: validate picking
po.picking_ids.button_validate()
# Step 5: match and approve custom import
custom_import.button_approve()
# Step 6: create vendor bill and send confirmation
po.action_create_invoice()
vendor_bill = po.invoice_ids
vendor_bill.write({
'invoice_date': fields.Date.today(),
'l10n_ke_payment_method_id': self.env.ref('l10n_ke_edi_oscu.code_07_05'),
})
self.assertFalse(vendor_bill.l10n_ke_validation_message)
vendor_bill.action_post()
with self.patch_cron_trigger() as mocked_trigger:
vendor_bill.action_l10n_ke_oscu_confirm_vendor_bill()
# Step 7: picking cron should get called
mocked_trigger.assert_called()
def _test_send_picking_between_branches(self):
# Step 1: Create Kakamega branch
self._test_create_branches()
branch = self.env['res.company'].search([('parent_id', '=', self.company_data['company'].id), ('name', '=like', 'KAKAMEGA%')])
branch.write({
'l10n_ke_oscu_cmc_key': self.branch_cmc_key,
'l10n_ke_oscu_user_agreement': True,
})
# Step 2: Create transfer from HQ to Kakamega
parent_delivery_type = self.env['stock.picking.type'].search([('company_id', '=', self.company_data['company'].id), ('code', '=', 'outgoing')], limit=1)
out_picking = self.env['stock.picking'].create({
'location_id': self.stock_location.id,
'location_dest_id': self.customer_location.id,
'partner_id': branch.partner_id.id,
'picking_type_id': parent_delivery_type.id,
'move_ids': [
Command.create({
'name': self.product_a.name,
'location_id': self.stock_location.id,
'location_dest_id': self.customer_location.id,
'product_id': self.product_a.id,
'product_uom_qty': 1,
'product_uom': self.product_a.uom_id.id,
'description_picking': self.product_a.name,
})
]
})
out_picking.button_validate()
# Step 3: Run picking cron as superuser
self.env.ref('l10n_ke_edi_oscu_stock.ir_cron_send_stock_moves').method_direct_trigger()
# Step 4: Create receipt in Kakamega
branch_receipt_type = self.env['stock.picking.type'].search([('company_id', '=', branch.id), ('code', '=', 'incoming')], limit=1)
branch_stock_location = self.env['stock.warehouse'].search([('company_id', '=', branch.id)], limit=1).lot_stock_id
in_picking = self.env['stock.picking'].with_company(branch).create({
'location_id': branch_stock_location.id,
'location_dest_id': self.supplier_location.id,
'partner_id': self.company_data['company'].partner_id.id,
'picking_type_id': branch_receipt_type.id,
'move_ids': [
Command.create({
'name': self.product_a.name,
'location_id': self.supplier_location.id,
'location_dest_id': branch_stock_location.id,
'product_id': self.product_a.id,
'product_uom_qty': 1,
'product_uom': self.product_a.uom_id.id,
'description_picking': self.product_a.name,
})
]
})
in_picking.button_validate()
# Step 5: Run picking cron as superuser
self.env.ref('l10n_ke_edi_oscu_stock.ir_cron_send_stock_moves').method_direct_trigger()
def _test_send_inventory_adjustment(self):
self.user.write({'groups_id': [Command.link(self.env.ref('stock.group_stock_user').id)]})
self.product_a.action_l10n_ke_oscu_save_item()
# Step 1: Create inventory adjustment
with self.patch_cron_trigger() as mocked_trigger:
self.env['stock.quant'].with_context(inventory_mode=True).create({
'product_id': self.product_a.id,
'location_id': self.stock_location.id,
'inventory_quantity_auto_apply': 21.0,
})
# Step 2: Check values of the created stock move
stock_move = self.env['stock.move'].search([
('company_id', '=', self.env.company.id),
('is_inventory', '=', True),
])
inventory_adjustment_location = self.env['ir.property']._get('property_stock_inventory', 'product.template')
expected_stock_move_vals = [{
'product_id': self.product_a.id,
'product_uom': self.product_a.uom_id.id,
'product_uom_qty': 1.0,
'location_id': inventory_adjustment_location.id,
'location_dest_id': self.stock_location.id,
}]
expected_stock_move_line_vals = [{
'product_id': self.product_a.id,
'product_uom_id': self.product_a.uom_id.id,
'quantity': 1.0,
'location_id': inventory_adjustment_location.id,
'location_dest_id': self.stock_location.id,
}]
self.assertRecordValues(stock_move, expected_stock_move_vals)
self.assertRecordValues(stock_move.move_line_ids, expected_stock_move_line_vals)
# Step 3: Check that the cron was called.
mocked_trigger.assert_called()
@tagged('external', 'external_l10n', 'post_install', '-post_install_l10n', '-at_install', '-standard')
class TestKeEdiStockLive(TestKeEdiStock):
@classmethod
def setUpClass(cls, chart_template_ref='ke'):
super().setUpClass(chart_template_ref=chart_template_ref)
cls.is_live_test = True
def test_send_invoice_and_credit_note(self):
self._test_send_invoice_and_credit_note()
def test_send_invoiced_stock_moves(self):
self._test_send_invoiced_stock_moves()
def test_confirm_vendor_bill(self):
# This is mocked because there are no purchases on the test server to retrieve.
with self.patch_session([
('selectTrnsPurchaseSalesList', 'get_purchases', 'get_purchases_2'),
]):
vendor_bill = self._test_get_vendor_bill()
self._test_confirm_vendor_bill(vendor_bill)
def test_confirm_custom_import(self):
# This is mocked because there are no custom imports on the test server to retrieve.
with self.patch_session([
('selectImportItemList', 'get_imports', 'get_imports_1'),
]):
custom_import = self._test_get_custom_import()
self._test_confirm_custom_import(custom_import)
def test_send_picking_between_branches(self):
self._test_send_picking_between_branches()
def test_send_inventory_adjustment(self):
self._test_send_inventory_adjustment()