Fixes for metrics calculations

This commit is contained in:
2026-02-07 21:34:42 -05:00
parent 9b2f9016f6
commit 12cc7a4639
18 changed files with 267 additions and 169 deletions

View File

@@ -17,6 +17,33 @@ async function importOrders(prodConnection, localConnection, incrementalUpdate =
const startTime = Date.now();
const skippedOrders = new Set();
const missingProducts = new Set();
// Map order status codes to text values (consistent with PO status mapping in purchase-orders.js)
const orderStatusMap = {
0: 'created',
10: 'unfinished',
15: 'canceled',
16: 'combined',
20: 'placed',
22: 'placed_incomplete',
30: 'canceled',
40: 'awaiting_payment',
50: 'awaiting_products',
55: 'shipping_later',
56: 'shipping_together',
60: 'ready',
61: 'flagged',
62: 'fix_before_pick',
65: 'manual_picking',
70: 'in_pt',
80: 'picked',
90: 'awaiting_shipment',
91: 'remote_wait',
92: 'awaiting_pickup',
93: 'fix_before_ship',
95: 'shipped_confirmed',
100: 'shipped'
};
let recordsAdded = 0;
let recordsUpdated = 0;
let processedCount = 0;
@@ -284,7 +311,7 @@ async function importOrders(prodConnection, localConnection, incrementalUpdate =
new Date(order.date), // Convert to TIMESTAMP WITH TIME ZONE
order.customer,
toTitleCase(order.customer_name) || '',
order.status.toString(), // Convert status to TEXT
orderStatusMap[order.status] || order.status.toString(), // Map numeric status to text
order.canceled,
order.summary_discount || 0,
order.summary_subtotal || 0,
@@ -587,17 +614,14 @@ async function importOrders(prodConnection, localConnection, incrementalUpdate =
oi.price,
oi.quantity,
(
-- Part 1: Sale Savings for the Line
(oi.base_discount * oi.quantity)
+
-- Part 2: Prorated Points Discount (if applicable)
-- Prorated Points Discount (e.g. loyalty points applied at order level)
CASE
WHEN om.summary_discount_subtotal > 0 AND om.summary_subtotal > 0 THEN
COALESCE(ROUND((om.summary_discount_subtotal * (oi.price * oi.quantity)) / NULLIF(om.summary_subtotal, 0), 4), 0)
ELSE 0
END
+
-- Part 3: Specific Item-Level Discount (only if parent discount affected subtotal)
-- Specific Item-Level Promo Discount (coupon codes, etc.)
COALESCE(ot.promo_discount_sum, 0)
)::NUMERIC(14, 4) as discount,
COALESCE(ot.total_tax, 0)::NUMERIC(14, 4) as tax,
@@ -654,7 +678,7 @@ async function importOrders(prodConnection, localConnection, incrementalUpdate =
o.shipping,
o.customer,
o.customer_name,
o.status.toString(), // Convert status to TEXT
o.status, // Already mapped to text via orderStatusMap
o.canceled,
o.costeach
]);

View File

@@ -77,7 +77,6 @@ async function setupTemporaryTables(connection) {
created_at TIMESTAMP WITH TIME ZONE,
date_online TIMESTAMP WITH TIME ZONE,
first_received TIMESTAMP WITH TIME ZONE,
landing_cost_price NUMERIC(14, 4),
barcode TEXT,
harmonized_tariff_code TEXT,
updated_at TIMESTAMP WITH TIME ZONE,
@@ -172,7 +171,6 @@ async function importMissingProducts(prodConnection, localConnection, missingPid
)
ELSE (SELECT costeach FROM product_inventory WHERE pid = p.pid ORDER BY daterec DESC LIMIT 1)
END AS cost_price,
NULL as landing_cost_price,
s.companyname AS vendor,
CASE
WHEN s.companyname = 'Notions' THEN sid.notions_itemnumber
@@ -242,8 +240,8 @@ async function importMissingProducts(prodConnection, localConnection, missingPid
const batch = prodData.slice(i, i + BATCH_SIZE);
const placeholders = batch.map((_, idx) => {
const base = idx * 50; // 50 columns
return `(${Array.from({ length: 50 }, (_, i) => `$${base + i + 1}`).join(', ')})`;
const base = idx * 49; // 49 columns
return `(${Array.from({ length: 49 }, (_, i) => `$${base + i + 1}`).join(', ')})`;
}).join(',');
const values = batch.flatMap(row => {
@@ -270,7 +268,6 @@ async function importMissingProducts(prodConnection, localConnection, missingPid
validateDate(row.date_created),
validateDate(row.date_ol),
validateDate(row.first_received),
row.landing_cost_price,
row.barcode,
row.harmonized_tariff_code,
validateDate(row.updated_at),
@@ -308,7 +305,7 @@ async function importMissingProducts(prodConnection, localConnection, missingPid
pid, title, description, sku, stock_quantity, preorder_count, notions_inv_count,
price, regular_price, cost_price, vendor, vendor_reference, notions_reference,
brand, line, subline, artist, categories, created_at, date_online, first_received,
landing_cost_price, barcode, harmonized_tariff_code, updated_at, visible,
barcode, harmonized_tariff_code, updated_at, visible,
managing_stock, replenishable, permalink, moq, uom, rating, reviews,
weight, length, width, height, country_of_origin, location, total_sold,
baskets, notifies, date_last_sold, shop_score, primary_iid, image, image_175, image_full, options, tags
@@ -382,7 +379,6 @@ async function materializeCalculations(prodConnection, localConnection, incremen
)
ELSE (SELECT costeach FROM product_inventory WHERE pid = p.pid ORDER BY daterec DESC LIMIT 1)
END AS cost_price,
NULL as landing_cost_price,
s.companyname AS vendor,
CASE
WHEN s.companyname = 'Notions' THEN sid.notions_itemnumber
@@ -457,8 +453,8 @@ async function materializeCalculations(prodConnection, localConnection, incremen
await withRetry(async () => {
const placeholders = batch.map((_, idx) => {
const base = idx * 50; // 50 columns
return `(${Array.from({ length: 50 }, (_, i) => `$${base + i + 1}`).join(', ')})`;
const base = idx * 49; // 49 columns
return `(${Array.from({ length: 49 }, (_, i) => `$${base + i + 1}`).join(', ')})`;
}).join(',');
const values = batch.flatMap(row => {
@@ -485,7 +481,6 @@ async function materializeCalculations(prodConnection, localConnection, incremen
validateDate(row.date_created),
validateDate(row.date_ol),
validateDate(row.first_received),
row.landing_cost_price,
row.barcode,
row.harmonized_tariff_code,
validateDate(row.updated_at),
@@ -522,7 +517,7 @@ async function materializeCalculations(prodConnection, localConnection, incremen
pid, title, description, sku, stock_quantity, preorder_count, notions_inv_count,
price, regular_price, cost_price, vendor, vendor_reference, notions_reference,
brand, line, subline, artist, categories, created_at, date_online, first_received,
landing_cost_price, barcode, harmonized_tariff_code, updated_at, visible,
barcode, harmonized_tariff_code, updated_at, visible,
managing_stock, replenishable, permalink, moq, uom, rating, reviews,
weight, length, width, height, country_of_origin, location, total_sold,
baskets, notifies, date_last_sold, shop_score, primary_iid, image, image_175, image_full, options, tags
@@ -547,7 +542,6 @@ async function materializeCalculations(prodConnection, localConnection, incremen
created_at = EXCLUDED.created_at,
date_online = EXCLUDED.date_online,
first_received = EXCLUDED.first_received,
landing_cost_price = EXCLUDED.landing_cost_price,
barcode = EXCLUDED.barcode,
harmonized_tariff_code = EXCLUDED.harmonized_tariff_code,
updated_at = EXCLUDED.updated_at,
@@ -702,7 +696,6 @@ async function importProducts(prodConnection, localConnection, incrementalUpdate
t.created_at,
t.date_online,
t.first_received,
t.landing_cost_price,
t.barcode,
t.harmonized_tariff_code,
t.updated_at,
@@ -742,8 +735,8 @@ async function importProducts(prodConnection, localConnection, incrementalUpdate
const batch = products.rows.slice(i, i + BATCH_SIZE);
const placeholders = batch.map((_, idx) => {
const base = idx * 49; // 49 columns
return `(${Array.from({ length: 49 }, (_, i) => `$${base + i + 1}`).join(', ')})`;
const base = idx * 48; // 48 columns (no primary_iid in this INSERT)
return `(${Array.from({ length: 48 }, (_, i) => `$${base + i + 1}`).join(', ')})`;
}).join(',');
const values = batch.flatMap(row => {
@@ -770,7 +763,6 @@ async function importProducts(prodConnection, localConnection, incrementalUpdate
validateDate(row.created_at),
validateDate(row.date_online),
validateDate(row.first_received),
row.landing_cost_price,
row.barcode,
row.harmonized_tariff_code,
validateDate(row.updated_at),
@@ -807,7 +799,7 @@ async function importProducts(prodConnection, localConnection, incrementalUpdate
pid, title, description, sku, stock_quantity, preorder_count, notions_inv_count,
price, regular_price, cost_price, vendor, vendor_reference, notions_reference,
brand, line, subline, artist, categories, created_at, date_online, first_received,
landing_cost_price, barcode, harmonized_tariff_code, updated_at, visible,
barcode, harmonized_tariff_code, updated_at, visible,
managing_stock, replenishable, permalink, moq, uom, rating, reviews,
weight, length, width, height, country_of_origin, location, total_sold,
baskets, notifies, date_last_sold, shop_score, image, image_175, image_full, options, tags
@@ -833,7 +825,6 @@ async function importProducts(prodConnection, localConnection, incrementalUpdate
created_at = EXCLUDED.created_at,
date_online = EXCLUDED.date_online,
first_received = EXCLUDED.first_received,
landing_cost_price = EXCLUDED.landing_cost_price,
barcode = EXCLUDED.barcode,
harmonized_tariff_code = EXCLUDED.harmonized_tariff_code,
updated_at = EXCLUDED.updated_at,