Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[16.0][ADD] purchase_duplicate_check: Module added #2516

Open
wants to merge 4 commits into
base: 16.0
Choose a base branch
from

Conversation

geomer198
Copy link

This module adds the following features to the Purchase App:

If there are pending RFQs or Purchase orders with associated incoming stock picking not in the "Done" state for the Product in the PO Line:

  • Add Confirmation Wizard if there's an existing RFQ/undelivered PO for the same products on the RFQ confirmation
  • Add the "Pending orders" field to the PO Line
  • Assign Acitivty for the responsible user to check the associated orders

@geomer198 geomer198 marked this pull request as draft January 15, 2025 23:26
Comment on lines 7 to 31
def _prepare_pending_orders_message(self, product_id):
"""
Prepare pending order line message

:param product_id: product.product record id
:return str: message
"""
message = ""
for order in self:
product_line = order.order_line.filtered(
lambda line: line.product_id.id == product_id
)
if not product_line:
continue

product_qty = sum(product_line.mapped("product_qty"))
order_date = order.create_date.date()
order_href = (
f"<a href='/web#id={order.id}&model={order._name}'>{order.name}</a>"
)
type_ = order.state in ["draft", "sent"] and "RFQ" or "PO"
message += (
f"{type_}: {order_href} date: {order_date} Qty: {product_qty}<br/>"
)
return message
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
def _prepare_pending_orders_message(self, product_id):
"""
Prepare pending order line message
:param product_id: product.product record id
:return str: message
"""
message = ""
for order in self:
product_line = order.order_line.filtered(
lambda line: line.product_id.id == product_id
)
if not product_line:
continue
product_qty = sum(product_line.mapped("product_qty"))
order_date = order.create_date.date()
order_href = (
f"<a href='/web#id={order.id}&model={order._name}'>{order.name}</a>"
)
type_ = order.state in ["draft", "sent"] and "RFQ" or "PO"
message += (
f"{type_}: {order_href} date: {order_date} Qty: {product_qty}<br/>"
)
return message
def _prepare_pending_orders_message(self, product_id):
"""
Prepare pending order line message
:param product_id: product.product record id
:return str: message
"""
self.ensure_one()
order_lines = self.env["purchase.order.line"].search([
('product_id', '=', product_id),
('order_id', 'in', self.ids)
])
message_parts = []
for line in order_lines:
order = line.order_id
order_href = f"<a href='/web#id={order.id}&model={order._name}'>{order.name}</a>"
type_ = "RFQ" if order.state in ["draft", "sent"] else "PO"
message_parts.append(
f"{type_}: {order_href} date: {order.create_date.date()} Qty: {line.product_qty}<br/>"
)
return "".join(message_parts)

Comment on lines 33 to 48
def _check_pending_order(self):
if (
not self.env["ir.config_parameter"]
.sudo()
.get_param(
"purchase_duplicate_check.create_activity_repeating_orders", False
)
):
return
if not self._context.get("skip_rfq_confirmation"):
return (
self.env["confirmation.wizard"]
.with_context(skip_rfq_confirmation=True)
.confirm_pending_order(self)
)
return
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please, create separate method to check settings, e.g.:

def _is_activity_enabled(self):
    """
    Check if activity for repeating orders is enabled.
    :return: bool
    """
    return self.env["ir.config_parameter"].sudo().get_param(
        "purchase_duplicate_check.create_activity_repeating_orders", False
    )

and

def _check_pending_order(self):
    """
    Check for pending orders and trigger confirmation wizard if needed.
    """
    if self._is_activity_enabled() and not self._context.get("skip_rfq_confirmation"):
        return self.env["confirmation.wizard"].with_context(
            skip_rfq_confirmation=True
        ).confirm_pending_order(self)

Comment on lines 50 to 54
def button_confirm(self):
action = self._check_pending_order()
if action is not None:
return action
return super().button_confirm()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

def button_confirm(self):
    """
    Confirm the purchase order.
    :return: action or super
    """
    action = self._check_pending_order()
    return action or super().button_confirm()

return super().button_confirm()


class PurchaseOrderLine(models.Model):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please, create separate file for this model: purchase_order_line.py


def _get_order_confirm_message(self):
"""Get order confirmation message for pending orders"""
message = ""
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

message_parts = []

product_line_msg = pending_orders._prepare_pending_orders_message(
line.product_id.id
)
message += f"""
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

message_parts.append(

Product <b>{line.product_id.name}</b><br/>
{product_line_msg}<br/>
"""
return message
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"".join(message_parts)

if rec.product_type != "product":
rec.pending_order_ids = False
continue
rfq_orders = purchase_order_obj.search(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it is necessary to use the read_group method instead of searching for records in a loop, which will reduce the load and optimize the query into the database.

class ResConfigSettings(models.TransientModel):
_inherit = "res.config.settings"

create_activity_repeating_orders = fields.Boolean(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please, rename create_activity_repeating_orders -> allow_create_activity_repeating_orders

Comment on lines 30 to 39
for record in records:
self.env["mail.activity"].create(
{
"user_id": activity_type.default_user_id.id or self.env.user.id,
"activity_type_id": activity_type.id,
"res_id": record.id,
"res_model_id": model_id,
"note": self.message,
}
)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
for record in records:
self.env["mail.activity"].create(
{
"user_id": activity_type.default_user_id.id or self.env.user.id,
"activity_type_id": activity_type.id,
"res_id": record.id,
"res_model_id": model_id,
"note": self.message,
}
)
message = self.message
user_id = activity_type.default_user_id.id or self.env.user.id
activity_type_id = activity_type.id
activity_vals_list = []
for record in records:
activity_vals_list.append({
"user_id": user_id,
"activity_type_id": activity_type_id,
"res_id": record.id,
"res_model_id": model_id,
"note":message,
})
if activity_vals_list:
self.env["mail.activity"].create(activity_vals_list)

@geomer198 geomer198 marked this pull request as ready for review January 17, 2025 13:37
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants