mirror of
https://github.com/bringout/oca-workflow-process.git
synced 2026-04-19 11:12:02 +02:00
317 lines
10 KiB
Python
317 lines
10 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, fields, models
|
|
from odoo.exceptions import UserError
|
|
|
|
_STATES = [
|
|
("draft", "Draft"),
|
|
("to_approve", "To be approved"),
|
|
("approved", "Approved"),
|
|
("in_progress", "In progress"),
|
|
("done", "Done"),
|
|
("rejected", "Rejected"),
|
|
]
|
|
|
|
|
|
class PurchaseRequest(models.Model):
|
|
|
|
_name = "purchase.request"
|
|
_description = "Purchase Request"
|
|
_mail_post_access = "read"
|
|
_inherit = ["mail.thread", "mail.activity.mixin"]
|
|
_order = "id desc"
|
|
|
|
@api.model
|
|
def _company_get(self):
|
|
return self.env["res.company"].browse(self.env.company.id)
|
|
|
|
@api.model
|
|
def _get_default_requested_by(self):
|
|
return self.env["res.users"].browse(self.env.uid)
|
|
|
|
@api.model
|
|
def _get_default_name(self):
|
|
return self.env["ir.sequence"].next_by_code("purchase.request")
|
|
|
|
@api.model
|
|
def _default_picking_type(self):
|
|
type_obj = self.env["stock.picking.type"]
|
|
company_id = self.env.context.get("company_id") or self.env.company.id
|
|
types = type_obj.search(
|
|
[("code", "=", "incoming"), ("warehouse_id.company_id", "=", company_id)]
|
|
)
|
|
if not types:
|
|
types = type_obj.search(
|
|
[("code", "=", "incoming"), ("warehouse_id", "=", False)]
|
|
)
|
|
return types[:1]
|
|
|
|
@api.depends("state")
|
|
def _compute_is_editable(self):
|
|
for rec in self:
|
|
if rec.state in (
|
|
"to_approve",
|
|
"approved",
|
|
"rejected",
|
|
"in_progress",
|
|
"done",
|
|
):
|
|
rec.is_editable = False
|
|
else:
|
|
rec.is_editable = True
|
|
|
|
name = fields.Char(
|
|
string="Request Reference",
|
|
required=True,
|
|
default=lambda self: _("New"),
|
|
tracking=True,
|
|
)
|
|
is_name_editable = fields.Boolean(
|
|
default=lambda self: self.env.user.has_group("base.group_no_one"),
|
|
)
|
|
origin = fields.Char(string="Source Document")
|
|
date_start = fields.Date(
|
|
string="Creation date",
|
|
help="Date when the user initiated the request.",
|
|
default=fields.Date.context_today,
|
|
tracking=True,
|
|
)
|
|
requested_by = fields.Many2one(
|
|
comodel_name="res.users",
|
|
required=True,
|
|
copy=False,
|
|
tracking=True,
|
|
default=_get_default_requested_by,
|
|
index=True,
|
|
)
|
|
assigned_to = fields.Many2one(
|
|
comodel_name="res.users",
|
|
string="Approver",
|
|
tracking=True,
|
|
domain=lambda self: [
|
|
(
|
|
"groups_id",
|
|
"in",
|
|
self.env.ref("purchase_request.group_purchase_request_manager").id,
|
|
)
|
|
],
|
|
index=True,
|
|
)
|
|
description = fields.Text()
|
|
company_id = fields.Many2one(
|
|
comodel_name="res.company",
|
|
required=False,
|
|
default=_company_get,
|
|
tracking=True,
|
|
)
|
|
line_ids = fields.One2many(
|
|
comodel_name="purchase.request.line",
|
|
inverse_name="request_id",
|
|
string="Products to Purchase",
|
|
readonly=True,
|
|
copy=True,
|
|
tracking=True,
|
|
states={"draft": [("readonly", False)]},
|
|
)
|
|
product_id = fields.Many2one(
|
|
comodel_name="product.product",
|
|
related="line_ids.product_id",
|
|
string="Product",
|
|
readonly=True,
|
|
)
|
|
state = fields.Selection(
|
|
selection=_STATES,
|
|
string="Status",
|
|
index=True,
|
|
tracking=True,
|
|
required=True,
|
|
copy=False,
|
|
default="draft",
|
|
)
|
|
is_editable = fields.Boolean(compute="_compute_is_editable", readonly=True)
|
|
to_approve_allowed = fields.Boolean(compute="_compute_to_approve_allowed")
|
|
picking_type_id = fields.Many2one(
|
|
comodel_name="stock.picking.type",
|
|
string="Picking Type",
|
|
required=True,
|
|
default=_default_picking_type,
|
|
)
|
|
group_id = fields.Many2one(
|
|
comodel_name="procurement.group",
|
|
string="Procurement Group",
|
|
copy=False,
|
|
index=True,
|
|
)
|
|
line_count = fields.Integer(
|
|
string="Purchase Request Line count",
|
|
compute="_compute_line_count",
|
|
readonly=True,
|
|
)
|
|
move_count = fields.Integer(
|
|
string="Stock Move count", compute="_compute_move_count", readonly=True
|
|
)
|
|
purchase_count = fields.Integer(
|
|
string="Purchases count", compute="_compute_purchase_count", readonly=True
|
|
)
|
|
currency_id = fields.Many2one(related="company_id.currency_id", readonly=True)
|
|
estimated_cost = fields.Monetary(
|
|
compute="_compute_estimated_cost",
|
|
string="Total Estimated Cost",
|
|
store=True,
|
|
)
|
|
|
|
@api.depends("line_ids", "line_ids.estimated_cost")
|
|
def _compute_estimated_cost(self):
|
|
for rec in self:
|
|
rec.estimated_cost = sum(rec.line_ids.mapped("estimated_cost"))
|
|
|
|
@api.depends("line_ids")
|
|
def _compute_purchase_count(self):
|
|
for rec in self:
|
|
rec.purchase_count = len(rec.mapped("line_ids.purchase_lines.order_id"))
|
|
|
|
def action_view_purchase_order(self):
|
|
action = self.env["ir.actions.actions"]._for_xml_id("purchase.purchase_rfq")
|
|
lines = self.mapped("line_ids.purchase_lines.order_id")
|
|
if len(lines) > 1:
|
|
action["domain"] = [("id", "in", lines.ids)]
|
|
elif lines:
|
|
action["views"] = [
|
|
(self.env.ref("purchase.purchase_order_form").id, "form")
|
|
]
|
|
action["res_id"] = lines.id
|
|
return action
|
|
|
|
@api.depends("line_ids")
|
|
def _compute_move_count(self):
|
|
for rec in self:
|
|
rec.move_count = len(
|
|
rec.mapped("line_ids.purchase_request_allocation_ids.stock_move_id")
|
|
)
|
|
|
|
def action_view_stock_picking(self):
|
|
action = self.env["ir.actions.actions"]._for_xml_id(
|
|
"stock.action_picking_tree_all"
|
|
)
|
|
# remove default filters
|
|
action["context"] = {}
|
|
lines = self.mapped(
|
|
"line_ids.purchase_request_allocation_ids.stock_move_id.picking_id"
|
|
)
|
|
if len(lines) > 1:
|
|
action["domain"] = [("id", "in", lines.ids)]
|
|
elif lines:
|
|
action["views"] = [(self.env.ref("stock.view_picking_form").id, "form")]
|
|
action["res_id"] = lines.id
|
|
return action
|
|
|
|
@api.depends("line_ids")
|
|
def _compute_line_count(self):
|
|
for rec in self:
|
|
rec.line_count = len(rec.mapped("line_ids"))
|
|
|
|
def action_view_purchase_request_line(self):
|
|
action = (
|
|
self.env.ref("purchase_request.purchase_request_line_form_action")
|
|
.sudo()
|
|
.read()[0]
|
|
)
|
|
lines = self.mapped("line_ids")
|
|
if len(lines) > 1:
|
|
action["domain"] = [("id", "in", lines.ids)]
|
|
elif lines:
|
|
action["views"] = [
|
|
(self.env.ref("purchase_request.purchase_request_line_form").id, "form")
|
|
]
|
|
action["res_id"] = lines.ids[0]
|
|
return action
|
|
|
|
@api.depends("state", "line_ids.product_qty", "line_ids.cancelled")
|
|
def _compute_to_approve_allowed(self):
|
|
for rec in self:
|
|
rec.to_approve_allowed = rec.state == "draft" and any(
|
|
not line.cancelled and line.product_qty for line in rec.line_ids
|
|
)
|
|
|
|
def copy(self, default=None):
|
|
default = dict(default or {})
|
|
self.ensure_one()
|
|
default.update({"state": "draft", "name": self._get_default_name()})
|
|
return super(PurchaseRequest, self).copy(default)
|
|
|
|
@api.model
|
|
def _get_partner_id(self, request):
|
|
user_id = request.assigned_to or self.env.user
|
|
return user_id.partner_id.id
|
|
|
|
@api.model_create_multi
|
|
def create(self, vals_list):
|
|
for vals in vals_list:
|
|
if vals.get("name", _("New")) == _("New"):
|
|
vals["name"] = self._get_default_name()
|
|
requests = super(PurchaseRequest, self).create(vals_list)
|
|
for vals, request in zip(vals_list, requests):
|
|
if vals.get("assigned_to"):
|
|
partner_id = self._get_partner_id(request)
|
|
request.message_subscribe(partner_ids=[partner_id])
|
|
return requests
|
|
|
|
def write(self, vals):
|
|
res = super(PurchaseRequest, self).write(vals)
|
|
for request in self:
|
|
if vals.get("assigned_to"):
|
|
partner_id = self._get_partner_id(request)
|
|
request.message_subscribe(partner_ids=[partner_id])
|
|
return res
|
|
|
|
def _can_be_deleted(self):
|
|
self.ensure_one()
|
|
return self.state == "draft"
|
|
|
|
def unlink(self):
|
|
for request in self:
|
|
if not request._can_be_deleted():
|
|
raise UserError(
|
|
_("You cannot delete a purchase request which is not draft.")
|
|
)
|
|
return super(PurchaseRequest, self).unlink()
|
|
|
|
def button_draft(self):
|
|
self.mapped("line_ids").do_uncancel()
|
|
return self.write({"state": "draft"})
|
|
|
|
def button_to_approve(self):
|
|
self.to_approve_allowed_check()
|
|
return self.write({"state": "to_approve"})
|
|
|
|
def button_approved(self):
|
|
return self.write({"state": "approved"})
|
|
|
|
def button_rejected(self):
|
|
self.mapped("line_ids").do_cancel()
|
|
return self.write({"state": "rejected"})
|
|
|
|
def button_in_progress(self):
|
|
return self.write({"state": "in_progress"})
|
|
|
|
def button_done(self):
|
|
return self.write({"state": "done"})
|
|
|
|
def check_auto_reject(self):
|
|
"""When all lines are cancelled the purchase request should be
|
|
auto-rejected."""
|
|
for pr in self:
|
|
if not pr.line_ids.filtered(lambda l: l.cancelled is False):
|
|
pr.write({"state": "rejected"})
|
|
|
|
def to_approve_allowed_check(self):
|
|
for rec in self:
|
|
if not rec.to_approve_allowed:
|
|
raise UserError(
|
|
_(
|
|
"You can't request an approval for a purchase request "
|
|
"which is empty. (%s)"
|
|
)
|
|
% rec.name
|
|
)
|