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 6 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
purchase_duplicate_check/__manifest__.py Outdated Show resolved Hide resolved
purchase_duplicate_check/__manifest__.py Outdated Show resolved Hide resolved
purchase_duplicate_check/__manifest__.py Outdated Show resolved Hide resolved
purchase_duplicate_check/models/purchase_order.py Outdated Show resolved Hide resolved
return "".join(message_parts)

def _is_activity_enabled(self) -> bool:
"""Check if activity for repeating orders is enabled"""

Choose a reason for hiding this comment

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

is repeating orders here mean duplicated orders?

Copy link
Author

Choose a reason for hiding this comment

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

is repeating orders here mean duplicated orders?

Yes

Choose a reason for hiding this comment

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

I think let's use duplicated instead of repeating then

compute="_compute_pending_order_ids",
)

def _compute_pending_order_ids(self):

Choose a reason for hiding this comment

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

I think you do need at least @api.depends('product_id') here

Choose a reason for hiding this comment

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

@geomer198 any comment?

Copy link
Author

Choose a reason for hiding this comment

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

@geomer198 any comment?

This compute method have many dependencies, that is why I don't write depends decorator here.

purchase_duplicate_check/tests/test_purchase_order.py Outdated Show resolved Hide resolved
)
type_ = order.state in ["draft", "sent"] and "RFQ" or "PO"
message_parts.append(
f"{type_}: {order_href} date: {order.create_date.date()} Qty: {line.product_qty}<br/>" # noqa

Choose a reason for hiding this comment

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

This will looks like RFQ: PO001 date: 01/01/2025 Qty: 10.0, it would be much better to be shown as RFQ: PO001 orders 10.0 unit, to confirm by 01/01/2025 and PO: PO001 orders 10.0 unit, expected to received by 01/01/2025

Copy link
Author

Choose a reason for hiding this comment

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

This will looks like RFQ: PO001 date: 01/01/2025 Qty: 10.0, it would be much better to be shown as RFQ: PO001 orders 10.0 unit, to confirm by 01/01/2025 and PO: PO001 orders 10.0 unit, expected to received by 01/01/2025

I think this is too much.

Choose a reason for hiding this comment

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

then at least separate the components with - or ;

@hoangtrann
Copy link

test is also failing, please check

@geomer198 geomer198 force-pushed the 16.0-purchase_duplicate_check-add branch from dbfdcd8 to 8477e98 Compare January 20, 2025 12:17
Copy link

@hoangtrann hoangtrann left a comment

Choose a reason for hiding this comment

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

Code LGTM

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants