purchase_order_product_recommendation_supermarket: calculate by clicking button, instead onchanges. Include order and lines amounts. Last order date for selected vendor.

This commit is contained in:
Luis 2025-06-16 17:34:08 +02:00
parent e2a5a830f3
commit e72fa0d59d
2 changed files with 94 additions and 12 deletions

View file

@ -32,6 +32,22 @@ class PurchaseOrderRecommendationSupermarketWizard(models.TransientModel):
help="Average number of days between orders for this vendor.",
readonly=True,
)
date_last_order = fields.Date(
string="Date of last order",
compute="_compute_avg_days_between_orders",
help="Date of the last order received from the vendor.",
readonly=True,
)
currency_id = fields.Many2one(
related="order_id.currency_id",
readonly=True,
)
order_total_amount = fields.Monetary(
string="Order total amount",
currency_field="currency_id",
compute="_compute_order_total_amount",
readonly=True,
)
@api.depends("date_begin", "date_end")
def _compute_total_days(self):
@ -55,6 +71,8 @@ class PurchaseOrderRecommendationSupermarketWizard(models.TransientModel):
order="date_order asc",
)
self.date_last_order = orders[-1].effective_date.date() if orders else False
dates = [o.date_order.date() for o in orders if o.date_order]
if len(dates) < 2:
self.avg_days_between_orders = 0.0
@ -71,13 +89,28 @@ class PurchaseOrderRecommendationSupermarketWizard(models.TransientModel):
else:
self.avg_days_between_orders = sum(day_diffs) / len(day_diffs)
@api.onchange(
"order_days",
"order_by_packages",
"ignore_zero_stock_days",
)
def _onchange_order_fields(self):
@api.depends("line_ids")
def _compute_order_total_amount(self):
"""Compute the total amount of the order."""
if not self.order_id:
self.order_total_amount = 0.0
return
total_amount = sum(line.subtotal_amount for line in self.line_ids)
self.order_total_amount = total_amount
# Override the method to remove onchange and recalculate only by clicking the button
def _generate_recommendations(self):
super()._generate_recommendations()
def regenerate_recommendations(self):
self._generate_recommendations()
return {
"type": "ir.actions.act_window",
"res_model": self._name,
"res_id": self.id,
"view_mode": "form",
"target": "new",
}
def _prepare_wizard_line(self, vals, order_line=False):
"""Used to create the wizard line"""
@ -96,9 +129,12 @@ class PurchaseOrderRecommendationSupermarketWizard(models.TransientModel):
)
if self.order_days != 0:
qty_to_order = (self.order_days * res["units_avg_delivered"]) - res[
"units_virtual_available"
]
qty_to_order = max(
0,
(self.order_days * res["units_avg_delivered"])
- res["units_virtual_available"],
)
res["units_included_original"] = qty_to_order
# Adjust qty_to_order to packaging multiples if order_by_packages is checked
if self.order_by_packages and product_id.packaging_ids:
@ -146,7 +182,6 @@ class PurchaseOrderRecommendationSupermarketWizard(models.TransientModel):
products = products.filtered(
lambda x: x.categ_id.id in self.product_category_ids.ids
)
print(self.product_category_ids)
return products
@ -167,7 +202,6 @@ class PurchaseOrderRecommendationLine(models.TransientModel):
store=True,
readonly=False,
)
packaging_contained_qty = fields.Float(
string="Packaging Quantity Contained",
help="Quantity of packages to order for this product.",
@ -182,6 +216,28 @@ class PurchaseOrderRecommendationLine(models.TransientModel):
units_scrapped = fields.Float(
readonly=True,
)
subtotal_amount = fields.Monetary(
string="Subtotal Amount",
compute="_compute_subtotal_amount",
readonly=True,
)
units_included_original = fields.Float(
string="Units Included Original",
readonly=True,
)
stock_duration = fields.Float(
string="Stock Duration",
compute="_compute_stock_duration",
readonly=True,
)
@api.depends("units_included", "product_id")
def _compute_subtotal_amount(self):
for rec in self:
if rec.product_id and rec.units_included:
rec.subtotal_amount = rec.units_included * rec.price_unit
else:
rec.subtotal_amount = 0.0
@api.depends("wizard_id.date_begin", "wizard_id.date_end")
def _compute_days_without_stock(self):
@ -215,3 +271,12 @@ class PurchaseOrderRecommendationLine(models.TransientModel):
if rec.product_id and rec.product_id.packaging_ids
else False
)
@api.depends("units_avg_delivered")
def _compute_stock_duration(self):
for rec in self:
rec.stock_duration = (
rec.units_virtual_available / rec.units_avg_delivered
if rec.units_avg_delivered > 0
else 0.0
)

View file

@ -5,20 +5,37 @@
<field name="model">purchase.order.recommendation</field>
<field name="inherit_id" ref="purchase_order_product_recommendation.purchase_order_recommendation_view_form"/>
<field name="arch" type="xml">
<xpath expr="//sheet" position="before">
<header>
<button name="regenerate_recommendations"
string="Calculate"
type="object"
class="btn-primary"
icon="fa-refresh"
context="{'no_return_action': True}"/>
</header>
</xpath>
<field name="date_end" position="after">
<field name="total_days" />
<field name="order_days" widget="numeric_step" />
<field name="avg_days_between_orders" />
<field name="avg_days_between_orders"/>
<field name="date_last_order"/>
</field>
<field name="show_all_products" position="after">
<field name="order_by_packages" />
<field name="ignore_zero_stock_days" />
<field name="order_total_amount" widget="monetary" options="{'currency_field': 'currency_id'}" />
<field name="currency_id" invisible="1"/>
</field>
<field name="units_included" position="before">
<field name="units_scrapped" string="Qty scrapped" optional="hide" />
<field name="stock_duration" string="Stock Duration" optional="hide" />
<field name="days_without_stock" optional="hide" />
<field name="packaging_id" optional="show" />
<field name="packaging_contained_qty" string="Packaging Contained Qty" optional="hide" />
<field name="subtotal_amount" string="Subtotal Amount" optional="hide" />
<field name="units_included_original" string="Qty needed" optional="hide" />
<field name="packaging_qty" string="Packaging Qty" optional="hide" />
</field>
</field>