Fixes to purchase_customer_requisition and shipping info on cust. inv.
purchase_customer_requisition: * Make sure to check the validity (state + dates) on purchase requisitions being selected for PO lines. shipping_information_on_customer_invoice: * Rework how the picking is selected, going through the sale lines related to the invoice lines instead of the non-existing picking_id field previously coded.
This commit is contained in:
parent
dd76c00ec1
commit
4c5b55a7dd
5 changed files with 155 additions and 49 deletions
|
|
@ -53,6 +53,7 @@ class PurchaseOrderLine(models.Model):
|
||||||
def _compute_requisition_id(self):
|
def _compute_requisition_id(self):
|
||||||
for line in self:
|
for line in self:
|
||||||
customer = line._get_customer()
|
customer = line._get_customer()
|
||||||
|
order_date = line.order_id.date_order
|
||||||
domain = [
|
domain = [
|
||||||
"|",
|
"|",
|
||||||
("requisition_id.vendor_id", "=", line.order_id.partner_id.id),
|
("requisition_id.vendor_id", "=", line.order_id.partner_id.id),
|
||||||
|
|
@ -62,6 +63,9 @@ class PurchaseOrderLine(models.Model):
|
||||||
line.order_id.partner_id.id,
|
line.order_id.partner_id.id,
|
||||||
),
|
),
|
||||||
("product_id", "=", line.product_id.id),
|
("product_id", "=", line.product_id.id),
|
||||||
|
("requisition_id.state", "=", "confirmed"),
|
||||||
|
("requisition_id.date_start", "<=", order_date),
|
||||||
|
("requisition_id.date_end", ">=", order_date),
|
||||||
]
|
]
|
||||||
requisition = self.order_id.requisition_id
|
requisition = self.order_id.requisition_id
|
||||||
if customer:
|
if customer:
|
||||||
|
|
|
||||||
|
|
@ -89,7 +89,7 @@ class TestPurchaseOrder(TransactionCase):
|
||||||
"date_end": fields.Date.today() + timedelta(days=265),
|
"date_end": fields.Date.today() + timedelta(days=265),
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
cls.agreement_1.action_confirm()
|
cls.agreement_2.action_confirm()
|
||||||
|
|
||||||
def test_one_purchase_order_line_gets_correct_agreement(self):
|
def test_one_purchase_order_line_gets_correct_agreement(self):
|
||||||
sale_order = self.env["sale.order"].create(
|
sale_order = self.env["sale.order"].create(
|
||||||
|
|
@ -175,3 +175,116 @@ class TestPurchaseOrder(TransactionCase):
|
||||||
line.requisition_id = False
|
line.requisition_id = False
|
||||||
|
|
||||||
self.assertEqual(purchase_order.order_line[0].price_unit, 3000)
|
self.assertEqual(purchase_order.order_line[0].price_unit, 3000)
|
||||||
|
|
||||||
|
def test_requisition_selection_state_and_validity(self):
|
||||||
|
"""Test that requisitions are only selected if they are confirmed and currently valid."""
|
||||||
|
# Create a draft requisition
|
||||||
|
draft_agreement = self.env["purchase.requisition"].create(
|
||||||
|
{
|
||||||
|
"vendor_id": self.supplier.id,
|
||||||
|
"customer_ids": [Command.set([self.client_1.id])],
|
||||||
|
"line_ids": [
|
||||||
|
Command.create(
|
||||||
|
{
|
||||||
|
"product_id": self.product_1.id,
|
||||||
|
"product_qty": 100,
|
||||||
|
"price_unit": 4000,
|
||||||
|
}
|
||||||
|
),
|
||||||
|
],
|
||||||
|
"date_start": fields.Date.today() - timedelta(days=100),
|
||||||
|
"date_end": fields.Date.today() + timedelta(days=265),
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
# Create an expired requisition
|
||||||
|
expired_agreement = self.env["purchase.requisition"].create(
|
||||||
|
{
|
||||||
|
"vendor_id": self.supplier.id,
|
||||||
|
"customer_ids": [Command.set([self.client_1.id])],
|
||||||
|
"line_ids": [
|
||||||
|
Command.create(
|
||||||
|
{
|
||||||
|
"product_id": self.product_1.id,
|
||||||
|
"product_qty": 100,
|
||||||
|
"price_unit": 5000,
|
||||||
|
}
|
||||||
|
),
|
||||||
|
],
|
||||||
|
"date_start": fields.Date.today() - timedelta(days=200),
|
||||||
|
"date_end": fields.Date.today() - timedelta(days=100),
|
||||||
|
}
|
||||||
|
)
|
||||||
|
expired_agreement.action_confirm()
|
||||||
|
|
||||||
|
# Create a future requisition
|
||||||
|
future_agreement = self.env["purchase.requisition"].create(
|
||||||
|
{
|
||||||
|
"vendor_id": self.supplier.id,
|
||||||
|
"customer_ids": [Command.set([self.client_1.id])],
|
||||||
|
"line_ids": [
|
||||||
|
Command.create(
|
||||||
|
{
|
||||||
|
"product_id": self.product_1.id,
|
||||||
|
"product_qty": 100,
|
||||||
|
"price_unit": 6000,
|
||||||
|
}
|
||||||
|
),
|
||||||
|
],
|
||||||
|
"date_start": fields.Date.today() + timedelta(days=100),
|
||||||
|
"date_end": fields.Date.today() + timedelta(days=200),
|
||||||
|
}
|
||||||
|
)
|
||||||
|
future_agreement.action_confirm()
|
||||||
|
|
||||||
|
# Create and confirm a sale order
|
||||||
|
sale_order = self.env["sale.order"].create(
|
||||||
|
{
|
||||||
|
"partner_id": self.client_1.id,
|
||||||
|
"order_line": [
|
||||||
|
Command.create(
|
||||||
|
{
|
||||||
|
"product_id": self.product_1.id,
|
||||||
|
"product_uom_qty": 50,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
],
|
||||||
|
}
|
||||||
|
)
|
||||||
|
sale_order.action_confirm()
|
||||||
|
|
||||||
|
# Verify that the purchase order line gets the correct agreement (agreement_1)
|
||||||
|
purchase_order = sale_order._get_purchase_orders()[0]
|
||||||
|
purchase_line = purchase_order.order_line[0]
|
||||||
|
|
||||||
|
# Should select agreement_1 which is confirmed and currently valid
|
||||||
|
self.assertEqual(
|
||||||
|
purchase_line.requisition_id,
|
||||||
|
self.agreement_1,
|
||||||
|
"Purchase order line should select the confirmed and currently valid agreement",
|
||||||
|
)
|
||||||
|
self.assertEqual(
|
||||||
|
purchase_line.price_unit,
|
||||||
|
1000,
|
||||||
|
"Purchase order line should have the price from the valid agreement",
|
||||||
|
)
|
||||||
|
|
||||||
|
# The other agreements should not be selected because:
|
||||||
|
# - draft_agreement is not confirmed
|
||||||
|
# - expired_agreement is outside its validity dates
|
||||||
|
# - future_agreement hasn't started yet
|
||||||
|
self.assertNotEqual(
|
||||||
|
purchase_line.requisition_id,
|
||||||
|
draft_agreement,
|
||||||
|
"Draft agreement should not be selected",
|
||||||
|
)
|
||||||
|
self.assertNotEqual(
|
||||||
|
purchase_line.requisition_id,
|
||||||
|
expired_agreement,
|
||||||
|
"Expired agreement should not be selected",
|
||||||
|
)
|
||||||
|
self.assertNotEqual(
|
||||||
|
purchase_line.requisition_id,
|
||||||
|
future_agreement,
|
||||||
|
"Future agreement should not be selected",
|
||||||
|
)
|
||||||
|
|
|
||||||
|
|
@ -1,19 +1,19 @@
|
||||||
{
|
{
|
||||||
'name': 'Shipping Information on Customer Invoice',
|
"name": "Shipping Information on Customer Invoice",
|
||||||
'version': '18.0.0.1',
|
"version": "18.0.0.1",
|
||||||
'category': 'Accounting',
|
"category": "Accounting",
|
||||||
'summary': 'Add shipping carrier information on customer invoices',
|
"summary": "Add shipping carrier information on customer invoices",
|
||||||
'description': """
|
"description": """
|
||||||
This module adds shipping carrier information to customer invoices:
|
This module adds shipping carrier information to customer invoices:
|
||||||
* Carrier name
|
* Carrier name
|
||||||
* Tracking number
|
* Tracking number
|
||||||
* Billing mode
|
* Billing mode
|
||||||
""",
|
""",
|
||||||
'depends': ['account', 'delivery'],
|
"depends": ["account", "delivery", "delivery_carrier_partner_account"],
|
||||||
'data': [
|
"data": [
|
||||||
'views/report_invoice.xml',
|
"views/report_invoice.xml",
|
||||||
],
|
],
|
||||||
'installable': True,
|
"installable": True,
|
||||||
'auto_install': False,
|
"auto_install": False,
|
||||||
'license': 'LGPL-3',
|
"license": "LGPL-3",
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,21 +1,17 @@
|
||||||
from odoo import api, fields, models
|
from odoo import api, fields, models
|
||||||
|
|
||||||
|
|
||||||
class AccountMove(models.Model):
|
class AccountMove(models.Model):
|
||||||
_inherit = 'account.move'
|
_inherit = "account.move"
|
||||||
|
|
||||||
def _get_delivery_info(self):
|
picking_id = fields.One2many(
|
||||||
"""Get the delivery information for the invoice."""
|
comodel_name="stock.picking",
|
||||||
self.ensure_one()
|
string="Pickings",
|
||||||
if self.move_type != 'out_invoice':
|
compute="_compute_picking_id",
|
||||||
return False
|
)
|
||||||
|
|
||||||
deliveries = self.picking_ids.filtered(lambda p: p.carrier_id)
|
@api.depends("invoice_line_ids.sale_line_ids.move_ids.picking_id")
|
||||||
if not deliveries:
|
def _compute_picking_id(self):
|
||||||
return False
|
for move in self:
|
||||||
|
pickings = move.invoice_line_ids.mapped("sale_line_ids.move_ids.picking_id")
|
||||||
carrier = deliveries[0].carrier_id
|
move.picking_id = pickings and pickings[0] or False
|
||||||
return {
|
|
||||||
'carrier_name': carrier.name,
|
|
||||||
'tracking_ref': deliveries[0].carrier_tracking_ref or '',
|
|
||||||
'invoice_policy': dict(carrier._fields['invoice_policy'].selection).get(carrier.invoice_policy, carrier.invoice_policy),
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -2,25 +2,18 @@
|
||||||
<odoo>
|
<odoo>
|
||||||
<template id="report_invoice_document_inherit_shipping" inherit_id="account.report_invoice_document">
|
<template id="report_invoice_document_inherit_shipping" inherit_id="account.report_invoice_document">
|
||||||
<xpath expr="//div[@id='informations']" position="inside">
|
<xpath expr="//div[@id='informations']" position="inside">
|
||||||
<t t-if="o._get_delivery_info()">
|
<div class="col-auto col-3 mw-100 mb-2" name="carrier" t-if="o.picking_id.carrier_id">
|
||||||
<div class="col-auto col-3 mw-100 mb-2" name="shipping_info">
|
<strong>Carrier: </strong>
|
||||||
<strong>Shipping Information:</strong>
|
<span t-field="o.picking_id.carrier_id.name"/>
|
||||||
<p class="m-0">
|
</div>
|
||||||
<strong>Carrier: </strong>
|
<div class="col-auto col-3 mw-100 mb-2" name="tracking" t-if="o.picking_id.carrier_tracking_ref">
|
||||||
<span t-esc="o._get_delivery_info()['carrier_name']"/>
|
<strong>Tracking: </strong>
|
||||||
</p>
|
<span t-field="o.picking_id.carrier_tracking_ref"/>
|
||||||
<t t-if="o._get_delivery_info()['tracking_ref']">
|
</div>
|
||||||
<p class="m-0">
|
<div class="col-auto col-3 mw-100 mb-2" name="delivery_billing_mode" t-if="o.picking_id.delivery_billing_mode">
|
||||||
<strong>Tracking: </strong>
|
<strong>Billing Mode: </strong>
|
||||||
<span t-esc="o._get_delivery_info()['tracking_ref']"/>
|
<span t-field="o.picking_id.delivery_billing_mode"/>
|
||||||
</p>
|
</div>
|
||||||
</t>
|
|
||||||
<p class="m-0">
|
|
||||||
<strong>Billing Mode: </strong>
|
|
||||||
<span t-esc="o._get_delivery_info()['invoice_policy']"/>
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</t>
|
|
||||||
</xpath>
|
</xpath>
|
||||||
</template>
|
</template>
|
||||||
</odoo>
|
</odoo>
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue