diff --git a/addons/mrp/models/stock_orderpoint.py b/addons/mrp/models/stock_orderpoint.py
index 282210ab871..1550eeee22a 100644
--- a/addons/mrp/models/stock_orderpoint.py
+++ b/addons/mrp/models/stock_orderpoint.py
@@ -20,7 +20,7 @@ class StockWarehouseOrderpoint(models.Model):
self.ensure_one()
domain = [('orderpoint_id', 'in', self.ids)]
if self.env.context.get('written_after'):
- domain = AND([domain, [('write_date', '>', self.env.context.get('written_after'))]])
+ domain = AND([domain, [('write_date', '>=', self.env.context.get('written_after'))]])
production = self.env['mrp.production'].search(domain, limit=1)
if production:
action = self.env.ref('mrp.action_mrp_production_form')
diff --git a/addons/mrp_subcontracting/wizard/__init__.py b/addons/mrp_subcontracting/wizard/__init__.py
index 0594ad02b2a..319a4950ae7 100644
--- a/addons/mrp_subcontracting/wizard/__init__.py
+++ b/addons/mrp_subcontracting/wizard/__init__.py
@@ -4,3 +4,4 @@
from . import stock_picking_return
from . import mrp_consumption_warning
from . import change_production_qty
+from . import product_replenish
diff --git a/addons/mrp_subcontracting/wizard/product_replenish.py b/addons/mrp_subcontracting/wizard/product_replenish.py
new file mode 100644
index 00000000000..3162ddb762a
--- /dev/null
+++ b/addons/mrp_subcontracting/wizard/product_replenish.py
@@ -0,0 +1,13 @@
+# -*- coding: utf-8 -*-
+# Part of Odoo. See LICENSE file for full copyright and licensing details.
+
+from odoo import models
+from odoo.osv import expression
+
+
+class ProductReplenish(models.TransientModel):
+ _inherit = 'product.replenish'
+
+ def _get_allowed_route_domain(self):
+ domains = super()._get_allowed_route_domain()
+ return expression.AND([domains, [('id', '!=', self.env.ref('mrp_subcontracting.route_resupply_subcontractor_mto', raise_if_not_found=False).id)]])
diff --git a/addons/mrp_subcontracting_dropshipping/__init__.py b/addons/mrp_subcontracting_dropshipping/__init__.py
index dc5e6b693d1..2ae6446f9dc 100644
--- a/addons/mrp_subcontracting_dropshipping/__init__.py
+++ b/addons/mrp_subcontracting_dropshipping/__init__.py
@@ -2,3 +2,4 @@
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from . import models
+from . import wizard
diff --git a/addons/mrp_subcontracting_dropshipping/wizard/__init__.py b/addons/mrp_subcontracting_dropshipping/wizard/__init__.py
new file mode 100644
index 00000000000..6326fb55f39
--- /dev/null
+++ b/addons/mrp_subcontracting_dropshipping/wizard/__init__.py
@@ -0,0 +1,4 @@
+# -*- coding: utf-8 -*-
+# Part of Odoo. See LICENSE file for full copyright and licensing details.
+
+from . import product_replenish
diff --git a/addons/mrp_subcontracting_dropshipping/wizard/product_replenish.py b/addons/mrp_subcontracting_dropshipping/wizard/product_replenish.py
new file mode 100644
index 00000000000..28c98264cd8
--- /dev/null
+++ b/addons/mrp_subcontracting_dropshipping/wizard/product_replenish.py
@@ -0,0 +1,13 @@
+# -*- coding: utf-8 -*-
+# Part of Odoo. See LICENSE file for full copyright and licensing details.
+
+from odoo import models
+from odoo.osv import expression
+
+
+class ProductReplenish(models.TransientModel):
+ _inherit = 'product.replenish'
+
+ def _get_allowed_route_domain(self):
+ domains = super()._get_allowed_route_domain()
+ return expression.AND([domains, [('id', '!=', self.env.ref('mrp_subcontracting_dropshipping.route_subcontracting_dropshipping', raise_if_not_found=False).id)]])
diff --git a/addons/purchase_stock/__manifest__.py b/addons/purchase_stock/__manifest__.py
index 47ce2b411a4..16ef01ac165 100644
--- a/addons/purchase_stock/__manifest__.py
+++ b/addons/purchase_stock/__manifest__.py
@@ -23,7 +23,8 @@
'report/purchase_report_views.xml',
'report/purchase_report_templates.xml',
'report/report_stock_rule.xml',
- 'wizard/stock_replenishment_info.xml'
+ 'wizard/stock_replenishment_info.xml',
+ 'wizard/product_replenish_views.xml',
],
'demo': [
'data/purchase_stock_demo.xml',
diff --git a/addons/purchase_stock/models/product.py b/addons/purchase_stock/models/product.py
index 4eacaac340e..025418d3ab2 100644
--- a/addons/purchase_stock/models/product.py
+++ b/addons/purchase_stock/models/product.py
@@ -130,3 +130,14 @@ class SupplierInfo(models.Model):
orderpoint.supplier_id = self
if orderpoint.qty_to_order < self.min_qty:
orderpoint.qty_to_order = self.min_qty
+ if self._context.get('replenish_id'):
+ replenish = self.env['product.replenish'].browse(self._context.get('replenish_id'))
+ replenish.supplier_id = self
+ return {
+ 'type': 'ir.actions.act_window',
+ 'name': 'Replenish',
+ 'res_model': 'product.replenish',
+ 'res_id': replenish.id,
+ 'target': 'new',
+ 'view_mode': 'form',
+ }
diff --git a/addons/purchase_stock/models/stock.py b/addons/purchase_stock/models/stock.py
index 84af9ffcf32..b77048c64bf 100644
--- a/addons/purchase_stock/models/stock.py
+++ b/addons/purchase_stock/models/stock.py
@@ -152,7 +152,7 @@ class Orderpoint(models.Model):
self.ensure_one()
domain = [('orderpoint_id', 'in', self.ids)]
if self.env.context.get('written_after'):
- domain = AND([domain, [('write_date', '>', self.env.context.get('written_after'))]])
+ domain = AND([domain, [('write_date', '>=', self.env.context.get('written_after'))]])
order = self.env['purchase.order.line'].search(domain, limit=1).order_id
if order:
action = self.env.ref('purchase.action_rfq_form')
diff --git a/addons/purchase_stock/tests/test_replenish_wizard.py b/addons/purchase_stock/tests/test_replenish_wizard.py
index 7ed82d33bb9..a60624905cd 100644
--- a/addons/purchase_stock/tests/test_replenish_wizard.py
+++ b/addons/purchase_stock/tests/test_replenish_wizard.py
@@ -43,11 +43,14 @@ class TestReplenishWizard(TestStockCommon):
'quantity': self.product_uom_qty,
'warehouse_id': self.wh.id,
})
- replenish_wizard.launch_replenishment()
- last_po_id = self.env['purchase.order'].search([
- ('origin', 'ilike', '%Manual Replenishment%'),
- ('partner_id', '=', self.vendor.id)
- ])[-1]
+ genrated_picking = replenish_wizard.launch_replenishment()
+ links = genrated_picking.get("params", {}).get("links")
+ url = links and links[0].get("url", "") or ""
+ purchase_order_id, model_name = self.url_extract_rec_id_and_model(url)
+
+ last_po_id = False
+ if purchase_order_id and model_name:
+ last_po_id = self.env[model_name[0]].browse(int(purchase_order_id[0]))
self.assertTrue(last_po_id, 'Purchase Order not found')
order_line = last_po_id.order_line.search([('product_id', '=', self.product1.id)])
self.assertTrue(order_line, 'The product is not in the Purchase Order')
@@ -93,10 +96,14 @@ class TestReplenishWizard(TestStockCommon):
'quantity': 10,
'warehouse_id': self.wh.id,
})
- replenish_wizard.launch_replenishment()
- last_po_id = self.env['purchase.order'].search([
- ('origin', 'ilike', '%Manual Replenishment%'),
- ])[-1]
+ genrated_picking = replenish_wizard.launch_replenishment()
+ links = genrated_picking.get("params", {}).get("links")
+ url = links and links[0].get("url", "") or ""
+ purchase_order_id, model_name = self.url_extract_rec_id_and_model(url)
+
+ last_po_id = False
+ if purchase_order_id and model_name:
+ last_po_id = self.env[model_name[0]].browse(int(purchase_order_id[0]))
self.assertEqual(last_po_id.partner_id, vendor1)
self.assertEqual(last_po_id.order_line.price_unit, 100)
@@ -148,10 +155,14 @@ class TestReplenishWizard(TestStockCommon):
'quantity': 10,
'warehouse_id': self.wh.id,
})
- replenish_wizard.launch_replenishment()
- last_po_id = self.env['purchase.order'].search([
- ('origin', 'ilike', '%Manual Replenishment%'),
- ])[-1]
+ genrated_picking = replenish_wizard.launch_replenishment()
+ links = genrated_picking.get("params", {}).get("links")
+ url = links and links[0].get("url", "") or ""
+ purchase_order_id, model_name = self.url_extract_rec_id_and_model(url)
+
+ last_po_id = False
+ if purchase_order_id and model_name:
+ last_po_id = self.env[model_name[0]].browse(int(purchase_order_id[0]))
self.assertEqual(last_po_id.partner_id, vendor1)
self.assertEqual(last_po_id.order_line.price_unit, 100)
@@ -193,10 +204,15 @@ class TestReplenishWizard(TestStockCommon):
'quantity': 10,
'warehouse_id': self.wh.id,
})
- replenish_wizard.launch_replenishment()
- last_po_id = self.env['purchase.order'].search([
- ('origin', 'ilike', '%Manual Replenishment%'),
- ])[-1]
+ genrated_picking = replenish_wizard.launch_replenishment()
+ links = genrated_picking.get("params", {}).get("links")
+ url = links and links[0].get("url", "") or ""
+ purchase_order_id, model_name = self.url_extract_rec_id_and_model(url)
+
+ last_po_id = False
+ if purchase_order_id and model_name:
+ last_po_id = self.env[model_name[0]].browse(int(purchase_order_id[0]))
+
self.assertEqual(last_po_id.partner_id, vendor2)
def test_chose_supplier_4(self):
@@ -241,10 +257,14 @@ class TestReplenishWizard(TestStockCommon):
'quantity': 10,
'warehouse_id': self.wh.id,
})
- replenish_wizard.launch_replenishment()
- last_po_id = self.env['purchase.order'].search([
- ('origin', 'ilike', '%Manual Replenishment%'),
- ])[-1]
+ genrated_picking = replenish_wizard.launch_replenishment()
+ links = genrated_picking.get("params", {}).get("links")
+ url = links and links[0].get("url", "") or ""
+ purchase_order_id, model_name = self.url_extract_rec_id_and_model(url)
+
+ last_po_id = False
+ if purchase_order_id and model_name:
+ last_po_id = self.env[model_name[0]].browse(int(purchase_order_id[0]))
self.assertEqual(last_po_id.partner_id, vendor1)
self.assertEqual(last_po_id.order_line.price_unit, 60)
diff --git a/addons/purchase_stock/tests/test_stockvaluation.py b/addons/purchase_stock/tests/test_stockvaluation.py
index 81a73034458..8a141046c73 100644
--- a/addons/purchase_stock/tests/test_stockvaluation.py
+++ b/addons/purchase_stock/tests/test_stockvaluation.py
@@ -11,12 +11,14 @@ from odoo.tests import Form
from odoo.tests.common import TransactionCase, tagged
from odoo.addons.account.tests.common import AccountTestInvoicingCommon
from odoo.tools import DEFAULT_SERVER_DATETIME_FORMAT
+from odoo.addons.stock.tests.common import TestStockCommon
class TestStockValuation(TransactionCase):
@classmethod
def setUpClass(cls):
super().setUpClass()
+ cls.url_extract_rec_id_and_model = TestStockCommon.url_extract_rec_id_and_model
cls.supplier_location = cls.env.ref('stock.stock_location_suppliers')
cls.stock_location = cls.env.ref('stock.stock_location_stock')
cls.partner_id = cls.env['res.partner'].create({
@@ -107,12 +109,14 @@ class TestStockValuation(TransactionCase):
'quantity': replenishment_uom_qty,
'warehouse_id': self.env['stock.warehouse'].search([('company_id', '=', self.env.user.id)], limit=1).id,
})
- replenish_wizard.launch_replenishment()
+ genrated_picking = replenish_wizard.launch_replenishment()
+ links = genrated_picking.get("params", {}).get("links")
+ url = links and links[0].get("url", "") or ""
+ purchase_order_id, model_name = self.url_extract_rec_id_and_model(url)
+ last_po_id = False
+ if purchase_order_id and model_name:
+ last_po_id = self.env[model_name[0]].browse(int(purchase_order_id[0]))
- last_po_id = self.env['purchase.order'].search([
- ('origin', 'ilike', '%Manual Replenishment%'),
- ('partner_id', '=', vendor.id)
- ])[-1]
order_line = last_po_id.order_line.search([('product_id', '=', self.product1.id)])
self.assertEqual(order_line.product_qty,
ap._compute_quantity(replenishment_uom_qty, kgm, rounding_method='HALF-UP'),
diff --git a/addons/purchase_stock/wizard/__init__.py b/addons/purchase_stock/wizard/__init__.py
index 28595d05268..2a77252ebc4 100644
--- a/addons/purchase_stock/wizard/__init__.py
+++ b/addons/purchase_stock/wizard/__init__.py
@@ -2,3 +2,4 @@
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from . import stock_replenishment_info
+from . import product_replenish
diff --git a/addons/purchase_stock/wizard/product_replenish.py b/addons/purchase_stock/wizard/product_replenish.py
new file mode 100644
index 00000000000..50adced44f9
--- /dev/null
+++ b/addons/purchase_stock/wizard/product_replenish.py
@@ -0,0 +1,71 @@
+# -*- coding: utf-8 -*-
+# Part of Odoo. See LICENSE file for full copyright and licensing details.
+
+from odoo import _, api, fields, models
+from odoo.osv.expression import AND
+
+
+class ProductReplenish(models.TransientModel):
+ _inherit = 'product.replenish'
+
+ supplier_id = fields.Many2one("product.supplierinfo", string="Vendor")
+ show_vendor = fields.Boolean(compute="_compute_show_vendor")
+
+ @api.model
+ def default_get(self, fields):
+ res = super().default_get(fields)
+ if res.get('product_id'):
+ product_id = self.env['product.product'].browse(res['product_id'])
+ product_tmpl_id = product_id.product_tmpl_id
+ if 'warehouse_id' not in res:
+ company = product_tmpl_id.company_id or self.env.company
+ res['warehouse_id'] = self.env['stock.warehouse'].search([('company_id', '=', company.id)], limit=1).id
+ orderpoint = self.env['stock.warehouse.orderpoint'].search([('product_id', 'in', [product_tmpl_id.product_variant_id.id, product_id.id]), ("warehouse_id", "=", res['warehouse_id'])], limit=1)
+ if orderpoint:
+ res['supplier_id'] = orderpoint.supplier_id.id
+ elif product_tmpl_id.seller_ids:
+ res['supplier_id'] = product_tmpl_id.seller_ids[0].id
+ if not product_tmpl_id.seller_ids:
+ company = product_tmpl_id.company_id or self.env.company
+ domain = ['|', ('company_id', '=', False), ('company_id', '=', company.id)] + self._get_allowed_route_domain()
+ domain = AND([domain, [('id', '!=', self.env.ref('purchase_stock.route_warehouse0_buy', raise_if_not_found=False).id)]])
+ res['route_id'] = self.env['stock.route'].search(domain, limit=1).id
+ return res
+
+ @api.depends('route_id')
+ def _compute_show_vendor(self):
+ for rec in self:
+ rec.show_vendor = rec.route_id == self.env.ref('purchase_stock.route_warehouse0_buy', raise_if_not_found=False)
+
+ @api.onchange('route_id')
+ def _onchange_route_id(self):
+ for rec in self:
+ if rec.route_id == self.env.ref('purchase_stock.route_warehouse0_buy', raise_if_not_found=False) and not rec.product_id.product_tmpl_id.seller_ids:
+ return {
+ 'warning': {
+ 'title': _("Vendor Not Found in Product %s", rec.product_id.name),
+ 'message': _("Go on the product form and add the list of vendors"),
+ },
+ }
+
+ def _prepare_orderpoint_values(self):
+ res = super()._prepare_orderpoint_values()
+ if self.supplier_id:
+ res['supplier_id'] = self.supplier_id.id
+ return res
+
+ def action_stock_replenishment_info(self):
+ self.ensure_one()
+ orderpoint = self.env["stock.warehouse.orderpoint"].search([("product_id", "=", self.product_id.id), ("warehouse_id", "=", self.warehouse_id.id)], limit=1)
+ if not orderpoint:
+ orderpoint = self.env["stock.warehouse.orderpoint"].create({
+ "product_id": self.product_id.id,
+ "warehouse_id": self.warehouse_id.id,
+ })
+ action = orderpoint.action_stock_replenishment_info()
+
+ action["context"] = {
+ 'default_orderpoint_id': orderpoint.id,
+ 'replenish_id': self.id,
+ }
+ return action
diff --git a/addons/purchase_stock/wizard/product_replenish_views.xml b/addons/purchase_stock/wizard/product_replenish_views.xml
new file mode 100644
index 00000000000..a3e356ae015
--- /dev/null
+++ b/addons/purchase_stock/wizard/product_replenish_views.xml
@@ -0,0 +1,22 @@
+
+