52 lines
2.2 KiB
JavaScript
52 lines
2.2 KiB
JavaScript
// @applet-input-schema {"type":"object","properties":{"month":{"type":"string","title":"Month (YYYY-MM)","default":"","description":"Only include orders placed in this month. Leave empty for all months."},"limit":{"type":"integer","title":"Max rows","default":50,"minimum":1,"maximum":500}}}
|
|
// @applet-output-schema month:string;orders:integer;positions:integer;net:number
|
|
// @applet-description "Order revenue by month — orders grouped per calendar month."
|
|
//
|
|
// Order revenue by month — orders grouped per calendar month.
|
|
//
|
|
// Demonstrates: paging, then aggregating into a Map keyed by `YYYY-MM` and rendering a small
|
|
// report. `GET /order` list rows already carry their line items, so no detail call is needed.
|
|
// Endpoints: GET /order (paged).
|
|
|
|
module.exports = async function (applet_input) {
|
|
const only = String(applet_input.month || '').trim();
|
|
const maxRows = Math.max(1, Number(applet_input.limit) || 50);
|
|
|
|
// 1. Page through orders.
|
|
const orders = [];
|
|
let offset = 0;
|
|
for (;;) {
|
|
const res = await fetch(`/order?offset=${offset}&limit=100`);
|
|
if (!res.ok) throw new Error(`GET /order failed: ${res.status}`);
|
|
const data = await res.json();
|
|
const page = data.orders || [];
|
|
orders.push(...page);
|
|
offset += page.length;
|
|
if (page.length === 0 || offset >= (data.total ?? orders.length)) break;
|
|
}
|
|
|
|
// 2. Aggregate per calendar month.
|
|
const buckets = new Map();
|
|
for (const order of orders) {
|
|
const month = String(order.date || '').slice(0, 7);
|
|
if (!month) continue;
|
|
if (only && month !== only) continue;
|
|
const bucket = buckets.get(month) || { month, orders: 0, positions: 0, net: 0 };
|
|
bucket.orders += 1;
|
|
for (const line of order.lines || []) {
|
|
bucket.positions += 1;
|
|
bucket.net += (line.amount || 0) * (line.net || 0);
|
|
}
|
|
buckets.set(month, bucket);
|
|
}
|
|
|
|
const rows = [...buckets.values()]
|
|
.map((b) => ({ ...b, net: Math.round(b.net * 100) / 100 }))
|
|
.sort((a, b) => a.month.localeCompare(b.month))
|
|
.slice(-maxRows);
|
|
|
|
const totalNet = rows.reduce((sum, r) => sum + r.net, 0);
|
|
console.log(`${rows.length} month(s), ${rows.reduce((n, r) => n + r.orders, 0)} order(s), net ${totalNet.toFixed(2)}.`);
|
|
return rows;
|
|
};
|