123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387 |
- # -*- coding: utf-8 -*-
- # Part of Odoo. See LICENSE file for full copyright and licensing details.
- from datetime import datetime, timedelta, time
- from unittest.mock import patch
- from odoo import fields
- from .common import PurchaseTestCommon
- from odoo.tests.common import Form
- class TestPurchaseLeadTime(PurchaseTestCommon):
- def test_00_product_company_level_delays(self):
- """ To check dates, set product's Delivery Lead Time
- and company's Purchase Lead Time."""
- company = self.env.ref('base.main_company')
- # Update company with Purchase Lead Time
- company.write({'po_lead': 3.00})
- # Make procurement request from product_1's form view, create procurement and check it's state
- date_planned = fields.datetime.now() + timedelta(days=10)
- self._create_make_procurement(self.product_1, 15.00, date_planned=date_planned)
- purchase = self.env['purchase.order.line'].search([('product_id', '=', self.product_1.id)], limit=1).order_id
- # Confirm purchase order
- purchase.button_confirm()
- # Check order date of purchase order
- order_date = fields.Datetime.from_string(date_planned) - timedelta(days=self.product_1.seller_ids.delay)
- self.assertEqual(purchase.date_order, order_date, 'Order date should be equal to: Date of the procurement order - Purchase Lead Time - Delivery Lead Time.')
- # Check scheduled date of purchase order
- schedule_date = order_date + timedelta(days=self.product_1.seller_ids.delay)
- self.assertEqual(purchase.order_line.date_planned, schedule_date, 'Schedule date should be equal to: Order date of Purchase order + Delivery Lead Time.')
- # check the picking created or not
- self.assertTrue(purchase.picking_ids, "Picking should be created.")
- # Check scheduled and deadline date of In Type shipment
- self.assertEqual(purchase.picking_ids.scheduled_date, schedule_date, 'Schedule date of In type shipment should be equal to: schedule date of purchase order.')
- self.assertEqual(purchase.picking_ids.date_deadline, schedule_date, 'Deadline date of should be equal to: schedule date of purchase order.')
- def test_01_product_level_delay(self):
- """ To check schedule dates of multiple purchase order line of the same purchase order,
- we create two procurements for the two different product with same vendor
- and different Delivery Lead Time."""
- company = self.env.ref('base.main_company')
- company.write({'po_lead': 0.00})
- # Make procurement request from product_1's form view, create procurement and check it's state
- date_planned1 = fields.datetime.now() + timedelta(days=10)
- self._create_make_procurement(self.product_1, 10.00, date_planned=date_planned1)
- purchase1 = self.env['purchase.order.line'].search([('product_id', '=', self.product_1.id)], limit=1).order_id
- # Make procurement request from product_2's form view, create procurement and check it's state
- date_planned2 = fields.datetime.now() + timedelta(days=10)
- self._create_make_procurement(self.product_2, 5.00, date_planned=date_planned2)
- purchase2 = self.env['purchase.order.line'].search([('product_id', '=', self.product_2.id)], limit=1).order_id
- # Check purchase order is same or not
- self.assertEqual(purchase1, purchase2, 'Purchase orders should be same for the two different product with same vendor.')
- # Confirm purchase order
- purchase1.button_confirm()
- # Check order date of purchase order
- order_line_pro_1 = purchase2.order_line.filtered(lambda r: r.product_id == self.product_1)
- order_line_pro_2 = purchase2.order_line.filtered(lambda r: r.product_id == self.product_2)
- order_date = date_planned1 - timedelta(days=self.product_1.seller_ids.delay)
- self.assertEqual(purchase2.date_order, order_date, 'Order date should be equal to: Date of the procurement order - Delivery Lead Time.')
- # Check scheduled date of purchase order line for product_1
- self.assertEqual(order_line_pro_1.date_planned, date_planned1, 'Schedule date of purchase order line for product_1 should be equal to: Order date of purchase order + Delivery Lead Time of product_1.')
- # Check scheduled date of purchase order line for product_2
- self.assertEqual(order_line_pro_2.date_planned, date_planned2, 'Schedule date of purchase order line for product_2 should be equal to: Order date of purchase order + Delivery Lead Time of product_2.')
- # Check the picking created or not
- self.assertTrue(purchase2.picking_ids, "Picking should be created.")
- # Check scheduled date of In Type shipment
- picking_schedule_date = min(date_planned1, date_planned2)
- self.assertEqual(purchase2.picking_ids.scheduled_date, picking_schedule_date,
- 'Schedule date of In type shipment should be same as schedule date of purchase order.')
- # Check deadline of pickings
- self.assertEqual(fields.Date.to_date(purchase2.picking_ids.date_deadline), fields.Date.to_date(purchase1.date_planned), "Deadline of pickings should be equals to the receipt date of purchase")
- purchase_form = Form(purchase2)
- purchase_form.date_planned = purchase2.date_planned + timedelta(days=2)
- purchase_form.save()
- self.assertEqual(purchase2.picking_ids.date_deadline, purchase2.date_planned, "Deadline of pickings should be propagate")
- def test_02_product_route_level_delays(self):
- """ In order to check dates, set product's Delivery Lead Time
- and warehouse route's delay."""
- company = self.env.ref('base.main_company')
- company.write({'po_lead': 1.00})
- # Update warehouse_1 with Incoming Shipments 3 steps
- self.warehouse_1.write({'reception_steps': 'three_steps'})
- # Set delay on push rule
- for push_rule in self.warehouse_1.reception_route_id.rule_ids:
- push_rule.write({'delay': 2})
- rule_delay = sum(self.warehouse_1.reception_route_id.rule_ids.mapped('delay'))
- date_planned = fields.Datetime.to_string(fields.datetime.now() + timedelta(days=10))
- # Create procurement order of product_1
- self.env['procurement.group'].run([self.env['procurement.group'].Procurement(
- self.product_1, 5.000, self.uom_unit, self.warehouse_1.lot_stock_id, 'Test scheduler for RFQ', '/', self.env.company,
- {
- 'warehouse_id': self.warehouse_1,
- 'date_planned': date_planned, # 10 days added to current date of procurement to get future schedule date and order date of purchase order.
- 'date_deadline': date_planned, # 10 days added to current date of procurement to get future schedule date and order date of purchase order.
- 'rule_id': self.warehouse_1.buy_pull_id,
- 'group_id': False,
- 'route_ids': [],
- }
- )])
- # Confirm purchase order
- purchase = self.env['purchase.order.line'].search([('product_id', '=', self.product_1.id)], limit=1).order_id
- purchase.button_confirm()
- # Check order date of purchase order
- order_date = fields.Datetime.from_string(date_planned) - timedelta(days=self.product_1.seller_ids.delay + rule_delay)
- self.assertEqual(purchase.date_order, order_date, 'Order date should be equal to: Date of the procurement order - Delivery Lead Time(supplier and pull rules).')
- # Check scheduled date of purchase order
- schedule_date = order_date + timedelta(days=self.product_1.seller_ids.delay + rule_delay)
- self.assertEqual(date_planned, str(schedule_date), 'Schedule date should be equal to: Order date of Purchase order + Delivery Lead Time(supplier and pull rules).')
- # Check the picking crated or not
- self.assertTrue(purchase.picking_ids, "Picking should be created.")
- # Check scheduled date of Internal Type shipment
- incoming_shipment1 = self.env['stock.picking'].search([('move_ids.product_id', 'in', (self.product_1.id, self.product_2.id)), ('picking_type_id', '=', self.warehouse_1.int_type_id.id), ('location_id', '=', self.warehouse_1.wh_input_stock_loc_id.id), ('location_dest_id', '=', self.warehouse_1.wh_qc_stock_loc_id.id)])
- incoming_shipment1_date = order_date + timedelta(days=self.product_1.seller_ids.delay)
- self.assertEqual(incoming_shipment1.scheduled_date, incoming_shipment1_date, 'Schedule date of Internal Type shipment for input stock location should be equal to: schedule date of purchase order + push rule delay.')
- self.assertEqual(incoming_shipment1.date_deadline, incoming_shipment1_date)
- old_deadline1 = incoming_shipment1.date_deadline
- incoming_shipment2 = self.env['stock.picking'].search([('picking_type_id', '=', self.warehouse_1.int_type_id.id), ('location_id', '=', self.warehouse_1.wh_qc_stock_loc_id.id), ('location_dest_id', '=', self.warehouse_1.lot_stock_id.id)])
- incoming_shipment2_date = schedule_date - timedelta(days=incoming_shipment2.move_ids[0].rule_id.delay)
- self.assertEqual(incoming_shipment2.scheduled_date, incoming_shipment2_date, 'Schedule date of Internal Type shipment for quality control stock location should be equal to: schedule date of Internal type shipment for input stock location + push rule delay..')
- self.assertEqual(incoming_shipment2.date_deadline, incoming_shipment2_date)
- old_deadline2 = incoming_shipment2.date_deadline
- # Modify the date_planned of the purchase -> propagate the deadline
- purchase_form = Form(purchase)
- purchase_form.date_planned = purchase.date_planned + timedelta(days=1)
- purchase_form.save()
- self.assertEqual(incoming_shipment2.date_deadline, old_deadline2 + timedelta(days=1), 'Deadline should be propagate')
- self.assertEqual(incoming_shipment1.date_deadline, old_deadline1 + timedelta(days=1), 'Deadline should be propagate')
- def test_merge_po_line(self):
- """Change that merging po line for same procurement is done."""
- # create a product with manufacture route
- product_1 = self.env['product.product'].create({
- 'name': 'AAA',
- 'route_ids': [(4, self.route_buy)],
- 'seller_ids': [(0, 0, {'partner_id': self.partner_1.id, 'delay': 5})]
- })
- # create a move for product_1 from stock to output and reserve to trigger the
- # rule
- move_1 = self.env['stock.move'].create({
- 'name': 'move_1',
- 'product_id': product_1.id,
- 'product_uom': self.ref('uom.product_uom_unit'),
- 'location_id': self.ref('stock.stock_location_stock'),
- 'location_dest_id': self.ref('stock.stock_location_output'),
- 'product_uom_qty': 10,
- 'procure_method': 'make_to_order'
- })
- move_1._action_confirm()
- po_line = self.env['purchase.order.line'].search([
- ('product_id', '=', product_1.id),
- ])
- self.assertEqual(len(po_line), 1, 'the purchase order line is not created')
- self.assertEqual(po_line.product_qty, 10, 'the purchase order line has a wrong quantity')
- move_2 = self.env['stock.move'].create({
- 'name': 'move_2',
- 'product_id': product_1.id,
- 'product_uom': self.ref('uom.product_uom_unit'),
- 'location_id': self.ref('stock.stock_location_stock'),
- 'location_dest_id': self.ref('stock.stock_location_output'),
- 'product_uom_qty': 5,
- 'procure_method': 'make_to_order'
- })
- move_2._action_confirm()
- po_line = self.env['purchase.order.line'].search([
- ('product_id', '=', product_1.id),
- ])
- self.assertEqual(len(po_line), 1, 'the purchase order lines should be merged')
- self.assertEqual(po_line.product_qty, 15, 'the purchase order line has a wrong quantity')
- def test_merge_po_line_3(self):
- """Change merging po line if same procurement is done depending on custom values."""
- company = self.env.ref('base.main_company')
- company.write({'po_lead': 0.00})
- # The seller has a specific product name and code which must be kept in the PO line
- self.t_shirt.seller_ids.write({
- 'product_name': 'Vendor Name',
- 'product_code': 'Vendor Code',
- })
- partner = self.t_shirt.seller_ids[:1].partner_id
- t_shirt = self.t_shirt.with_context(
- lang=partner.lang,
- partner_id=partner.id,
- )
- # Create procurement order of product_1
- ProcurementGroup = self.env['procurement.group']
- procurement_values = {
- 'warehouse_id': self.warehouse_1,
- 'rule_id': self.warehouse_1.buy_pull_id,
- 'date_planned': fields.datetime.now() + timedelta(days=10),
- 'group_id': False,
- 'route_ids': [],
- }
- procurement_values['product_description_variants'] = 'Color (Red)'
- order_1_values = procurement_values
- ProcurementGroup.run([self.env['procurement.group'].Procurement(
- self.t_shirt, 5, self.uom_unit, self.warehouse_1.lot_stock_id,
- self.t_shirt.name, '/', self.env.company, order_1_values)
- ])
- purchase_order = self.env['purchase.order.line'].search([('product_id', '=', self.t_shirt.id)], limit=1).order_id
- order_line_description = purchase_order.order_line.product_id.description_pickingin or ''
- self.assertEqual(len(purchase_order.order_line), 1, 'wrong number of order line is created')
- self.assertEqual(purchase_order.order_line.name, t_shirt.display_name + "\n" + "Color (Red)", 'wrong description in po lines')
- procurement_values['product_description_variants'] = 'Color (Red)'
- order_2_values = procurement_values
- ProcurementGroup.run([self.env['procurement.group'].Procurement(
- self.t_shirt, 10, self.uom_unit, self.warehouse_1.lot_stock_id,
- self.t_shirt.name, '/', self.env.company, order_2_values)
- ])
- self.env['procurement.group'].run_scheduler()
- self.assertEqual(len(purchase_order.order_line), 1, 'line with same custom value should be merged')
- self.assertEqual(purchase_order.order_line[0].product_qty, 15, 'line with same custom value should be merged and qty should be update')
- procurement_values['product_description_variants'] = 'Color (Green)'
- order_3_values = procurement_values
- ProcurementGroup.run([self.env['procurement.group'].Procurement(
- self.t_shirt, 10, self.uom_unit, self.warehouse_1.lot_stock_id,
- self.t_shirt.name, '/', self.env.company, order_3_values)
- ])
- self.assertEqual(len(purchase_order.order_line), 2, 'line with different custom value should not be merged')
- self.assertEqual(purchase_order.order_line.filtered(lambda x: x.product_qty == 15).name, t_shirt.display_name + "\n" + "Color (Red)", 'wrong description in po lines')
- self.assertEqual(purchase_order.order_line.filtered(lambda x: x.product_qty == 10).name, t_shirt.display_name + "\n" + "Color (Green)", 'wrong description in po lines')
- purchase_order.button_confirm()
- self.assertEqual(purchase_order.picking_ids[0].move_ids_without_package.filtered(lambda x: x.product_uom_qty == 15).description_picking, t_shirt.display_name + "\n" + order_line_description + "Color (Red)", 'wrong description in picking')
- self.assertEqual(purchase_order.picking_ids[0].move_ids_without_package.filtered(lambda x: x.product_uom_qty == 10).description_picking, t_shirt.display_name + "\n" + order_line_description + "Color (Green)", 'wrong description in picking')
- def test_reordering_days_to_purchase(self):
- company = self.env.ref('base.main_company')
- company2 = self.env['res.company'].create({
- 'name': 'Second Company',
- })
- company.write({'po_lead': 0.00})
- self.patcher = patch('odoo.addons.stock.models.stock_orderpoint.fields.Date', wraps=fields.Date)
- self.mock_date = self.startPatcher(self.patcher)
- vendor = self.env['res.partner'].create({
- 'name': 'Colruyt'
- })
- vendor2 = self.env['res.partner'].create({
- 'name': 'Delhaize'
- })
- self.env.company.days_to_purchase = 2.0
- # Test if the orderpoint is created when opening the replenishment view
- prod = self.env['product.product'].create({
- 'name': 'Carrot',
- 'type': 'product',
- 'seller_ids': [
- (0, 0, {'partner_id': vendor.id, 'delay': 1.0, 'company_id': company.id})
- ]
- })
- warehouse = self.env['stock.warehouse'].search([], limit=1)
- self.env['stock.move'].create({
- 'name': 'Delivery',
- 'date': datetime.today() + timedelta(days=3),
- 'product_id': prod.id,
- 'product_uom': prod.uom_id.id,
- 'product_uom_qty': 5.0,
- 'location_id': warehouse.lot_stock_id.id,
- 'location_dest_id': self.ref('stock.stock_location_customers'),
- })._action_confirm()
- self.env['stock.warehouse.orderpoint'].action_open_orderpoints()
- replenishment = self.env['stock.warehouse.orderpoint'].search([
- ('product_id', '=', prod.id),
- ])
- self.assertEqual(len(replenishment), 1)
- # Test if purchase orders are created according to the days to purchase
- product = self.env['product.product'].create({
- 'name': 'Chicory',
- 'type': 'product',
- 'seller_ids': [
- (0, 0, {'partner_id': vendor2.id, 'delay': 15.0, 'company_id': company2.id}),
- (0, 0, {'partner_id': vendor.id, 'delay': 1.0, 'company_id': company.id})
- ]
- })
- orderpoint_form = Form(self.env['stock.warehouse.orderpoint'])
- orderpoint_form.product_id = product
- orderpoint_form.product_min_qty = 0.0
- orderpoint_form.visibility_days = 1.0
- orderpoint = orderpoint_form.save()
- orderpoint_form = Form(self.env['stock.warehouse.orderpoint'].with_company(company2))
- orderpoint_form.product_id = product
- orderpoint_form.product_min_qty = 0.0
- orderpoint = orderpoint_form.save()
- delivery_moves = self.env['stock.move']
- for i in range(0, 6):
- delivery_moves |= self.env['stock.move'].create({
- 'name': 'Delivery',
- 'date': datetime.today() + timedelta(days=i),
- 'product_id': product.id,
- 'product_uom': product.uom_id.id,
- 'product_uom_qty': 5.0,
- 'location_id': warehouse.lot_stock_id.id,
- 'location_dest_id': self.ref('stock.stock_location_customers'),
- })
- delivery_moves._action_confirm()
- self.env['procurement.group'].run_scheduler()
- po_line = self.env['purchase.order.line'].search([('product_id', '=', product.id)])
- expected_date_order = fields.Date.today() + timedelta(days=2)
- self.assertEqual(fields.Date.to_date(po_line.order_id.date_order), expected_date_order)
- self.assertEqual(len(po_line), 1)
- self.assertEqual(po_line.product_uom_qty, 25.0)
- self.assertEqual(len(po_line.order_id), 1)
- orderpoint_form = Form(orderpoint)
- orderpoint_form.save()
- self.mock_date.today.return_value = fields.Date.today() + timedelta(days=2)
- orderpoint._compute_qty()
- self.env['procurement.group'].run_scheduler()
- po_line02 = self.env['purchase.order.line'].search([('product_id', '=', product.id)])
- self.assertEqual(po_line02, po_line, 'The orderpoint execution should not create a new POL')
- self.assertEqual(fields.Date.to_date(po_line.order_id.date_order), expected_date_order, 'The Order Deadline should not change')
- self.assertEqual(po_line.product_uom_qty, 30.0, 'The existing POL should be updated with the quantity of the last execution')
- def test_supplier_lead_time(self):
- """ Basic stock configuration and a supplier with a minimum qty and a lead time """
- self.env['stock.warehouse.orderpoint'].search([]).unlink()
- orderpoint_form = Form(self.env['stock.warehouse.orderpoint'])
- orderpoint_form.product_id = self.product_1
- orderpoint_form.product_min_qty = 10
- orderpoint_form.product_max_qty = 50
- orderpoint_form.save()
- self.env['product.supplierinfo'].search([('product_tmpl_id', '=', self.product_1.product_tmpl_id.id)]).unlink()
- self.env['product.supplierinfo'].create({
- 'partner_id': self.partner_1.id,
- 'min_qty': 1,
- 'price': 1,
- 'delay': 7,
- 'product_tmpl_id': self.product_1.product_tmpl_id.id,
- })
- self.env['procurement.group'].run_scheduler()
- purchase_order = self.env['purchase.order'].search([('partner_id', '=', self.partner_1.id)])
- today = fields.Datetime.start_of(fields.Datetime.now(), 'day')
- self.assertEqual(purchase_order.date_order, today)
- self.assertEqual(fields.Datetime.start_of(purchase_order.date_planned, 'day'), today + timedelta(days=7))
|