# 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 = "

%s

" 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 = "

%s

" % 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 += "" 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