Files
stock-logistics-warehouse/stock_demand_estimate_matrix/wizards/stock_demand_estimate_wizard.py

264 lines
8.7 KiB
Python

# Copyright 2019 ForgeFlow S.L. (https://www.forgeflow.com)
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).
from odoo import _, api, fields, models
from odoo.exceptions import UserError, ValidationError
from odoo.osv import expression
class StockDemandEstimateSheet(models.TransientModel):
_name = "stock.demand.estimate.sheet"
_description = "Stock Demand Estimate Sheet"
date_start = fields.Date(
string="Date From",
readonly=True,
)
date_end = fields.Date(
string="Date to",
readonly=True,
)
date_range_type_id = fields.Many2one(
string="Date Range Type",
comodel_name="date.range.type",
readonly=True,
)
location_id = fields.Many2one(
comodel_name="stock.location",
string="Location",
readonly=True,
)
line_ids = fields.Many2many(
string="Estimates",
comodel_name="stock.demand.estimate.sheet.line",
relation="stock_demand_estimate_line_rel",
)
product_ids = fields.Many2many(
string="Products",
comodel_name="product.product",
)
@api.onchange(
"date_start",
"date_end",
"date_range_type_id",
)
def _onchange_dates(self):
for sheet in self:
if not all([sheet.date_start, sheet.date_end, sheet.date_range_type_id]):
return
ranges = sheet._get_ranges()
if not ranges:
raise UserError(_("There is no ranges created."))
estimates = self.env["stock.demand.estimate"].search(
[
("product_id", "in", sheet.product_ids.ids),
("date_range_id", "in", ranges.ids),
("location_id", "=", sheet.location_id.id),
]
)
lines = []
for product in sheet.product_ids:
for _range in ranges:
estimate = estimates.filtered(
lambda x: (
x.date_range_id == _range and x.product_id == product
)
)
if estimate:
uom_id = fields.first(estimate).product_uom.id
uom_qty = estimate[0].product_uom_qty
estimate_id = estimate[0].id
else:
uom_id = product.uom_id.id
uom_qty = 0.0
estimate_id = None
lines.append(
(
0,
0,
sheet._get_default_estimate_line(
_range,
product,
uom_id,
uom_qty,
estimate_id=estimate_id,
),
)
)
sheet.line_ids = lines
def _get_ranges(self):
domain_1 = [
"&",
("type_id", "=", self.date_range_type_id.id),
"|",
"&",
("date_start", ">=", self.date_start),
("date_start", "<=", self.date_end),
"&",
("date_end", ">=", self.date_start),
("date_end", "<=", self.date_end),
]
domain_2 = [
"&",
("type_id", "=", self.date_range_type_id.id),
"&",
("date_start", "<=", self.date_start),
("date_end", ">=", self.date_start),
]
domain = expression.OR([domain_1, domain_2])
ranges = self.env["date.range"].search(domain)
return ranges
def _get_default_estimate_line(
self, _range, product, uom_id, uom_qty, estimate_id=None
):
name_y = "{} - {}".format(product.name, product.uom_id.name)
if product.default_code:
name_y += "[{}] {}".format(product.default_code, name_y)
values = {
"value_x": _range.name,
"value_y": name_y,
"date_range_id": _range.id,
"product_id": product.id,
"product_uom": uom_id,
"product_uom_qty": uom_qty,
"location_id": self.location_id.id,
"estimate_id": estimate_id,
}
return values
@api.model
def _prepare_estimate_data(self, line):
return {
"date_range_id": line.date_range_id.id,
"product_id": line.product_id.id,
"location_id": line.location_id.id,
"product_uom_qty": line.product_uom_qty,
"product_uom": line.product_id.uom_id.id,
}
def button_validate(self):
res = []
for line in self.line_ids:
if line.estimate_id:
line.estimate_id.product_uom_qty = line.product_uom_qty
res.append(line.estimate_id.id)
else:
data = self._prepare_estimate_data(line)
estimate = self.env["stock.demand.estimate"].create(data)
res.append(estimate.id)
res = {
"domain": [("id", "in", res)],
"name": _("Stock Demand Estimates"),
"src_model": "stock.demand.estimate.wizard",
"view_type": "form",
"view_mode": "tree",
"res_model": "stock.demand.estimate",
"type": "ir.actions.act_window",
}
return res
class StockDemandEstimateSheetLine(models.TransientModel):
_name = "stock.demand.estimate.sheet.line"
_description = "Stock Demand Estimate Sheet Line"
estimate_id = fields.Many2one(comodel_name="stock.demand.estimate")
date_range_id = fields.Many2one(comodel_name="date.range", string="Period")
location_id = fields.Many2one(
comodel_name="stock.location", string="Stock Location"
)
product_id = fields.Many2one(comodel_name="product.product", string="Product")
value_x = fields.Char(string="Period Name")
value_y = fields.Char(string="Product Name")
product_uom = fields.Many2one(comodel_name="uom.uom", string="Unit of measure")
product_uom_qty = fields.Float(string="Quantity", digits="Product UoM")
class DemandEstimateWizard(models.TransientModel):
_name = "stock.demand.estimate.wizard"
_description = "Stock Demand Estimate Wizard"
date_start = fields.Date(
string="Date From",
required=True,
)
date_end = fields.Date(
string="Date To",
required=True,
)
date_range_type_id = fields.Many2one(
string="Date Range Type",
comodel_name="date.range.type",
required=True,
)
location_id = fields.Many2one(
comodel_name="stock.location",
string="Location",
required=True,
)
product_ids = fields.Many2many(
comodel_name="product.product",
string="Products",
)
@api.onchange("date_range_type_id")
def _onchange_date_range_type_id(self):
if self.date_range_type_id.company_id:
return {
"domain": {
"location_id": [
("company_id", "=", self.date_range_type_id.company_id.id)
]
}
}
return {}
@api.constrains("date_start", "date_end")
def _check_start_end_dates(self):
self.ensure_one()
if self.date_start > self.date_end:
raise ValidationError(
_("The start date cannot be later than the end date.")
)
def _prepare_demand_estimate_sheet(self):
self.ensure_one()
return {
"date_start": self.date_start,
"date_end": self.date_end,
"date_range_type_id": self.date_range_type_id.id,
"location_id": self.location_id.id,
}
def create_sheet(self):
self.ensure_one()
if not self.product_ids:
raise UserError(_("You must select at least one product."))
# 2d matrix widget need real records to work
sheet = self.env["stock.demand.estimate.sheet"].create(
{
"date_start": self.date_start,
"date_end": self.date_end,
"date_range_type_id": self.date_range_type_id.id,
"location_id": self.location_id.id,
"product_ids": [(6, 0, self.product_ids.ids)],
}
)
sheet._onchange_dates()
res = {
"name": _("Estimate Sheet"),
"src_model": "stock.demand.estimate.wizard",
"view_type": "form",
"view_mode": "form",
"target": "new",
"res_model": "stock.demand.estimate.sheet",
"res_id": sheet.id,
"type": "ir.actions.act_window",
}
return res