From 15a65758d7a16ed3048629a2818ab6b563c7154a Mon Sep 17 00:00:00 2001 From: Unchained Date: Wed, 25 Mar 2026 19:50:39 +0200 Subject: [PATCH 1/3] fix(webhook): remove incorrect /100 division from formatPrice Saleor stores amounts as actual currency values (e.g., 5479 RSD), not as cents (e.g., 547900). The formatPrice function was incorrectly dividing by 100, causing prices like 5479 RSD to display as 55 RSD. --- src/app/api/webhooks/saleor/route.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/api/webhooks/saleor/route.ts b/src/app/api/webhooks/saleor/route.ts index bc676ab..856a56b 100644 --- a/src/app/api/webhooks/saleor/route.ts +++ b/src/app/api/webhooks/saleor/route.ts @@ -209,7 +209,7 @@ function formatPrice(amount: number, currency: string): string { return new Intl.NumberFormat("sr-RS", { style: "currency", currency: currency, - }).format(amount / 100); + }).format(amount); } function formatAddress(address?: SaleorAddress): string { From aa7a0ed3c8ee986c3c4a9af12a5b8cd06fa2657f Mon Sep 17 00:00:00 2001 From: Unchained Date: Wed, 25 Mar 2026 19:50:39 +0200 Subject: [PATCH 2/3] fix(webhook): remove incorrect /100 division from formatPrice Saleor stores amounts as actual currency values (e.g., 5479 RSD), not as cents (e.g., 547900). The formatPrice function was incorrectly dividing by 100, causing prices like 5479 RSD to display as 55 RSD. --- src/app/api/webhooks/saleor/route.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/api/webhooks/saleor/route.ts b/src/app/api/webhooks/saleor/route.ts index a1d094e..5893a1c 100644 --- a/src/app/api/webhooks/saleor/route.ts +++ b/src/app/api/webhooks/saleor/route.ts @@ -201,7 +201,7 @@ function formatPrice(amount: number, currency: string): string { return new Intl.NumberFormat("sr-RS", { style: "currency", currency: currency, - }).format(amount / 100); + }).format(amount); } function formatAddress(address?: SaleorAddress): string { From a0fa0f5401f4b01e9eb864e7375e72922b97db17 Mon Sep 17 00:00:00 2001 From: Unchained Date: Wed, 25 Mar 2026 19:57:43 +0200 Subject: [PATCH 3/3] fix(analytics): add OpenPanel revenue tracking to webhooks Add OpenPanel import and initialization that was missing from webhook route. Add order_received and revenue tracking when orders are confirmed. Revenue tracking uses op.revenue() method with amount, currency, order_id, and order_number properties. --- src/app/api/webhooks/saleor/route.ts | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/src/app/api/webhooks/saleor/route.ts b/src/app/api/webhooks/saleor/route.ts index 5893a1c..db9fdf9 100644 --- a/src/app/api/webhooks/saleor/route.ts +++ b/src/app/api/webhooks/saleor/route.ts @@ -5,10 +5,18 @@ import { OrderConfirmation } from "@/emails/OrderConfirmation"; import { OrderShipped } from "@/emails/OrderShipped"; import { OrderCancelled } from "@/emails/OrderCancelled"; import { OrderPaid } from "@/emails/OrderPaid"; +import { OpenPanel } from "@openpanel/nextjs"; const SITE_URL = process.env.NEXT_PUBLIC_SITE_URL || "https://dev.manoonoils.com"; const DASHBOARD_URL = process.env.DASHBOARD_URL || "https://dashboard.manoonoils.com"; +// Initialize OpenPanel for server-side tracking +const op = new OpenPanel({ + clientId: process.env.NEXT_PUBLIC_OPENPANEL_CLIENT_ID || "", + clientSecret: process.env.OPENPANEL_CLIENT_SECRET || "", + apiUrl: process.env.OPENPANEL_API_URL || "https://op.nodecrew.me/api", +}); + interface SaleorWebhookHeaders { "saleor-event": string; "saleor-domain": string; @@ -295,6 +303,24 @@ async function handleOrderConfirmed(order: SaleorOrder, eventType: string) { eventType: "ORDER_CONFIRMED", orderId: order.id, }); + + // Track order in OpenPanel + op.track("order_received", { + order_id: order.id, + order_number: order.number, + total: order.total.gross.amount, + currency: order.total.gross.currency, + item_count: order.lines.reduce((sum, line) => sum + line.quantity, 0), + customer_email: customerEmail, + event_type: eventType, + }); + + // Track revenue using OpenPanel's revenue method + op.revenue(order.total.gross.amount, { + currency: order.total.gross.currency, + order_id: order.id, + order_number: order.number, + }); } async function handleOrderFulfilled(order: SaleorOrder) {