feat: Display a customer's top 3 purchased products in the POS partner editor.

This commit is contained in:
admin.suherdy 2025-12-03 08:48:28 +07:00
parent 84ae87fdcf
commit ebab33f7a9
4 changed files with 46 additions and 5 deletions

View File

@ -25,3 +25,22 @@ class ResPartner(models.Model):
'price_subtotal_incl': line.price_subtotal_incl, 'price_subtotal_incl': line.price_subtotal_incl,
} for line in order.lines], } for line in order.lines],
} for order in orders] } for order in orders]
@api.model
def get_pos_top_products(self, partner_id):
# SQL query to get top 3 products by quantity for a specific partner
query = """
SELECT
pt.name ->> 'en_US' as product_name,
SUM(pol.qty) as total_qty
FROM pos_order_line pol
JOIN pos_order po ON pol.order_id = po.id
JOIN product_product pp ON pol.product_id = pp.id
JOIN product_template pt ON pp.product_tmpl_id = pt.id
WHERE po.partner_id = %s
GROUP BY pt.name
ORDER BY total_qty DESC
LIMIT 3
"""
self.env.cr.execute(query, (partner_id,))
return self.env.cr.dictfetchall()

View File

@ -9,21 +9,25 @@ patch(PartnerDetailsEdit.prototype, {
setup() { setup() {
super.setup(); super.setup();
this.orm = useService("orm"); this.orm = useService("orm");
this.state = useState({ ...this.state, lastOrders: [] }); this.state = useState({ ...this.state, lastOrders: [], topProducts: [] });
onWillStart(async () => { onWillStart(async () => {
await this.fetchLastOrders(); await this.fetchData();
}); });
}, },
async fetchLastOrders() { async fetchData() {
const partnerId = this.props.partner.id; const partnerId = this.props.partner.id;
if (partnerId) { if (partnerId) {
try { try {
const orders = await this.orm.call("res.partner", "get_pos_last_orders", [partnerId]); const [orders, topProducts] = await Promise.all([
this.orm.call("res.partner", "get_pos_last_orders", [partnerId]),
this.orm.call("res.partner", "get_pos_top_products", [partnerId])
]);
this.state.lastOrders = orders; this.state.lastOrders = orders;
this.state.topProducts = topProducts;
} catch (error) { } catch (error) {
console.error("Error fetching orders:", error); console.error("Error fetching data:", error);
} }
} }
} }

View File

@ -5,6 +5,24 @@
<xpath expr="//section" position="after"> <xpath expr="//section" position="after">
<section class="partner-details-orders d-flex flex-column m-3"> <section class="partner-details-orders d-flex flex-column m-3">
<div class="container"> <div class="container">
<h3 class="mb-3">Top 3 Products</h3>
<t t-if="state.topProducts and state.topProducts.length > 0">
<div class="list-group mb-4">
<t t-foreach="state.topProducts" t-as="product" t-key="product.product_name">
<div class="list-group-item d-flex justify-content-between align-items-center">
<span class="fw-bold" t-esc="product.product_name"/>
<span class="text-muted">
<i class="fa fa-shopping-cart me-1"/>
<strong class="text-dark" style="font-size: 1.1em;"><t t-esc="product.total_qty"/></strong> Units
</span>
</div>
</t>
</div>
</t>
<t t-else="">
<div class="alert alert-info mb-4">No top products found.</div>
</t>
<h3 class="mb-3">Last Orders</h3> <h3 class="mb-3">Last Orders</h3>
<t t-if="state.lastOrders and state.lastOrders.length > 0"> <t t-if="state.lastOrders and state.lastOrders.length > 0">
<div class="list-group"> <div class="list-group">