Начальное наполнение
This commit is contained in:
parent
08a104bda6
commit
eec08269ad
4
__init__.py
Normal file
4
__init__.py
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||||
|
|
||||||
|
from . import models
|
16
__manifest__.py
Normal file
16
__manifest__.py
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||||
|
|
||||||
|
{
|
||||||
|
'name': 'MTO Sale <-> Purchase',
|
||||||
|
'version': '1.0',
|
||||||
|
'category': 'Hidden',
|
||||||
|
'summary': 'SO/PO relation in case of MTO',
|
||||||
|
'description': """
|
||||||
|
Add relation information between Sale Orders and Purchase Orders if Make to Order (MTO) is activated on one sold product.
|
||||||
|
""",
|
||||||
|
'depends': ['sale_stock', 'purchase_stock', 'sale_purchase'],
|
||||||
|
'installable': True,
|
||||||
|
'auto_install': True,
|
||||||
|
'license': 'LGPL-3',
|
||||||
|
}
|
28
i18n/ru.po
Normal file
28
i18n/ru.po
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
# Translation of Odoo Server.
|
||||||
|
# This file contains the translation of the following modules:
|
||||||
|
# * sale_purchase_stock
|
||||||
|
#
|
||||||
|
# Translators:
|
||||||
|
msgid ""
|
||||||
|
msgstr ""
|
||||||
|
"Project-Id-Version: Odoo Server 17.0\n"
|
||||||
|
"Report-Msgid-Bugs-To: \n"
|
||||||
|
"POT-Creation-Date: 2023-10-26 21:55+0000\n"
|
||||||
|
"PO-Revision-Date: 2024-01-30 15:14+0400\n"
|
||||||
|
"Last-Translator: \n"
|
||||||
|
"Language-Team: Russian (https://app.transifex.com/odoo/teams/41243/ru/)\n"
|
||||||
|
"Language: ru\n"
|
||||||
|
"MIME-Version: 1.0\n"
|
||||||
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
|
"Content-Transfer-Encoding: \n"
|
||||||
|
"Plural-Forms: nplurals=4; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<12 || n%100>14) ? 1 : n%10==0 || (n%10>=5 && n%10<=9) || (n%100>=11 && n%100<=14)? 2 : 3);\n"
|
||||||
|
|
||||||
|
#. module: sale_purchase_stock
|
||||||
|
#: model:ir.model,name:sale_purchase_stock.model_purchase_order
|
||||||
|
msgid "Purchase Order"
|
||||||
|
msgstr "Заказа на покупку"
|
||||||
|
|
||||||
|
#. module: sale_purchase_stock
|
||||||
|
#: model:ir.model,name:sale_purchase_stock.model_sale_order
|
||||||
|
msgid "Sales Order"
|
||||||
|
msgstr "Заказ на продажу"
|
26
i18n/sale_purchase_stock.pot
Normal file
26
i18n/sale_purchase_stock.pot
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
# Translation of Odoo Server.
|
||||||
|
# This file contains the translation of the following modules:
|
||||||
|
# * sale_purchase_stock
|
||||||
|
#
|
||||||
|
msgid ""
|
||||||
|
msgstr ""
|
||||||
|
"Project-Id-Version: Odoo Server 17.0\n"
|
||||||
|
"Report-Msgid-Bugs-To: \n"
|
||||||
|
"POT-Creation-Date: 2023-10-26 21:55+0000\n"
|
||||||
|
"PO-Revision-Date: 2023-10-26 21:55+0000\n"
|
||||||
|
"Last-Translator: \n"
|
||||||
|
"Language-Team: \n"
|
||||||
|
"MIME-Version: 1.0\n"
|
||||||
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
|
"Content-Transfer-Encoding: \n"
|
||||||
|
"Plural-Forms: \n"
|
||||||
|
|
||||||
|
#. module: sale_purchase_stock
|
||||||
|
#: model:ir.model,name:sale_purchase_stock.model_purchase_order
|
||||||
|
msgid "Purchase Order"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: sale_purchase_stock
|
||||||
|
#: model:ir.model,name:sale_purchase_stock.model_sale_order
|
||||||
|
msgid "Sales Order"
|
||||||
|
msgstr ""
|
5
models/__init__.py
Normal file
5
models/__init__.py
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||||
|
|
||||||
|
from . import purchase_order
|
||||||
|
from . import sale_order
|
15
models/purchase_order.py
Normal file
15
models/purchase_order.py
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||||
|
|
||||||
|
from odoo import api, models
|
||||||
|
|
||||||
|
|
||||||
|
class PurchaseOrder(models.Model):
|
||||||
|
_inherit = 'purchase.order'
|
||||||
|
|
||||||
|
@api.depends('order_line.move_dest_ids.group_id.sale_id', 'order_line.move_ids.move_dest_ids.group_id.sale_id')
|
||||||
|
def _compute_sale_order_count(self):
|
||||||
|
super(PurchaseOrder, self)._compute_sale_order_count()
|
||||||
|
|
||||||
|
def _get_sale_orders(self):
|
||||||
|
return super(PurchaseOrder, self)._get_sale_orders() | self.order_line.move_dest_ids.group_id.sale_id | self.order_line.move_ids.move_dest_ids.group_id.sale_id
|
15
models/sale_order.py
Normal file
15
models/sale_order.py
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||||
|
|
||||||
|
from odoo import api, models
|
||||||
|
|
||||||
|
|
||||||
|
class SaleOrder(models.Model):
|
||||||
|
_inherit = 'sale.order'
|
||||||
|
|
||||||
|
@api.depends('procurement_group_id.stock_move_ids.created_purchase_line_ids.order_id', 'procurement_group_id.stock_move_ids.move_orig_ids.purchase_line_id.order_id')
|
||||||
|
def _compute_purchase_order_count(self):
|
||||||
|
super(SaleOrder, self)._compute_purchase_order_count()
|
||||||
|
|
||||||
|
def _get_purchase_orders(self):
|
||||||
|
return super(SaleOrder, self)._get_purchase_orders() | self.procurement_group_id.stock_move_ids.created_purchase_line_ids.order_id | self.procurement_group_id.stock_move_ids.move_orig_ids.purchase_line_id.order_id
|
6
tests/__init__.py
Normal file
6
tests/__init__.py
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||||
|
|
||||||
|
from . import test_sale_purchase_stock_flow
|
||||||
|
from . import test_access_rights
|
||||||
|
from . import test_unwanted_replenish_flow
|
76
tests/test_access_rights.py
Normal file
76
tests/test_access_rights.py
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||||
|
|
||||||
|
from odoo.tests import tagged
|
||||||
|
from odoo.addons.sale_purchase.tests.common import TestCommonSalePurchaseNoChart
|
||||||
|
|
||||||
|
|
||||||
|
@tagged('post_install', '-at_install')
|
||||||
|
class TestAccessRights(TestCommonSalePurchaseNoChart):
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def setUpClass(cls):
|
||||||
|
super(TestAccessRights, cls).setUpClass()
|
||||||
|
|
||||||
|
group_sale_user = cls.env.ref('sales_team.group_sale_salesman')
|
||||||
|
|
||||||
|
cls.user_salesperson = cls.env['res.users'].with_context(no_reset_password=True).create({
|
||||||
|
'name': 'Le Grand Jojo User',
|
||||||
|
'login': 'grand.jojo',
|
||||||
|
'email': 'grand.jojo@chansonbelge.com',
|
||||||
|
'groups_id': [(6, 0, [group_sale_user.id])]
|
||||||
|
})
|
||||||
|
|
||||||
|
def test_access_saleperson_decreases_qty(self):
|
||||||
|
"""
|
||||||
|
Suppose a user who has no right on PO
|
||||||
|
Suppose a PO linked to a SO
|
||||||
|
The user decreases the qty on the SO
|
||||||
|
This test ensures that an activity (warning) is added to the PO
|
||||||
|
"""
|
||||||
|
mto_route = self.env.ref('stock.route_warehouse0_mto')
|
||||||
|
buy_route = self.env.ref('purchase_stock.route_warehouse0_buy')
|
||||||
|
mto_route.active = True
|
||||||
|
|
||||||
|
vendor = self.env['res.partner'].create({'name': 'vendor'})
|
||||||
|
seller = self.env['product.supplierinfo'].create({
|
||||||
|
'partner_id': vendor.id,
|
||||||
|
'price': 8,
|
||||||
|
})
|
||||||
|
|
||||||
|
product = self.env['product.product'].create({
|
||||||
|
'name': 'SuperProduct',
|
||||||
|
'type': 'product',
|
||||||
|
'seller_ids': [(6, 0, seller.ids)],
|
||||||
|
'route_ids': [(6, 0, (mto_route + buy_route).ids)]
|
||||||
|
})
|
||||||
|
|
||||||
|
so = self.env['sale.order'].with_user(self.user_salesperson).create({
|
||||||
|
'partner_id': self.partner_a.id,
|
||||||
|
'user_id': self.user_salesperson.id,
|
||||||
|
})
|
||||||
|
so_line, _ = self.env['sale.order.line'].create([{
|
||||||
|
'name': product.name,
|
||||||
|
'product_id': product.id,
|
||||||
|
'product_uom_qty': 1,
|
||||||
|
'product_uom': product.uom_id.id,
|
||||||
|
'price_unit': product.list_price,
|
||||||
|
'tax_id': False,
|
||||||
|
'order_id': so.id,
|
||||||
|
}, {
|
||||||
|
'name': 'Super Section',
|
||||||
|
'display_type': 'line_section',
|
||||||
|
'order_id': so.id,
|
||||||
|
}])
|
||||||
|
|
||||||
|
so.action_confirm()
|
||||||
|
|
||||||
|
po = self.env['purchase.order'].search([('partner_id', '=', vendor.id)])
|
||||||
|
po.button_confirm()
|
||||||
|
|
||||||
|
# salesperson writes on the SO
|
||||||
|
so.write({
|
||||||
|
'order_line': [(1, so_line.id, {'product_uom_qty': 0.9})]
|
||||||
|
})
|
||||||
|
|
||||||
|
self.assertIn(so.name, po.activity_ids.note)
|
63
tests/test_lead_time.py
Normal file
63
tests/test_lead_time.py
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||||
|
|
||||||
|
from datetime import timedelta
|
||||||
|
|
||||||
|
from odoo import fields
|
||||||
|
from odoo.tests import tagged
|
||||||
|
from odoo.addons.sale_purchase.tests.common import TestCommonSalePurchaseNoChart
|
||||||
|
|
||||||
|
|
||||||
|
@tagged('post_install', '-at_install')
|
||||||
|
class TestLeadTime(TestCommonSalePurchaseNoChart):
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def setUpClass(cls):
|
||||||
|
super(TestLeadTime, cls).setUpClass()
|
||||||
|
|
||||||
|
cls.buy_route = cls.env.ref('purchase_stock.route_warehouse0_buy')
|
||||||
|
cls.mto_route = cls.env.ref('stock.route_warehouse0_mto')
|
||||||
|
cls.mto_route.active = True
|
||||||
|
cls.vendor = cls.env['res.partner'].create({'name': 'The Emperor'})
|
||||||
|
cls.user_salesperson = cls.env['res.users'].with_context(no_reset_password=True).create({
|
||||||
|
'name': 'Le Grand Horus',
|
||||||
|
'login': 'grand.horus',
|
||||||
|
'email': 'grand.horus@chansonbelge.dz',
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
def test_supplier_lead_time(self):
|
||||||
|
""" Basic stock configuration and a supplier with a minimum qty and a lead time """
|
||||||
|
|
||||||
|
self.env.user.company_id.po_lead = 7
|
||||||
|
seller = self.env['product.supplierinfo'].create({
|
||||||
|
'name': self.vendor.id,
|
||||||
|
'min_qty': 1,
|
||||||
|
'price': 10,
|
||||||
|
'date_start': fields.Date.today() - timedelta(days=1),
|
||||||
|
})
|
||||||
|
|
||||||
|
product = self.env['product.product'].create({
|
||||||
|
'name': 'corpse starch',
|
||||||
|
'type': 'product',
|
||||||
|
'seller_ids': [(6, 0, seller.ids)],
|
||||||
|
'route_ids': [(6, 0, (self.mto_route + self.buy_route).ids)],
|
||||||
|
})
|
||||||
|
|
||||||
|
so = self.env['sale.order'].with_user(self.user_salesperson).create({
|
||||||
|
'partner_id': self.partner_a.id,
|
||||||
|
'user_id': self.user_salesperson.id,
|
||||||
|
})
|
||||||
|
self.env['sale.order.line'].create({
|
||||||
|
'name': product.name,
|
||||||
|
'product_id': product.id,
|
||||||
|
'product_uom_qty': 1,
|
||||||
|
'product_uom': product.uom_id.id,
|
||||||
|
'price_unit': product.list_price,
|
||||||
|
'tax_id': False,
|
||||||
|
'order_id': so.id,
|
||||||
|
})
|
||||||
|
so.action_confirm()
|
||||||
|
|
||||||
|
po = self.env['purchase.order'].search([('partner_id', '=', self.vendor.id)])
|
||||||
|
self.assertEqual(po.order_line.price_unit, seller.price)
|
144
tests/test_sale_purchase_stock_flow.py
Normal file
144
tests/test_sale_purchase_stock_flow.py
Normal file
@ -0,0 +1,144 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||||
|
|
||||||
|
from odoo.tests.common import TransactionCase, Form
|
||||||
|
from freezegun import freeze_time
|
||||||
|
from datetime import datetime, timedelta
|
||||||
|
|
||||||
|
class TestSalePurchaseStockFlow(TransactionCase):
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def setUpClass(cls):
|
||||||
|
super(TestSalePurchaseStockFlow, cls).setUpClass()
|
||||||
|
cls.mto_route = cls.env.ref('stock.route_warehouse0_mto')
|
||||||
|
cls.buy_route = cls.env.ref('purchase_stock.route_warehouse0_buy')
|
||||||
|
cls.mto_route.active = True
|
||||||
|
|
||||||
|
cls.customer_location = cls.env.ref('stock.stock_location_customers')
|
||||||
|
|
||||||
|
cls.vendor = cls.env['res.partner'].create({'name': 'Super Vendor'})
|
||||||
|
cls.customer = cls.env['res.partner'].create({'name': 'Super Customer'})
|
||||||
|
|
||||||
|
cls.mto_product = cls.env['product.product'].create({
|
||||||
|
'name': 'SuperProduct',
|
||||||
|
'type': 'product',
|
||||||
|
'route_ids': [(6, 0, (cls.mto_route + cls.buy_route).ids)],
|
||||||
|
'seller_ids': [(0, 0, {
|
||||||
|
'partner_id': cls.vendor.id,
|
||||||
|
})],
|
||||||
|
})
|
||||||
|
|
||||||
|
def test_cancel_so_with_draft_po(self):
|
||||||
|
"""
|
||||||
|
Sell a MTO+Buy product -> a PO is generated
|
||||||
|
Cancel the SO -> an activity should be added to the PO
|
||||||
|
"""
|
||||||
|
so_form = Form(self.env['sale.order'])
|
||||||
|
so_form.partner_id = self.env.user.partner_id
|
||||||
|
with so_form.order_line.new() as line:
|
||||||
|
line.product_id = self.mto_product
|
||||||
|
so = so_form.save()
|
||||||
|
so.action_confirm()
|
||||||
|
|
||||||
|
po = self.env['purchase.order'].search([('partner_id', '=', self.vendor.id)])
|
||||||
|
|
||||||
|
so._action_cancel()
|
||||||
|
|
||||||
|
self.assertTrue(po.activity_ids)
|
||||||
|
self.assertIn(so.name, po.activity_ids.note)
|
||||||
|
|
||||||
|
def test_qty_delivered_with_mto_and_done_quantity_change(self):
|
||||||
|
"""
|
||||||
|
MTO product P
|
||||||
|
Sell 10 x P. On the delivery, set the done quantity to 12, validate and
|
||||||
|
then set the done quantity to 10: the delivered qty of the SOL should
|
||||||
|
be 10
|
||||||
|
"""
|
||||||
|
so = self.env['sale.order'].create({
|
||||||
|
'partner_id': self.customer.id,
|
||||||
|
'order_line': [(0, 0, {
|
||||||
|
'name': self.mto_product.name,
|
||||||
|
'product_id': self.mto_product.id,
|
||||||
|
'product_uom_qty': 10,
|
||||||
|
'product_uom': self.mto_product.uom_id.id,
|
||||||
|
'price_unit': 1,
|
||||||
|
})],
|
||||||
|
})
|
||||||
|
so.action_confirm()
|
||||||
|
|
||||||
|
delivery = so.picking_ids.filtered(lambda p: p.location_dest_id == self.customer_location)
|
||||||
|
sm = delivery.move_ids
|
||||||
|
sm.move_line_ids = [(5, 0, 0), (0, 0, {
|
||||||
|
'location_id': sm.location_id.id,
|
||||||
|
'location_dest_id': sm.location_dest_id.id,
|
||||||
|
'product_id': sm.product_id.id,
|
||||||
|
'quantity': 12,
|
||||||
|
'company_id': sm.company_id.id,
|
||||||
|
'product_uom_id': sm.product_uom.id,
|
||||||
|
'picking_id': delivery.id,
|
||||||
|
})]
|
||||||
|
delivery.button_validate()
|
||||||
|
|
||||||
|
self.assertEqual(delivery.state, 'done')
|
||||||
|
self.assertEqual(delivery.move_ids.move_line_ids.quantity, 12)
|
||||||
|
self.assertEqual(so.order_line.qty_delivered, 12)
|
||||||
|
|
||||||
|
sm.move_line_ids.quantity = 10
|
||||||
|
self.assertEqual(so.order_line.qty_delivered, 10)
|
||||||
|
|
||||||
|
@freeze_time('2024-01-01')
|
||||||
|
def test_reordering_with_visibility_days(self):
|
||||||
|
"""
|
||||||
|
If reordering rules' visibility is set bigger than
|
||||||
|
DAYS_FROM_TODAY_TO_ORDER (plus lead time). Then the
|
||||||
|
order should be included in the calculation of quantity to order.
|
||||||
|
|
||||||
|
┌─ Today ┌── Scheduled Delivery
|
||||||
|
│ (2024-01-01) │ (2024-02-01)
|
||||||
|
│ │ aka commitment_date
|
||||||
|
│ │
|
||||||
|
▼ ▼
|
||||||
|
──────────────────────────────────────────►
|
||||||
|
time
|
||||||
|
◄────────────────────────────►
|
||||||
|
DAYS_FROM_TODAY_TO_ORDER
|
||||||
|
|
||||||
|
◄────►
|
||||||
|
lead_time
|
||||||
|
"""
|
||||||
|
N_ORDERED_QTY = 666
|
||||||
|
DAYS_FROM_TODAY_TO_ORDER = 30
|
||||||
|
MONTH_FROM_TODAY = (datetime.today() + timedelta(days=DAYS_FROM_TODAY_TO_ORDER)).strftime('%Y-%m-%d')
|
||||||
|
|
||||||
|
# Setup: Create a product with vendor
|
||||||
|
partner = self.env['res.partner'].create({'name': 'Azure Interior'})
|
||||||
|
seller = self.env['product.supplierinfo'].create({
|
||||||
|
'partner_id': partner.id,
|
||||||
|
'price': 1.0,
|
||||||
|
})
|
||||||
|
product = self.env['product.product'].create({
|
||||||
|
'name': 'Dummy Product',
|
||||||
|
'type': 'product',
|
||||||
|
'seller_ids': [seller.id],
|
||||||
|
})
|
||||||
|
|
||||||
|
# Setup: Create sale order scheduled in the future
|
||||||
|
so = self.env['sale.order'].create({
|
||||||
|
'partner_id': self.customer.id,
|
||||||
|
'commitment_date': MONTH_FROM_TODAY,
|
||||||
|
'order_line': [(0, 0, {
|
||||||
|
'name': product.name,
|
||||||
|
'product_id': product.id,
|
||||||
|
'price_unit': 1,
|
||||||
|
'product_uom_qty': N_ORDERED_QTY,
|
||||||
|
})],
|
||||||
|
})
|
||||||
|
so.action_confirm() # so.state: 'draft' -> 'sale'
|
||||||
|
|
||||||
|
# Create Reordering rule and trigger recalculation
|
||||||
|
orderpoint_form = Form(self.env['stock.warehouse.orderpoint'])
|
||||||
|
orderpoint_form.product_id = product
|
||||||
|
orderpoint_form.visibility_days = DAYS_FROM_TODAY_TO_ORDER
|
||||||
|
orderpoint = orderpoint_form.save()
|
||||||
|
|
||||||
|
self.assertEqual(orderpoint.qty_to_order, N_ORDERED_QTY, f"Order from {DAYS_FROM_TODAY_TO_ORDER} days from today NOT included into the qty_to_order calculation, despite having visibility days set {DAYS_FROM_TODAY_TO_ORDER}!")
|
135
tests/test_unwanted_replenish_flow.py
Normal file
135
tests/test_unwanted_replenish_flow.py
Normal file
@ -0,0 +1,135 @@
|
|||||||
|
from datetime import datetime, timedelta
|
||||||
|
from odoo import Command
|
||||||
|
from odoo.tests import common, Form, tagged
|
||||||
|
|
||||||
|
@tagged('post_install', '-at_install')
|
||||||
|
class TestWarnUnwantedReplenish(common.TransactionCase):
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def setUpClass(cls):
|
||||||
|
super().setUpClass()
|
||||||
|
|
||||||
|
cls.buy_route = cls.env.ref('purchase_stock.route_warehouse0_buy')
|
||||||
|
|
||||||
|
# Create a vendor (& suppliers) and a customer
|
||||||
|
cls.vendor = cls.env['res.partner'].create(dict(name='Vendor'))
|
||||||
|
cls.customer = cls.env['res.partner'].create(dict(name='Customer'))
|
||||||
|
|
||||||
|
cls.supplier_A = cls.env['product.supplierinfo'].create({
|
||||||
|
'partner_id' : cls.vendor.id,
|
||||||
|
'min_qty' : 0.0,
|
||||||
|
'price' : 10.0,
|
||||||
|
'delay' : 0
|
||||||
|
})
|
||||||
|
|
||||||
|
cls.supplier_B = cls.env['product.supplierinfo'].create({
|
||||||
|
'partner_id' : cls.vendor.id,
|
||||||
|
'min_qty' : 0.0,
|
||||||
|
'price' : 12.0,
|
||||||
|
'delay' : 0
|
||||||
|
})
|
||||||
|
|
||||||
|
# Create a "A" and a "B" Product :
|
||||||
|
# No Stock
|
||||||
|
# Partner/Customer Lead Time = 0
|
||||||
|
# Manual reordering 0 0
|
||||||
|
|
||||||
|
cls.product_A = cls.env['product.product'].create({
|
||||||
|
'name': 'Product A',
|
||||||
|
'type': 'product',
|
||||||
|
'categ_id': cls.env.ref('product.product_category_all').id,
|
||||||
|
'purchase_method': 'purchase',
|
||||||
|
'invoice_policy': 'delivery',
|
||||||
|
'standard_price': 5.0,
|
||||||
|
'list_price': 10.0,
|
||||||
|
'seller_ids': [Command.link(cls.supplier_A.id)],
|
||||||
|
'route_ids': [Command.link(cls.buy_route.id)],
|
||||||
|
'sale_delay' : 0,
|
||||||
|
})
|
||||||
|
|
||||||
|
cls.product_B = cls.env['product.product'].create({
|
||||||
|
'name': 'Product B',
|
||||||
|
'type': 'product',
|
||||||
|
'categ_id': cls.env.ref('product.product_category_all').id,
|
||||||
|
'purchase_method': 'purchase',
|
||||||
|
'invoice_policy': 'delivery',
|
||||||
|
'standard_price': 6.0,
|
||||||
|
'list_price': 12.0,
|
||||||
|
'seller_ids': [Command.link(cls.supplier_B.id)],
|
||||||
|
'route_ids': [Command.link(cls.buy_route.id)],
|
||||||
|
'sale_delay': 0,
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
orderpoint_form = Form(cls.env['stock.warehouse.orderpoint'])
|
||||||
|
orderpoint_form.product_id = cls.product_A
|
||||||
|
orderpoint_form.product_min_qty = 0.0
|
||||||
|
orderpoint_form.product_max_qty = 0.0
|
||||||
|
cls.orderpoint_A = orderpoint_form.save()
|
||||||
|
cls.orderpoint_A.trigger = 'manual'
|
||||||
|
|
||||||
|
orderpoint_form = Form(cls.env['stock.warehouse.orderpoint'])
|
||||||
|
orderpoint_form.product_id = cls.product_B
|
||||||
|
orderpoint_form.product_min_qty = 0.0
|
||||||
|
orderpoint_form.product_max_qty = 0.0
|
||||||
|
cls.orderpoint_B = orderpoint_form.save()
|
||||||
|
cls.orderpoint_B.trigger = 'manual'
|
||||||
|
|
||||||
|
# Create Sales
|
||||||
|
# For A and for B
|
||||||
|
# Delivered today
|
||||||
|
# Confirm SO
|
||||||
|
|
||||||
|
cls.sale_order = cls.env['sale.order'].create({
|
||||||
|
'partner_id': cls.customer.id,
|
||||||
|
'order_line': [
|
||||||
|
Command.create({
|
||||||
|
'product_id': cls.product_A.id,
|
||||||
|
'product_uom_qty': 10,
|
||||||
|
}),
|
||||||
|
Command.create({
|
||||||
|
'product_id': cls.product_B.id,
|
||||||
|
'product_uom_qty': 10,
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
})
|
||||||
|
|
||||||
|
cls.sale_order.action_confirm()
|
||||||
|
|
||||||
|
# Create PO for Product A
|
||||||
|
# Confirm PO with date planned : TODAY
|
||||||
|
# Incoming Picking : reschedule in one week
|
||||||
|
|
||||||
|
cls.po_A = cls.env['purchase.order'].create({
|
||||||
|
'partner_id': cls.vendor.id,
|
||||||
|
'order_line': [
|
||||||
|
Command.create({
|
||||||
|
'name': cls.product_A.name,
|
||||||
|
'product_id': cls.product_A.id,
|
||||||
|
'product_qty': 10.0,
|
||||||
|
'price_unit': 10.0,
|
||||||
|
'date_planned': datetime.today(),
|
||||||
|
})],
|
||||||
|
})
|
||||||
|
|
||||||
|
cls.po_A.button_confirm()
|
||||||
|
|
||||||
|
cls.picking_A = cls.po_A.picking_ids[0]
|
||||||
|
cls.picking_A.scheduled_date = (datetime.today() + timedelta(days=10))
|
||||||
|
|
||||||
|
def test_01_pre_updateA_post(self):
|
||||||
|
"""
|
||||||
|
TEST 1
|
||||||
|
Replenishment ->
|
||||||
|
Product A
|
||||||
|
unwanted_replenish SHALL be TRUE
|
||||||
|
Product B
|
||||||
|
unwanted_replenish SHALL be FALSE
|
||||||
|
Product A
|
||||||
|
Modify Visible Days past 1 Week -> unwanted_replenish SHALL be FALSE
|
||||||
|
"""
|
||||||
|
self.assertTrue(self.orderpoint_A.unwanted_replenish, 'Orderpoint A not set to unwanted_replenish')
|
||||||
|
self.assertFalse(self.orderpoint_B.unwanted_replenish, 'Orderpoint B is set to unwanted_replenish')
|
||||||
|
#Update Orderpoint A
|
||||||
|
self.orderpoint_A.visibility_days = 10
|
||||||
|
self.assertFalse(self.orderpoint_A.unwanted_replenish, 'Orderpoint A shall not be set to unwanted_replenish')
|
Loading…
x
Reference in New Issue
Block a user