mirror of
https://github.com/bringout/oca-purchase.git
synced 2026-04-20 03:02:03 +02:00
🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
240 lines
9.1 KiB
Python
240 lines
9.1 KiB
Python
# Copyright 2018-2019 ForgeFlow, S.L.
|
|
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl-3.0)
|
|
|
|
from odoo import _, api, exceptions, fields, models
|
|
|
|
|
|
class PurchaseOrder(models.Model):
|
|
_inherit = "purchase.order"
|
|
|
|
def _purchase_request_confirm_message_content(self, request, request_dict=None):
|
|
self.ensure_one()
|
|
if not request_dict:
|
|
request_dict = {}
|
|
title = _("Order confirmation %(po_name)s for your Request %(pr_name)s") % {
|
|
"po_name": self.name,
|
|
"pr_name": request.name,
|
|
}
|
|
message = "<h3>%s</h3><ul>" % title
|
|
message += _(
|
|
"The following requested items from Purchase Request %(pr_name)s "
|
|
"have now been confirmed in Purchase Order %(po_name)s:"
|
|
) % {
|
|
"po_name": self.name,
|
|
"pr_name": request.name,
|
|
}
|
|
|
|
for line in request_dict.values():
|
|
message += _(
|
|
"<li><b>%(prl_name)s</b>: Ordered quantity %(prl_qty)s %(prl_uom)s, "
|
|
"Planned date %(prl_date_planned)s</li>"
|
|
) % {
|
|
"prl_name": line["name"],
|
|
"prl_qty": line["product_qty"],
|
|
"prl_uom": line["product_uom"],
|
|
"prl_date_planned": line["date_planned"],
|
|
}
|
|
message += "</ul>"
|
|
return message
|
|
|
|
def _purchase_request_confirm_message(self):
|
|
request_obj = self.env["purchase.request"]
|
|
for po in self:
|
|
requests_dict = {}
|
|
for line in po.order_line:
|
|
for request_line in line.sudo().purchase_request_lines:
|
|
request_id = request_line.request_id.id
|
|
if request_id not in requests_dict:
|
|
requests_dict[request_id] = {}
|
|
date_planned = "%s" % line.date_planned
|
|
data = {
|
|
"name": request_line.name,
|
|
"product_qty": line.product_qty,
|
|
"product_uom": line.product_uom.name,
|
|
"date_planned": date_planned,
|
|
}
|
|
requests_dict[request_id][request_line.id] = data
|
|
for request_id in requests_dict:
|
|
request = request_obj.sudo().browse(request_id)
|
|
message = po._purchase_request_confirm_message_content(
|
|
request, requests_dict[request_id]
|
|
)
|
|
request.message_post(
|
|
body=message,
|
|
subtype_id=self.env.ref(
|
|
"purchase_request.mt_request_po_confirmed"
|
|
).id,
|
|
)
|
|
return True
|
|
|
|
def _purchase_request_line_check(self):
|
|
for po in self:
|
|
for line in po.order_line:
|
|
for request_line in line.purchase_request_lines:
|
|
if request_line.sudo().purchase_state == "done":
|
|
raise exceptions.UserError(
|
|
_("Purchase Request %s has already been completed")
|
|
% (request_line.request_id.name)
|
|
)
|
|
return True
|
|
|
|
def button_confirm(self):
|
|
self._purchase_request_line_check()
|
|
res = super(PurchaseOrder, self).button_confirm()
|
|
self._purchase_request_confirm_message()
|
|
return res
|
|
|
|
def unlink(self):
|
|
alloc_to_unlink = self.env["purchase.request.allocation"]
|
|
for rec in self:
|
|
for alloc in (
|
|
rec.order_line.mapped("purchase_request_lines")
|
|
.mapped("purchase_request_allocation_ids")
|
|
.filtered(
|
|
lambda alloc, rec=rec: alloc.purchase_line_id.order_id.id == rec.id
|
|
)
|
|
):
|
|
alloc_to_unlink += alloc
|
|
res = super().unlink()
|
|
alloc_to_unlink.unlink()
|
|
return res
|
|
|
|
|
|
class PurchaseOrderLine(models.Model):
|
|
_inherit = "purchase.order.line"
|
|
|
|
purchase_request_lines = fields.Many2many(
|
|
comodel_name="purchase.request.line",
|
|
relation="purchase_request_purchase_order_line_rel",
|
|
column1="purchase_order_line_id",
|
|
column2="purchase_request_line_id",
|
|
readonly=True,
|
|
copy=False,
|
|
)
|
|
|
|
purchase_request_allocation_ids = fields.One2many(
|
|
comodel_name="purchase.request.allocation",
|
|
inverse_name="purchase_line_id",
|
|
string="Purchase Request Allocation",
|
|
copy=False,
|
|
)
|
|
|
|
def action_open_request_line_tree_view(self):
|
|
"""
|
|
:return dict: dictionary value for created view
|
|
"""
|
|
request_line_ids = []
|
|
for line in self:
|
|
request_line_ids += line.purchase_request_lines.ids
|
|
|
|
domain = [("id", "in", request_line_ids)]
|
|
|
|
return {
|
|
"name": _("Purchase Request Lines"),
|
|
"type": "ir.actions.act_window",
|
|
"res_model": "purchase.request.line",
|
|
"view_mode": "tree,form",
|
|
"domain": domain,
|
|
}
|
|
|
|
def _prepare_stock_moves(self, picking):
|
|
self.ensure_one()
|
|
val = super(PurchaseOrderLine, self)._prepare_stock_moves(picking)
|
|
all_list = []
|
|
for v in val:
|
|
all_ids = self.env["purchase.request.allocation"].search(
|
|
[("purchase_line_id", "=", v["purchase_line_id"])]
|
|
)
|
|
for all_id in all_ids:
|
|
all_list.append((4, all_id.id))
|
|
v["purchase_request_allocation_ids"] = all_list
|
|
return val
|
|
|
|
def update_service_allocations(self, prev_qty_received):
|
|
for rec in self:
|
|
allocation = self.env["purchase.request.allocation"].search(
|
|
[
|
|
("purchase_line_id", "=", rec.id),
|
|
("purchase_line_id.product_id.type", "=", "service"),
|
|
]
|
|
)
|
|
if not allocation:
|
|
return
|
|
qty_left = rec.qty_received - prev_qty_received
|
|
for alloc in allocation:
|
|
allocated_product_qty = alloc.allocated_product_qty
|
|
if not qty_left:
|
|
alloc.purchase_request_line_id._compute_qty()
|
|
break
|
|
if alloc.open_product_qty <= qty_left:
|
|
allocated_product_qty += alloc.open_product_qty
|
|
qty_left -= alloc.open_product_qty
|
|
alloc._notify_allocation(alloc.open_product_qty)
|
|
else:
|
|
allocated_product_qty += qty_left
|
|
alloc._notify_allocation(qty_left)
|
|
qty_left = 0
|
|
alloc.write({"allocated_product_qty": allocated_product_qty})
|
|
|
|
message_data = self._prepare_request_message_data(
|
|
alloc, alloc.purchase_request_line_id, allocated_product_qty
|
|
)
|
|
message = self._purchase_request_confirm_done_message_content(
|
|
message_data
|
|
)
|
|
if message:
|
|
alloc.purchase_request_line_id.request_id.message_post(
|
|
body=message, subtype_id=self.env.ref("mail.mt_note").id
|
|
)
|
|
|
|
alloc.purchase_request_line_id._compute_qty()
|
|
return True
|
|
|
|
@api.model
|
|
def _purchase_request_confirm_done_message_content(self, message_data):
|
|
title = _("Service confirmation for Request %s") % (
|
|
message_data["request_name"]
|
|
)
|
|
message = "<h3>%s</h3>" % title
|
|
message += _(
|
|
"The following requested services from Purchase"
|
|
" Request %(request_name)s requested by %(requestor)s "
|
|
"have now been received:"
|
|
) % {
|
|
"request_name": message_data["request_name"],
|
|
"requestor": message_data["requestor"],
|
|
}
|
|
message += "<ul>"
|
|
message += _(
|
|
"<li><b>%(product_name)s</b>: "
|
|
"Received quantity %(product_qty)s %(product_uom)s</li>"
|
|
) % {
|
|
"product_name": message_data["product_name"],
|
|
"product_qty": message_data["product_qty"],
|
|
"product_uom": message_data["product_uom"],
|
|
}
|
|
message += "</ul>"
|
|
return message
|
|
|
|
def _prepare_request_message_data(self, alloc, request_line, allocated_qty):
|
|
return {
|
|
"request_name": request_line.request_id.name,
|
|
"product_name": request_line.product_id.name_get()[0][1],
|
|
"product_qty": allocated_qty,
|
|
"product_uom": alloc.product_uom_id.name,
|
|
"requestor": request_line.request_id.requested_by.partner_id.name,
|
|
}
|
|
|
|
def write(self, vals):
|
|
# As services do not generate stock move this tweak is required
|
|
# to allocate them.
|
|
prev_qty_received = {}
|
|
if vals.get("qty_received", False):
|
|
service_lines = self.filtered(lambda l: l.product_id.type == "service")
|
|
for line in service_lines:
|
|
prev_qty_received[line.id] = line.qty_received
|
|
res = super(PurchaseOrderLine, self).write(vals)
|
|
if prev_qty_received:
|
|
for line in service_lines:
|
|
line.update_service_allocations(prev_qty_received[line.id])
|
|
return res
|