[IMP] purchase_stock: extend replenishment report
Adds Purchase Orders as replenishment/consuming document for the replenishment report. task-2058495
This commit is contained in:
@@ -24,6 +24,7 @@
|
||||
'views/product_category_views.xml',
|
||||
'report/purchase_report_views.xml',
|
||||
'report/purchase_report_templates.xml',
|
||||
'report/report_stock_forecasted.xml',
|
||||
'report/report_stock_rule.xml',
|
||||
],
|
||||
'demo': [
|
||||
|
||||
@@ -105,6 +105,10 @@ class StockMove(models.Model):
|
||||
rslt += self.mapped('picking_id.purchase_id.invoice_ids').filtered(lambda x: x.state == 'posted')
|
||||
return rslt
|
||||
|
||||
def _get_source_document(self):
|
||||
res = super()._get_source_document()
|
||||
return self.purchase_line_id.order_id or res
|
||||
|
||||
|
||||
class StockWarehouse(models.Model):
|
||||
_inherit = 'stock.warehouse'
|
||||
|
||||
@@ -2,5 +2,6 @@
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from . import purchase_report
|
||||
from . import report_stock_forecasted
|
||||
from . import report_stock_rule
|
||||
from . import vendor_delay_report
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from odoo import models
|
||||
|
||||
|
||||
class ReplenishmentReport(models.AbstractModel):
|
||||
_inherit = 'report.stock.report_product_product_replenishment'
|
||||
|
||||
def _compute_draft_quantity_count(self, product_template_ids, product_variant_ids, wh_location_ids):
|
||||
res = super()._compute_draft_quantity_count(product_template_ids, product_variant_ids, wh_location_ids)
|
||||
domain = [('state', 'in', ['draft', 'sent'])]
|
||||
domain += self._product_purchase_domain(product_template_ids, product_variant_ids)
|
||||
warehouse_id = self.env.context.get('warehouse', False)
|
||||
if warehouse_id:
|
||||
domain += [('order_id.picking_type_id.warehouse_id', '=', warehouse_id)]
|
||||
po_lines = self.env['purchase.order.line'].read_group(domain, ['product_uom_qty'], 'product_id')
|
||||
in_sum = sum(line['product_uom_qty'] for line in po_lines)
|
||||
|
||||
res['draft_purchase_qty'] = in_sum
|
||||
res['qty']['in'] += in_sum
|
||||
return res
|
||||
|
||||
def _product_purchase_domain(self, product_template_ids, product_variant_ids):
|
||||
if product_variant_ids:
|
||||
return [('product_id', 'in', product_variant_ids)]
|
||||
elif product_template_ids:
|
||||
products = self.env['product.product'].search_read(
|
||||
[('product_tmpl_id', 'in', product_template_ids)], ['id']
|
||||
)
|
||||
product_ids = [product['id'] for product in products]
|
||||
return [('product_id', 'in', product_ids)]
|
||||
@@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<template id="purchase_report_product_product_replenishment" inherit_id="stock.report_product_product_replenishment">
|
||||
<xpath expr="//tr[@name='draft_picking_in']" position="after">
|
||||
<tr t-if="docs['draft_purchase_qty']" name="draft_po_in">
|
||||
<td colspan="2">Draft PO</td>
|
||||
<td t-esc="docs['draft_purchase_qty']" class="text-right"/>
|
||||
<td t-esc="docs['uom']" groups="uom.group_uom"/>
|
||||
</tr>
|
||||
</xpath>
|
||||
</template>
|
||||
</odoo>
|
||||
@@ -11,6 +11,7 @@ from . import test_purchase_delete_order
|
||||
from . import test_purchase_lead_time
|
||||
from . import test_purchase_order
|
||||
from . import test_purchase_order_process
|
||||
from . import test_purchase_stock_report
|
||||
from . import test_stockvaluation
|
||||
from . import test_replenish_wizard
|
||||
from . import test_reordering_rule
|
||||
|
||||
@@ -0,0 +1,147 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from odoo.tests.common import Form
|
||||
from odoo.addons.stock.tests.test_report import TestReportsCommon
|
||||
|
||||
|
||||
class TestPurchaseStockReports(TestReportsCommon):
|
||||
def test_report_forecast_1_purchase_order_multi_receipt(self):
|
||||
""" Create a PO for 5 product, receive them then increase the quantity to 10.
|
||||
"""
|
||||
po_form = Form(self.env['purchase.order'])
|
||||
po_form.partner_id = self.partner
|
||||
with po_form.order_line.new() as line:
|
||||
line.product_id = self.product
|
||||
line.product_qty = 5
|
||||
po = po_form.save()
|
||||
|
||||
# Checks the report.
|
||||
report_values, docs, lines = self.get_report_forecast(product_template_ids=self.product_template.ids)
|
||||
draft_picking_qty_in = docs['draft_picking_qty']['in']
|
||||
draft_purchase_qty = docs['draft_purchase_qty']
|
||||
pending_qty_in = docs['qty']['in']
|
||||
self.assertEqual(len(lines), 0, "Must have 0 line for now.")
|
||||
self.assertEqual(draft_picking_qty_in, 0)
|
||||
self.assertEqual(draft_purchase_qty, 5)
|
||||
self.assertEqual(pending_qty_in, 5)
|
||||
|
||||
# Confirms the PO and checks the report again.
|
||||
po.button_confirm()
|
||||
report_values, docs, lines = self.get_report_forecast(product_template_ids=self.product_template.ids)
|
||||
draft_picking_qty_in = docs['draft_picking_qty']['in']
|
||||
draft_purchase_qty = docs['draft_purchase_qty']
|
||||
pending_qty_in = docs['qty']['in']
|
||||
self.assertEqual(len(lines), 1)
|
||||
self.assertEqual(lines[0]['document_in'].id, po.id)
|
||||
self.assertEqual(lines[0]['quantity'], 5)
|
||||
self.assertEqual(lines[0]['document_out'], False)
|
||||
self.assertEqual(draft_picking_qty_in, 0)
|
||||
self.assertEqual(draft_purchase_qty, 0)
|
||||
self.assertEqual(pending_qty_in, 0)
|
||||
|
||||
# Receives 5 products.
|
||||
receipt = po.picking_ids
|
||||
res_dict = receipt.button_validate()
|
||||
wizard = Form(self.env[res_dict['res_model']].with_context(res_dict['context'])).save()
|
||||
wizard.process()
|
||||
report_values, docs, lines = self.get_report_forecast(product_template_ids=self.product_template.ids)
|
||||
draft_picking_qty_in = docs['draft_picking_qty']['in']
|
||||
draft_purchase_qty = docs['draft_purchase_qty']
|
||||
pending_qty_in = docs['qty']['in']
|
||||
self.assertEqual(len(lines), 0)
|
||||
self.assertEqual(draft_picking_qty_in, 0)
|
||||
self.assertEqual(draft_purchase_qty, 0)
|
||||
self.assertEqual(pending_qty_in, 0)
|
||||
|
||||
# Increase the PO quantity to 10, so must create a second receipt.
|
||||
po_form = Form(po)
|
||||
with po_form.order_line.edit(0) as line:
|
||||
line.product_qty = 10
|
||||
po = po_form.save()
|
||||
# Checks the report.
|
||||
report_values, docs, lines = self.get_report_forecast(product_template_ids=self.product_template.ids)
|
||||
draft_picking_qty_in = docs['draft_picking_qty']['in']
|
||||
draft_purchase_qty = docs['draft_purchase_qty']
|
||||
pending_qty_in = docs['qty']['in']
|
||||
self.assertEqual(len(lines), 1, "Must have 1 line for now.")
|
||||
self.assertEqual(lines[0]['document_in'].id, po.id)
|
||||
self.assertEqual(lines[0]['quantity'], 5)
|
||||
self.assertEqual(draft_picking_qty_in, 0)
|
||||
self.assertEqual(draft_purchase_qty, 0)
|
||||
self.assertEqual(pending_qty_in, 0)
|
||||
|
||||
def test_report_forecast_2_purchase_order_three_step_receipt(self):
|
||||
""" Create a PO for 4 product, receive them then increase the quantity
|
||||
to 10, but use three steps receipt.
|
||||
"""
|
||||
grp_multi_loc = self.env.ref('stock.group_stock_multi_locations')
|
||||
grp_multi_routes = self.env.ref('stock.group_adv_location')
|
||||
self.env.user.write({'groups_id': [(4, grp_multi_loc.id)]})
|
||||
self.env.user.write({'groups_id': [(4, grp_multi_routes.id)]})
|
||||
# Configure warehouse.
|
||||
warehouse = self.env.ref('stock.warehouse0')
|
||||
warehouse.reception_steps = 'three_steps'
|
||||
|
||||
po_form = Form(self.env['purchase.order'])
|
||||
po_form.partner_id = self.partner
|
||||
with po_form.order_line.new() as line:
|
||||
line.product_id = self.product
|
||||
line.product_qty = 4
|
||||
po = po_form.save()
|
||||
|
||||
# Checks the report -> Must be empty for now, just display some pending qty.
|
||||
report_values, docs, lines = self.get_report_forecast(product_template_ids=self.product_template.ids)
|
||||
draft_picking_qty_in = docs['draft_picking_qty']['in']
|
||||
draft_purchase_qty = docs['draft_purchase_qty']
|
||||
pending_qty_in = docs['qty']['in']
|
||||
self.assertEqual(len(lines), 0, "Must have 0 line for now.")
|
||||
self.assertEqual(draft_picking_qty_in, 0)
|
||||
self.assertEqual(draft_purchase_qty, 4)
|
||||
self.assertEqual(pending_qty_in, 4)
|
||||
|
||||
# Confirms the PO and checks the report again.
|
||||
po.button_confirm()
|
||||
report_values, docs, lines = self.get_report_forecast(product_template_ids=self.product_template.ids)
|
||||
draft_picking_qty_in = docs['draft_picking_qty']['in']
|
||||
draft_purchase_qty = docs['draft_purchase_qty']
|
||||
pending_qty_in = docs['qty']['in']
|
||||
self.assertEqual(len(lines), 1)
|
||||
self.assertEqual(lines[0]['document_in'].id, po.id)
|
||||
self.assertEqual(lines[0]['quantity'], 4)
|
||||
self.assertEqual(lines[0]['document_out'], False)
|
||||
self.assertEqual(draft_picking_qty_in, 0)
|
||||
self.assertEqual(draft_purchase_qty, 0)
|
||||
self.assertEqual(pending_qty_in, 0)
|
||||
# Get back the different transfers.
|
||||
receipt = po.picking_ids
|
||||
|
||||
# Receives 4 products.
|
||||
res_dict = receipt.button_validate()
|
||||
wizard = Form(self.env[res_dict['res_model']].with_context(res_dict['context'])).save()
|
||||
wizard.process()
|
||||
report_values, docs, lines = self.get_report_forecast(product_template_ids=self.product_template.ids)
|
||||
draft_picking_qty_in = docs['draft_picking_qty']['in']
|
||||
draft_purchase_qty = docs['draft_purchase_qty']
|
||||
pending_qty_in = docs['qty']['in']
|
||||
self.assertEqual(len(lines), 0)
|
||||
self.assertEqual(draft_picking_qty_in, 0)
|
||||
self.assertEqual(draft_purchase_qty, 0)
|
||||
self.assertEqual(pending_qty_in, 0)
|
||||
|
||||
# Increase the PO quantity to 10, so must create a second receipt.
|
||||
po_form = Form(po)
|
||||
with po_form.order_line.edit(0) as line:
|
||||
line.product_qty = 10
|
||||
po = po_form.save()
|
||||
# Checks the report.
|
||||
report_values, docs, lines = self.get_report_forecast(product_template_ids=self.product_template.ids)
|
||||
draft_picking_qty_in = docs['draft_picking_qty']['in']
|
||||
draft_purchase_qty = docs['draft_purchase_qty']
|
||||
pending_qty_in = docs['qty']['in']
|
||||
self.assertEqual(len(lines), 1)
|
||||
self.assertEqual(lines[0]['document_in'].id, po.id)
|
||||
self.assertEqual(lines[0]['quantity'], 6)
|
||||
self.assertEqual(draft_picking_qty_in, 0)
|
||||
self.assertEqual(draft_purchase_qty, 0)
|
||||
self.assertEqual(pending_qty_in, 0)
|
||||
Reference in New Issue
Block a user