u
This commit is contained in:
2
API.md
2
API.md
@@ -185,6 +185,8 @@ The store is exposed as a `LibDashStore` instance (see `src/index.js`). Each met
|
|||||||
- `delete(googleAuthId: number, id: number, tx?: object): Promise<void>`
|
- `delete(googleAuthId: number, id: number, tx?: object): Promise<void>`
|
||||||
- `getById(googleAuthId: number, id: number, tx?: object): Promise<{id: number, number: string, type: string, entityId: number|null, externalNumber: string|null, date: string, lines: Array<{id: number, sku: string|null, name: string|null, pu: number, amount: number, net: number, rebate: number, taxrate: number, comment: string|null}>}>`
|
- `getById(googleAuthId: number, id: number, tx?: object): Promise<{id: number, number: string, type: string, entityId: number|null, externalNumber: string|null, date: string, lines: Array<{id: number, sku: string|null, name: string|null, pu: number, amount: number, net: number, rebate: number, taxrate: number, comment: string|null}>}>`
|
||||||
- `list(googleAuthId: number, opts?: {offset?: number, limit?: number, search?: string, onlyUnpaid?: boolean, onlyUndelivered?: boolean, seekMonths?: number}, tx?: object): Promise<{orders: Array<{id: number, number: string, type: string, entityId: number|null, externalNumber: string|null, date: string, createdAt: string|null, lines: Array<{id: number, sku: string|null, name: string|null, pu: number, amount: number, net: number, rebate: number, taxrate: number, comment: string|null}>}>, total: number, offset: number, limit: number}|Array<object>>`
|
- `list(googleAuthId: number, opts?: {offset?: number, limit?: number, search?: string, onlyUnpaid?: boolean, onlyUndelivered?: boolean, seekMonths?: number}, tx?: object): Promise<{orders: Array<{id: number, number: string, type: string, entityId: number|null, externalNumber: string|null, date: string, createdAt: string|null, lines: Array<{id: number, sku: string|null, name: string|null, pu: number, amount: number, net: number, rebate: number, taxrate: number, comment: string|null}>}>, total: number, offset: number, limit: number}|Array<object>>`
|
||||||
|
- `rebuildSummaries(provider: import('../../providers/provider.js').DatabaseProvider): void`
|
||||||
|
- `syncSummary(): void`
|
||||||
- `update(googleAuthId: number, id: number, patch: {number?: string, date?: string, entityId?: number, externalNumber?: string, lines?: Array<{sku?: string, name?: string, pu?: number, amount: number, net: number, rebate?: number, taxrate: number, comment?: string|null}>}, tx?: object): Promise<{id: number, number: string, type: string, entityId: number|null, externalNumber: string|null, date: string, lines: Array<{id: number, sku: string|null, name: string|null, pu: number, amount: number, net: number, rebate: number, taxrate: number, comment: string|null}>}>`
|
- `update(googleAuthId: number, id: number, patch: {number?: string, date?: string, entityId?: number, externalNumber?: string, lines?: Array<{sku?: string, name?: string, pu?: number, amount: number, net: number, rebate?: number, taxrate: number, comment?: string|null}>}, tx?: object): Promise<{id: number, number: string, type: string, entityId: number|null, externalNumber: string|null, date: string, lines: Array<{id: number, sku: string|null, name: string|null, pu: number, amount: number, net: number, rebate: number, taxrate: number, comment: string|null}>}>`
|
||||||
- [shipment](API.shipment.md)
|
- [shipment](API.shipment.md)
|
||||||
- `create(provider: import('../../providers/provider.js').DatabaseProvider): void`
|
- `create(provider: import('../../providers/provider.js').DatabaseProvider): void`
|
||||||
|
|||||||
18
API.order.md
18
API.order.md
@@ -127,6 +127,24 @@ const orders = await store.order.list(42);
|
|||||||
// => [{ id, number, type, entityId, externalNumber, date, createdAt, lines: [...] }]
|
// => [{ id, number, type, entityId, externalNumber, date, createdAt, lines: [...] }]
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## `order.rebuildSummaries`
|
||||||
|
|
||||||
|
*Source: `src/store/order/rebuildSummaries.js`*
|
||||||
|
|
||||||
|
Rebuilds the `ordersummary` table for the user's selected company.
|
||||||
|
|
||||||
|
**Parameters**
|
||||||
|
|
||||||
|
| Name | Type | Description |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| `provider` | `import('../../providers/provider.js').DatabaseProvider` | |
|
||||||
|
|
||||||
|
## `order.syncSummary`
|
||||||
|
|
||||||
|
*Source: `src/store/order/syncSummary.js`*
|
||||||
|
|
||||||
|
Centralized sync and rebuild logic for the materialized `ordersummary` table.
|
||||||
|
|
||||||
## `order.update`
|
## `order.update`
|
||||||
|
|
||||||
*Source: `src/store/order/update.js`*
|
*Source: `src/store/order/update.js`*
|
||||||
|
|||||||
@@ -98,6 +98,7 @@ import orderGetById from './store/order/getById.js';
|
|||||||
import orderCreate from './store/order/create.js';
|
import orderCreate from './store/order/create.js';
|
||||||
import orderUpdate from './store/order/update.js';
|
import orderUpdate from './store/order/update.js';
|
||||||
import orderDelete from './store/order/delete.js';
|
import orderDelete from './store/order/delete.js';
|
||||||
|
import orderRebuildSummaries from './store/order/rebuildSummaries.js';
|
||||||
import posterminalList from './store/posterminal/list.js';
|
import posterminalList from './store/posterminal/list.js';
|
||||||
import posterminalUpsert from './store/posterminal/upsert.js';
|
import posterminalUpsert from './store/posterminal/upsert.js';
|
||||||
import posterminalDelete from './store/posterminal/delete.js';
|
import posterminalDelete from './store/posterminal/delete.js';
|
||||||
@@ -427,6 +428,7 @@ export default class LibDashStore {
|
|||||||
create: orderCreate(provider),
|
create: orderCreate(provider),
|
||||||
update: orderUpdate(provider),
|
update: orderUpdate(provider),
|
||||||
delete: orderDelete(provider),
|
delete: orderDelete(provider),
|
||||||
|
rebuildSummaries: orderRebuildSummaries(provider),
|
||||||
};
|
};
|
||||||
|
|
||||||
this.posterminal = {
|
this.posterminal = {
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
/** Drop order = reverse of schema create dependency order. */
|
/** Drop order = reverse of schema create dependency order. */
|
||||||
export const TABLES = [
|
export const TABLES = [
|
||||||
|
'ordersummary',
|
||||||
'package',
|
'package',
|
||||||
'shipping',
|
'shipping',
|
||||||
'payment',
|
'payment',
|
||||||
|
|||||||
@@ -1177,6 +1177,44 @@ BEGIN
|
|||||||
END
|
END
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
export const INIT_ORDERSUMMARY = `
|
||||||
|
IF NOT EXISTS (SELECT * FROM sys.tables WHERE name = 'ordersummary')
|
||||||
|
BEGIN
|
||||||
|
CREATE TABLE ordersummary (
|
||||||
|
id INT IDENTITY(1,1) PRIMARY KEY,
|
||||||
|
company_id INT NOT NULL,
|
||||||
|
manifest_id INT NOT NULL CONSTRAINT UQ_ordersummary_manifest UNIQUE,
|
||||||
|
order_number NVARCHAR(100) NOT NULL,
|
||||||
|
order_date DATETIME2 NOT NULL,
|
||||||
|
created_at DATETIME2 NOT NULL CONSTRAINT DF_ordersummary_created_at DEFAULT SYSUTCDATETIME(),
|
||||||
|
entity_id INT NULL,
|
||||||
|
customer_name NVARCHAR(255) NULL,
|
||||||
|
positions INT NOT NULL CONSTRAINT DF_ordersummary_positions DEFAULT 0,
|
||||||
|
gross_total FLOAT NOT NULL CONSTRAINT DF_ordersummary_gross_total DEFAULT 0,
|
||||||
|
paid_total FLOAT NOT NULL CONSTRAINT DF_ordersummary_paid_total DEFAULT 0,
|
||||||
|
ordered_quantity FLOAT NOT NULL CONSTRAINT DF_ordersummary_ordered_quantity DEFAULT 0,
|
||||||
|
shipped_quantity FLOAT NOT NULL CONSTRAINT DF_ordersummary_shipped_quantity DEFAULT 0,
|
||||||
|
is_paid TINYINT NOT NULL CONSTRAINT DF_ordersummary_is_paid DEFAULT 0,
|
||||||
|
is_shipped TINYINT NOT NULL CONSTRAINT DF_ordersummary_is_shipped DEFAULT 0,
|
||||||
|
CONSTRAINT FK_ordersummary_company FOREIGN KEY (company_id) REFERENCES company(id) ON DELETE NO ACTION,
|
||||||
|
CONSTRAINT FK_ordersummary_manifest FOREIGN KEY (manifest_id) REFERENCES manifest(id) ON DELETE CASCADE,
|
||||||
|
CONSTRAINT FK_ordersummary_entity FOREIGN KEY (entity_id) REFERENCES entity(id) ON DELETE SET NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE INDEX IX_ordersummary_company_date
|
||||||
|
ON ordersummary (company_id, order_date DESC, manifest_id DESC);
|
||||||
|
|
||||||
|
CREATE INDEX IX_ordersummary_company_shipped
|
||||||
|
ON ordersummary (company_id, is_shipped);
|
||||||
|
|
||||||
|
CREATE INDEX IX_ordersummary_company_paid
|
||||||
|
ON ordersummary (company_id, is_paid);
|
||||||
|
|
||||||
|
CREATE INDEX IX_ordersummary_company_number
|
||||||
|
ON ordersummary (company_id, order_number);
|
||||||
|
END
|
||||||
|
`;
|
||||||
|
|
||||||
export const INIT_MCP_CLIENT = `
|
export const INIT_MCP_CLIENT = `
|
||||||
IF NOT EXISTS (SELECT * FROM sys.tables WHERE name = 'mcp_client')
|
IF NOT EXISTS (SELECT * FROM sys.tables WHERE name = 'mcp_client')
|
||||||
BEGIN
|
BEGIN
|
||||||
@@ -1299,6 +1337,7 @@ export const SCHEMA_SCRIPTS = [
|
|||||||
INIT_PAYMENT,
|
INIT_PAYMENT,
|
||||||
INIT_SHIPPING,
|
INIT_SHIPPING,
|
||||||
INIT_PACKAGE,
|
INIT_PACKAGE,
|
||||||
|
INIT_ORDERSUMMARY,
|
||||||
INIT_MCP_CLIENT,
|
INIT_MCP_CLIENT,
|
||||||
INIT_MCP_AUTH_CODE,
|
INIT_MCP_AUTH_CODE,
|
||||||
INIT_MCP_TOKEN,
|
INIT_MCP_TOKEN,
|
||||||
|
|||||||
@@ -845,6 +845,37 @@ CREATE TABLE IF NOT EXISTS package (
|
|||||||
);
|
);
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
export const INIT_ORDERSUMMARY = `
|
||||||
|
CREATE TABLE IF NOT EXISTS ordersummary (
|
||||||
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
|
company_id INTEGER NOT NULL,
|
||||||
|
manifest_id INTEGER NOT NULL UNIQUE,
|
||||||
|
order_number TEXT NOT NULL,
|
||||||
|
order_date TEXT NOT NULL,
|
||||||
|
created_at TEXT NOT NULL DEFAULT (${UTC_NOW}),
|
||||||
|
entity_id INTEGER NULL,
|
||||||
|
customer_name TEXT NULL,
|
||||||
|
positions INTEGER NOT NULL DEFAULT 0,
|
||||||
|
gross_total REAL NOT NULL DEFAULT 0,
|
||||||
|
paid_total REAL NOT NULL DEFAULT 0,
|
||||||
|
ordered_quantity REAL NOT NULL DEFAULT 0,
|
||||||
|
shipped_quantity REAL NOT NULL DEFAULT 0,
|
||||||
|
is_paid INTEGER NOT NULL DEFAULT 0,
|
||||||
|
is_shipped INTEGER NOT NULL DEFAULT 0,
|
||||||
|
FOREIGN KEY (company_id) REFERENCES company(id) ON DELETE NO ACTION,
|
||||||
|
FOREIGN KEY (manifest_id) REFERENCES manifest(id) ON DELETE CASCADE,
|
||||||
|
FOREIGN KEY (entity_id) REFERENCES entity(id) ON DELETE SET NULL
|
||||||
|
);
|
||||||
|
CREATE INDEX IF NOT EXISTS IX_ordersummary_company_date
|
||||||
|
ON ordersummary (company_id, order_date DESC, manifest_id DESC);
|
||||||
|
CREATE INDEX IF NOT EXISTS IX_ordersummary_company_shipped
|
||||||
|
ON ordersummary (company_id, is_shipped);
|
||||||
|
CREATE INDEX IF NOT EXISTS IX_ordersummary_company_paid
|
||||||
|
ON ordersummary (company_id, is_paid);
|
||||||
|
CREATE INDEX IF NOT EXISTS IX_ordersummary_company_number
|
||||||
|
ON ordersummary (company_id, order_number);
|
||||||
|
`;
|
||||||
|
|
||||||
export const INIT_MCP_CLIENT = `
|
export const INIT_MCP_CLIENT = `
|
||||||
CREATE TABLE IF NOT EXISTS mcp_client (
|
CREATE TABLE IF NOT EXISTS mcp_client (
|
||||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
@@ -953,6 +984,7 @@ export const SCHEMA_SCRIPTS = [
|
|||||||
INIT_PAYMENT,
|
INIT_PAYMENT,
|
||||||
INIT_SHIPPING,
|
INIT_SHIPPING,
|
||||||
INIT_PACKAGE,
|
INIT_PACKAGE,
|
||||||
|
INIT_ORDERSUMMARY,
|
||||||
INIT_MCP_CLIENT,
|
INIT_MCP_CLIENT,
|
||||||
INIT_MCP_AUTH_CODE,
|
INIT_MCP_AUTH_CODE,
|
||||||
INIT_MCP_TOKEN,
|
INIT_MCP_TOKEN,
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ import taxEnsure from '../tax/ensure.js';
|
|||||||
import { insertLines, normalizeLines, parseDate } from '../manifestLines.js';
|
import { insertLines, normalizeLines, parseDate } from '../manifestLines.js';
|
||||||
import { assertCustomerEntity, loadDoc } from '../manifestDoc/helpers.js';
|
import { assertCustomerEntity, loadDoc } from '../manifestDoc/helpers.js';
|
||||||
import { recordOrderHistory } from '../articlehistory/record.js';
|
import { recordOrderHistory } from '../articlehistory/record.js';
|
||||||
|
import { syncOrderSummary } from './syncSummary.js';
|
||||||
import makeRunner from '../runner.js';
|
import makeRunner from '../runner.js';
|
||||||
|
|
||||||
export default function create(provider) {
|
export default function create(provider) {
|
||||||
@@ -129,6 +130,8 @@ export default function create(provider) {
|
|||||||
id: manifestId,
|
id: manifestId,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
await syncOrderSummary(runner, { companyId, manifestId });
|
||||||
|
|
||||||
return doc;
|
return doc;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -124,97 +124,19 @@ export default function list(provider) {
|
|||||||
|
|
||||||
// Only unpaid (strictly boolean true; overpaid orders also count as unpaid)
|
// Only unpaid (strictly boolean true; overpaid orders also count as unpaid)
|
||||||
if (opts?.onlyUnpaid === true) {
|
if (opts?.onlyUnpaid === true) {
|
||||||
conditions.push(`(
|
conditions.push('COALESCE(os.is_paid, 0) = 0');
|
||||||
COALESCE((
|
|
||||||
SELECT SUM(ma.amount * (ma.net * (1.0 - ma.rebate / 100.0)) * (1.0 + ma.taxrate / 100.0))
|
|
||||||
FROM manifestarticle ma
|
|
||||||
WHERE ma.manifest_id = m.id
|
|
||||||
), 0) = 0
|
|
||||||
OR
|
|
||||||
ABS(
|
|
||||||
COALESCE((
|
|
||||||
SELECT SUM(p.amount)
|
|
||||||
FROM payment p
|
|
||||||
WHERE p.manifest_id = m.id
|
|
||||||
), 0)
|
|
||||||
-
|
|
||||||
COALESCE((
|
|
||||||
SELECT SUM(ma.amount * (ma.net * (1.0 - ma.rebate / 100.0)) * (1.0 + ma.taxrate / 100.0))
|
|
||||||
FROM manifestarticle ma
|
|
||||||
WHERE ma.manifest_id = m.id
|
|
||||||
), 0)
|
|
||||||
) >= 0.01
|
|
||||||
)`);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Only undelivered (strictly boolean true)
|
// Only undelivered (strictly boolean true)
|
||||||
if (opts?.onlyUndelivered === true) {
|
if (opts?.onlyUndelivered === true) {
|
||||||
const prefixRes = await runner.query(sqlShipmentPrefix, { companyId });
|
conditions.push('COALESCE(os.is_shipped, 0) = 0');
|
||||||
params.shipmentPrefix = prefixRes.rows[0]?.prefix?.trim?.() || '-L-';
|
|
||||||
|
|
||||||
if (isSqlite) {
|
|
||||||
conditions.push(`NOT (
|
|
||||||
(
|
|
||||||
COALESCE((SELECT SUM(ma.amount) FROM manifestarticle ma WHERE ma.manifest_id = m.id), 0) > 0
|
|
||||||
AND
|
|
||||||
COALESCE((
|
|
||||||
SELECT SUM(ma_s.amount)
|
|
||||||
FROM manifest m_s
|
|
||||||
JOIN manifestarticle ma_s ON ma_s.manifest_id = m_s.id
|
|
||||||
WHERE m_s.company_id = m.company_id
|
|
||||||
AND m_s."type" = 'shipment'
|
|
||||||
AND m_s."number" LIKE (m."number" || @shipmentPrefix || '%')
|
|
||||||
), 0) >= (SELECT SUM(ma.amount) FROM manifestarticle ma WHERE ma.manifest_id = m.id) - 0.001
|
|
||||||
)
|
|
||||||
OR EXISTS (
|
|
||||||
SELECT 1 FROM shipping s
|
|
||||||
WHERE (
|
|
||||||
s.manifest_id = m.id
|
|
||||||
OR s.manifest_id IN (
|
|
||||||
SELECT m_s.id FROM manifest m_s
|
|
||||||
WHERE m_s.company_id = m.company_id
|
|
||||||
AND m_s."type" = 'shipment'
|
|
||||||
AND m_s."number" LIKE (m."number" || @shipmentPrefix || '%')
|
|
||||||
)
|
|
||||||
)
|
|
||||||
AND LOWER(s."state") IN ('shipped', 'delivered')
|
|
||||||
)
|
|
||||||
)`);
|
|
||||||
} else {
|
|
||||||
conditions.push(`NOT (
|
|
||||||
(
|
|
||||||
COALESCE((SELECT SUM(ma.amount) FROM manifestarticle ma WHERE ma.manifest_id = m.id), 0) > 0
|
|
||||||
AND
|
|
||||||
COALESCE((
|
|
||||||
SELECT SUM(ma_s.amount)
|
|
||||||
FROM manifest m_s
|
|
||||||
JOIN manifestarticle ma_s ON ma_s.manifest_id = m_s.id
|
|
||||||
WHERE m_s.company_id = m.company_id
|
|
||||||
AND m_s.[type] = 'shipment'
|
|
||||||
AND m_s.[number] LIKE (m.[number] + @shipmentPrefix + '%')
|
|
||||||
), 0) >= (SELECT SUM(ma.amount) FROM manifestarticle ma WHERE ma.manifest_id = m.id) - 0.001
|
|
||||||
)
|
|
||||||
OR EXISTS (
|
|
||||||
SELECT 1 FROM shipping s
|
|
||||||
WHERE (
|
|
||||||
s.manifest_id = m.id
|
|
||||||
OR s.manifest_id IN (
|
|
||||||
SELECT m_s.id FROM manifest m_s
|
|
||||||
WHERE m_s.company_id = m.company_id
|
|
||||||
AND m_s.[type] = 'shipment'
|
|
||||||
AND m_s.[number] LIKE (m.[number] + @shipmentPrefix + '%')
|
|
||||||
)
|
|
||||||
)
|
|
||||||
AND LOWER(s.[state]) IN ('shipped', 'delivered')
|
|
||||||
)
|
|
||||||
)`);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const whereClause = conditions.join('\n AND ');
|
const whereClause = conditions.join('\n AND ');
|
||||||
const sqlCount = `
|
const sqlCount = `
|
||||||
SELECT COUNT(*) AS total
|
SELECT COUNT(*) AS total
|
||||||
FROM manifest m
|
FROM manifest m
|
||||||
|
LEFT JOIN ordersummary os ON os.manifest_id = m.id
|
||||||
LEFT JOIN entity e ON e.id = m.entity_id
|
LEFT JOIN entity e ON e.id = m.entity_id
|
||||||
WHERE ${whereClause}
|
WHERE ${whereClause}
|
||||||
`;
|
`;
|
||||||
@@ -229,8 +151,17 @@ export default function list(provider) {
|
|||||||
m.entity_id AS entityId,
|
m.entity_id AS entityId,
|
||||||
m.external_number AS externalNumber,
|
m.external_number AS externalNumber,
|
||||||
m."date",
|
m."date",
|
||||||
m.created_at AS createdAt
|
m.created_at AS createdAt,
|
||||||
|
os.positions,
|
||||||
|
os.gross_total AS grossTotal,
|
||||||
|
os.paid_total AS paidTotal,
|
||||||
|
os.ordered_quantity AS orderedQuantity,
|
||||||
|
os.shipped_quantity AS shippedQuantity,
|
||||||
|
os.is_paid AS isPaid,
|
||||||
|
os.is_shipped AS isShipped,
|
||||||
|
os.customer_name AS customerName
|
||||||
FROM manifest m
|
FROM manifest m
|
||||||
|
LEFT JOIN ordersummary os ON os.manifest_id = m.id
|
||||||
LEFT JOIN entity e ON e.id = m.entity_id
|
LEFT JOIN entity e ON e.id = m.entity_id
|
||||||
WHERE ${whereClause}
|
WHERE ${whereClause}
|
||||||
ORDER BY m."date" DESC, m.id DESC
|
ORDER BY m."date" DESC, m.id DESC
|
||||||
@@ -245,8 +176,17 @@ export default function list(provider) {
|
|||||||
m.entity_id AS entityId,
|
m.entity_id AS entityId,
|
||||||
m.external_number AS externalNumber,
|
m.external_number AS externalNumber,
|
||||||
m.[date],
|
m.[date],
|
||||||
m.created_at AS createdAt
|
m.created_at AS createdAt,
|
||||||
|
os.positions,
|
||||||
|
os.gross_total AS grossTotal,
|
||||||
|
os.paid_total AS paidTotal,
|
||||||
|
os.ordered_quantity AS orderedQuantity,
|
||||||
|
os.shipped_quantity AS shippedQuantity,
|
||||||
|
os.is_paid AS isPaid,
|
||||||
|
os.is_shipped AS isShipped,
|
||||||
|
os.customer_name AS customerName
|
||||||
FROM manifest m
|
FROM manifest m
|
||||||
|
LEFT JOIN ordersummary os ON os.manifest_id = m.id
|
||||||
LEFT JOIN entity e ON e.id = m.entity_id
|
LEFT JOIN entity e ON e.id = m.entity_id
|
||||||
WHERE ${whereClause}
|
WHERE ${whereClause}
|
||||||
ORDER BY m.[date] DESC, m.id DESC
|
ORDER BY m.[date] DESC, m.id DESC
|
||||||
@@ -292,6 +232,14 @@ export default function list(provider) {
|
|||||||
const orders = manifestRows.map((row) => ({
|
const orders = manifestRows.map((row) => ({
|
||||||
...shapeSummary(orderType, row),
|
...shapeSummary(orderType, row),
|
||||||
lines: linesByManifestId.get(row.id) ?? [],
|
lines: linesByManifestId.get(row.id) ?? [],
|
||||||
|
positions: row.positions !== undefined && row.positions !== null ? Number(row.positions) : undefined,
|
||||||
|
grossTotal: row.grossTotal !== undefined && row.grossTotal !== null ? Number(row.grossTotal) : undefined,
|
||||||
|
paidTotal: row.paidTotal !== undefined && row.paidTotal !== null ? Number(row.paidTotal) : undefined,
|
||||||
|
orderedQuantity: row.orderedQuantity !== undefined && row.orderedQuantity !== null ? Number(row.orderedQuantity) : undefined,
|
||||||
|
shippedQuantity: row.shippedQuantity !== undefined && row.shippedQuantity !== null ? Number(row.shippedQuantity) : undefined,
|
||||||
|
isPaid: row.isPaid !== undefined && row.isPaid !== null ? Boolean(row.isPaid) : undefined,
|
||||||
|
isShipped: row.isShipped !== undefined && row.isShipped !== null ? Boolean(row.isShipped) : undefined,
|
||||||
|
customerName: row.customerName ?? undefined,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
if (isPaged) {
|
if (isPaged) {
|
||||||
|
|||||||
19
src/store/order/rebuildSummaries.js
Normal file
19
src/store/order/rebuildSummaries.js
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
import resolveSelectedCompanyAccess from '../companyuser/resolveSelectedCompanyAccess.js';
|
||||||
|
import makeRunner from '../runner.js';
|
||||||
|
import { rebuildOrderSummaries } from './syncSummary.js';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Rebuilds the `ordersummary` table for the user's selected company.
|
||||||
|
*
|
||||||
|
* @param {import('../../providers/provider.js').DatabaseProvider} provider
|
||||||
|
*/
|
||||||
|
export default function rebuildSummaries(provider) {
|
||||||
|
const access = resolveSelectedCompanyAccess(provider);
|
||||||
|
|
||||||
|
return async (googleAuthId, tx) => {
|
||||||
|
const runner = makeRunner(provider, tx);
|
||||||
|
const { companyId } = await access(googleAuthId, runner);
|
||||||
|
await rebuildOrderSummaries(runner, companyId);
|
||||||
|
return { ok: true, companyId };
|
||||||
|
};
|
||||||
|
}
|
||||||
364
src/store/order/syncSummary.js
Normal file
364
src/store/order/syncSummary.js
Normal file
@@ -0,0 +1,364 @@
|
|||||||
|
/**
|
||||||
|
* Centralized sync and rebuild logic for the materialized `ordersummary` table.
|
||||||
|
*/
|
||||||
|
|
||||||
|
const SQL_GET_SHIPMENT_PREFIX = `
|
||||||
|
SELECT prefix FROM numbers WHERE company_id = @companyId AND [type] = 'shipment'
|
||||||
|
`;
|
||||||
|
|
||||||
|
const SQL_GET_ORDER_BY_ID_SQLITE = `
|
||||||
|
SELECT m.id, m.company_id, m."number", m."date", m.created_at, m.entity_id
|
||||||
|
FROM manifest m
|
||||||
|
WHERE m.id = @manifestId AND m.company_id = @companyId AND m."type" = 'order'
|
||||||
|
`;
|
||||||
|
|
||||||
|
const SQL_GET_ORDER_BY_ID_MSSQL = `
|
||||||
|
SELECT m.id, m.company_id, m.[number], m.[date], m.created_at, m.entity_id
|
||||||
|
FROM manifest m
|
||||||
|
WHERE m.id = @manifestId AND m.company_id = @companyId AND m.[type] = 'order'
|
||||||
|
`;
|
||||||
|
|
||||||
|
const SQL_GET_ORDER_BY_NUMBER_SQLITE = `
|
||||||
|
SELECT m.id, m.company_id, m."number", m."date", m.created_at, m.entity_id
|
||||||
|
FROM manifest m
|
||||||
|
WHERE m."number" = @number AND m.company_id = @companyId AND m."type" = 'order'
|
||||||
|
`;
|
||||||
|
|
||||||
|
const SQL_GET_ORDER_BY_NUMBER_MSSQL = `
|
||||||
|
SELECT m.id, m.company_id, m.[number], m.[date], m.created_at, m.entity_id
|
||||||
|
FROM manifest m
|
||||||
|
WHERE m.[number] = @number AND m.company_id = @companyId AND m.[type] = 'order'
|
||||||
|
`;
|
||||||
|
|
||||||
|
const SQL_LINE_TOTALS = `
|
||||||
|
SELECT
|
||||||
|
COUNT(*) AS positions,
|
||||||
|
COALESCE(SUM(amount), 0) AS ordered_quantity,
|
||||||
|
COALESCE(SUM(amount * (net * (1.0 - rebate / 100.0)) * (1.0 + taxrate / 100.0)), 0) AS gross_total
|
||||||
|
FROM manifestarticle
|
||||||
|
WHERE manifest_id = @manifestId
|
||||||
|
`;
|
||||||
|
|
||||||
|
const SQL_PAYMENT_TOTAL = `
|
||||||
|
SELECT COALESCE(SUM(amount), 0) AS paid_total
|
||||||
|
FROM payment
|
||||||
|
WHERE manifest_id = @manifestId
|
||||||
|
`;
|
||||||
|
|
||||||
|
const SQL_SHIPPED_QTY_SQLITE = `
|
||||||
|
SELECT COALESCE(SUM(ma_s.amount), 0) AS shipped_quantity
|
||||||
|
FROM manifest m_s
|
||||||
|
JOIN manifestarticle ma_s ON ma_s.manifest_id = m_s.id
|
||||||
|
WHERE m_s.company_id = @companyId
|
||||||
|
AND m_s."type" = 'shipment'
|
||||||
|
AND m_s."number" >= (@orderNumber || @shipmentPrefix)
|
||||||
|
AND m_s."number" < (@orderNumber || @shipmentPrefix || char(127))
|
||||||
|
`;
|
||||||
|
|
||||||
|
const SQL_SHIPPED_QTY_MSSQL = `
|
||||||
|
SELECT COALESCE(SUM(ma_s.amount), 0) AS shipped_quantity
|
||||||
|
FROM manifest m_s
|
||||||
|
JOIN manifestarticle ma_s ON ma_s.manifest_id = m_s.id
|
||||||
|
WHERE m_s.company_id = @companyId
|
||||||
|
AND m_s.[type] = 'shipment'
|
||||||
|
AND m_s.[number] >= (@orderNumber + @shipmentPrefix)
|
||||||
|
AND m_s.[number] < (@orderNumber + @shipmentPrefix + NCHAR(127))
|
||||||
|
`;
|
||||||
|
|
||||||
|
const SQL_CUSTOMER_NAME_SQLITE = `
|
||||||
|
SELECT TRIM(COALESCE(first_name || ' ', '') || COALESCE(name, '')) AS customer_name
|
||||||
|
FROM entity
|
||||||
|
WHERE id = @entityId
|
||||||
|
`;
|
||||||
|
|
||||||
|
const SQL_CUSTOMER_NAME_MSSQL = `
|
||||||
|
SELECT LTRIM(RTRIM(ISNULL(first_name + ' ', '') + ISNULL(name, ''))) AS customer_name
|
||||||
|
FROM entity
|
||||||
|
WHERE id = @entityId
|
||||||
|
`;
|
||||||
|
|
||||||
|
const SQL_UPSERT_SUMMARY_SQLITE = `
|
||||||
|
INSERT INTO ordersummary (
|
||||||
|
company_id, manifest_id, order_number, order_date, created_at,
|
||||||
|
entity_id, customer_name, positions, gross_total, paid_total,
|
||||||
|
ordered_quantity, shipped_quantity, is_paid, is_shipped
|
||||||
|
) VALUES (
|
||||||
|
@companyId, @manifestId, @orderNumber, @orderDate, @createdAt,
|
||||||
|
@entityId, @customerName, @positions, @grossTotal, @paidTotal,
|
||||||
|
@orderedQuantity, @shippedQuantity, @isPaid, @isShipped
|
||||||
|
)
|
||||||
|
ON CONFLICT(manifest_id) DO UPDATE SET
|
||||||
|
order_number = excluded.order_number,
|
||||||
|
order_date = excluded.order_date,
|
||||||
|
created_at = excluded.created_at,
|
||||||
|
entity_id = excluded.entity_id,
|
||||||
|
customer_name = excluded.customer_name,
|
||||||
|
positions = excluded.positions,
|
||||||
|
gross_total = excluded.gross_total,
|
||||||
|
paid_total = excluded.paid_total,
|
||||||
|
ordered_quantity = excluded.ordered_quantity,
|
||||||
|
shipped_quantity = excluded.shipped_quantity,
|
||||||
|
is_paid = excluded.is_paid,
|
||||||
|
is_shipped = excluded.is_shipped
|
||||||
|
`;
|
||||||
|
|
||||||
|
const SQL_UPSERT_SUMMARY_MSSQL = `
|
||||||
|
MERGE INTO ordersummary AS target
|
||||||
|
USING (SELECT @manifestId AS manifest_id) AS source
|
||||||
|
ON (target.manifest_id = source.manifest_id)
|
||||||
|
WHEN MATCHED THEN
|
||||||
|
UPDATE SET
|
||||||
|
order_number = @orderNumber,
|
||||||
|
order_date = @orderDate,
|
||||||
|
created_at = @createdAt,
|
||||||
|
entity_id = @entityId,
|
||||||
|
customer_name = @customerName,
|
||||||
|
positions = @positions,
|
||||||
|
gross_total = @grossTotal,
|
||||||
|
paid_total = @paidTotal,
|
||||||
|
ordered_quantity = @orderedQuantity,
|
||||||
|
shipped_quantity = @shippedQuantity,
|
||||||
|
is_paid = @isPaid,
|
||||||
|
is_shipped = @isShipped
|
||||||
|
WHEN NOT MATCHED THEN
|
||||||
|
INSERT (
|
||||||
|
company_id, manifest_id, order_number, order_date, created_at,
|
||||||
|
entity_id, customer_name, positions, gross_total, paid_total,
|
||||||
|
ordered_quantity, shipped_quantity, is_paid, is_shipped
|
||||||
|
) VALUES (
|
||||||
|
@companyId, @manifestId, @orderNumber, @orderDate, @createdAt,
|
||||||
|
@entityId, @customerName, @positions, @grossTotal, @paidTotal,
|
||||||
|
@orderedQuantity, @shippedQuantity, @isPaid, @isShipped
|
||||||
|
);
|
||||||
|
`;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Recalculates and upserts a single order summary into `ordersummary`.
|
||||||
|
*
|
||||||
|
* @param {object} runner - Database runner.
|
||||||
|
* @param {object} opts
|
||||||
|
* @param {number} opts.companyId
|
||||||
|
* @param {number} [opts.manifestId] - Order manifest id.
|
||||||
|
* @param {string} [opts.orderNumber] - Order number (if manifestId not given).
|
||||||
|
*/
|
||||||
|
export async function syncOrderSummary(runner, { companyId, manifestId, orderNumber }) {
|
||||||
|
const isSqlite = runner.dialect === 'sqlite3';
|
||||||
|
|
||||||
|
let orderRow;
|
||||||
|
if (manifestId) {
|
||||||
|
const res = await runner.query(
|
||||||
|
isSqlite ? SQL_GET_ORDER_BY_ID_SQLITE : SQL_GET_ORDER_BY_ID_MSSQL,
|
||||||
|
{ manifestId, companyId },
|
||||||
|
);
|
||||||
|
orderRow = res.rows[0];
|
||||||
|
} else if (orderNumber) {
|
||||||
|
const res = await runner.query(
|
||||||
|
isSqlite ? SQL_GET_ORDER_BY_NUMBER_SQLITE : SQL_GET_ORDER_BY_NUMBER_MSSQL,
|
||||||
|
{ number: orderNumber, companyId },
|
||||||
|
);
|
||||||
|
orderRow = res.rows[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!orderRow) {
|
||||||
|
if (manifestId) {
|
||||||
|
await runner.query('DELETE FROM ordersummary WHERE manifest_id = @manifestId', { manifestId });
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const orderId = orderRow.id;
|
||||||
|
const num = orderRow.number;
|
||||||
|
|
||||||
|
const prefixRes = await runner.query(SQL_GET_SHIPMENT_PREFIX, { companyId });
|
||||||
|
const shipmentPrefix = prefixRes.rows[0]?.prefix?.trim?.() || '-L-';
|
||||||
|
|
||||||
|
const [lineRes, payRes, shipRes] = await Promise.all([
|
||||||
|
runner.query(SQL_LINE_TOTALS, { manifestId: orderId }),
|
||||||
|
runner.query(SQL_PAYMENT_TOTAL, { manifestId: orderId }),
|
||||||
|
runner.query(isSqlite ? SQL_SHIPPED_QTY_SQLITE : SQL_SHIPPED_QTY_MSSQL, {
|
||||||
|
companyId,
|
||||||
|
orderNumber: num,
|
||||||
|
shipmentPrefix,
|
||||||
|
}),
|
||||||
|
]);
|
||||||
|
|
||||||
|
let customerName = null;
|
||||||
|
if (orderRow.entity_id) {
|
||||||
|
const custRes = await runner.query(
|
||||||
|
isSqlite ? SQL_CUSTOMER_NAME_SQLITE : SQL_CUSTOMER_NAME_MSSQL,
|
||||||
|
{ entityId: orderRow.entity_id },
|
||||||
|
);
|
||||||
|
customerName = custRes.rows[0]?.customer_name || null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const positions = Number(lineRes.rows[0]?.positions || 0);
|
||||||
|
const orderedQuantity = Math.round(Number(lineRes.rows[0]?.ordered_quantity || 0) * 1000) / 1000;
|
||||||
|
const grossTotal = Math.round(Number(lineRes.rows[0]?.gross_total || 0) * 100) / 100;
|
||||||
|
const paidTotal = Math.round(Number(payRes.rows[0]?.paid_total || 0) * 100) / 100;
|
||||||
|
const shippedQuantity = Math.round(Number(shipRes.rows[0]?.shipped_quantity || 0) * 1000) / 1000;
|
||||||
|
|
||||||
|
const isPaid = grossTotal > 0 && Math.abs(paidTotal - grossTotal) < 0.01 ? 1 : 0;
|
||||||
|
const isShipped = orderedQuantity > 0 && Math.abs(shippedQuantity - orderedQuantity) < 0.001 ? 1 : 0;
|
||||||
|
|
||||||
|
await runner.query(isSqlite ? SQL_UPSERT_SUMMARY_SQLITE : SQL_UPSERT_SUMMARY_MSSQL, {
|
||||||
|
companyId,
|
||||||
|
manifestId: orderId,
|
||||||
|
orderNumber: num,
|
||||||
|
orderDate: orderRow.date,
|
||||||
|
createdAt: orderRow.created_at,
|
||||||
|
entityId: orderRow.entity_id ?? null,
|
||||||
|
customerName,
|
||||||
|
positions,
|
||||||
|
grossTotal,
|
||||||
|
paidTotal,
|
||||||
|
orderedQuantity,
|
||||||
|
shippedQuantity,
|
||||||
|
isPaid,
|
||||||
|
isShipped,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Full rebuild of all orders in `ordersummary` for a given company.
|
||||||
|
*
|
||||||
|
* @param {object} runner
|
||||||
|
* @param {number} companyId
|
||||||
|
*/
|
||||||
|
export async function rebuildOrderSummaries(runner, companyId) {
|
||||||
|
const isSqlite = runner.dialect === 'sqlite3';
|
||||||
|
|
||||||
|
const prefixRes = await runner.query(SQL_GET_SHIPMENT_PREFIX, { companyId });
|
||||||
|
const shipmentPrefix = prefixRes.rows[0]?.prefix?.trim?.() || '-L-';
|
||||||
|
|
||||||
|
if (isSqlite) {
|
||||||
|
const sqlRebuildSqlite = `
|
||||||
|
WITH
|
||||||
|
order_articles AS (
|
||||||
|
SELECT
|
||||||
|
manifest_id,
|
||||||
|
COUNT(*) AS positions,
|
||||||
|
SUM(amount) AS ordered_quantity,
|
||||||
|
SUM(amount * (net * (1.0 - rebate / 100.0)) * (1.0 + taxrate / 100.0)) AS gross_total
|
||||||
|
FROM manifestarticle
|
||||||
|
GROUP BY manifest_id
|
||||||
|
),
|
||||||
|
order_payments AS (
|
||||||
|
SELECT
|
||||||
|
manifest_id,
|
||||||
|
SUM(amount) AS paid_total
|
||||||
|
FROM payment
|
||||||
|
GROUP BY manifest_id
|
||||||
|
),
|
||||||
|
shipment_totals AS (
|
||||||
|
SELECT
|
||||||
|
SUBSTR(m_s."number", 1, INSTR(m_s."number", @shipmentPrefix) - 1) AS order_number,
|
||||||
|
SUM(ma_s.amount) AS shipped_quantity
|
||||||
|
FROM manifest m_s
|
||||||
|
JOIN manifestarticle ma_s ON ma_s.manifest_id = m_s.id
|
||||||
|
WHERE m_s.company_id = @companyId
|
||||||
|
AND m_s."type" = 'shipment'
|
||||||
|
AND INSTR(m_s."number", @shipmentPrefix) > 0
|
||||||
|
GROUP BY SUBSTR(m_s."number", 1, INSTR(m_s."number", @shipmentPrefix) - 1)
|
||||||
|
)
|
||||||
|
INSERT INTO ordersummary (
|
||||||
|
company_id, manifest_id, order_number, order_date, created_at,
|
||||||
|
entity_id, customer_name, positions, gross_total, paid_total,
|
||||||
|
ordered_quantity, shipped_quantity, is_paid, is_shipped
|
||||||
|
)
|
||||||
|
SELECT
|
||||||
|
m.company_id,
|
||||||
|
m.id AS manifest_id,
|
||||||
|
m."number" AS order_number,
|
||||||
|
m."date" AS order_date,
|
||||||
|
m.created_at,
|
||||||
|
m.entity_id,
|
||||||
|
TRIM(COALESCE(e.first_name || ' ', '') || COALESCE(e.name, '')) AS customer_name,
|
||||||
|
COALESCE(oa.positions, 0) AS positions,
|
||||||
|
ROUND(COALESCE(oa.gross_total, 0), 2) AS gross_total,
|
||||||
|
ROUND(COALESCE(op.paid_total, 0), 2) AS paid_total,
|
||||||
|
ROUND(COALESCE(oa.ordered_quantity, 0), 3) AS ordered_quantity,
|
||||||
|
ROUND(COALESCE(st.shipped_quantity, 0), 3) AS shipped_quantity,
|
||||||
|
CASE WHEN COALESCE(oa.gross_total, 0) > 0 AND ABS(COALESCE(op.paid_total, 0) - oa.gross_total) < 0.01 THEN 1 ELSE 0 END AS is_paid,
|
||||||
|
CASE WHEN COALESCE(oa.ordered_quantity, 0) > 0 AND ABS(COALESCE(st.shipped_quantity, 0) - oa.ordered_quantity) < 0.001 THEN 1 ELSE 0 END AS is_shipped
|
||||||
|
FROM manifest m
|
||||||
|
LEFT JOIN entity e ON e.id = m.entity_id
|
||||||
|
LEFT JOIN order_articles oa ON oa.manifest_id = m.id
|
||||||
|
LEFT JOIN order_payments op ON op.manifest_id = m.id
|
||||||
|
LEFT JOIN shipment_totals st ON st.order_number = m."number"
|
||||||
|
WHERE m.company_id = @companyId AND m."type" = 'order'
|
||||||
|
ON CONFLICT(manifest_id) DO UPDATE SET
|
||||||
|
order_number = excluded.order_number,
|
||||||
|
order_date = excluded.order_date,
|
||||||
|
created_at = excluded.created_at,
|
||||||
|
entity_id = excluded.entity_id,
|
||||||
|
customer_name = excluded.customer_name,
|
||||||
|
positions = excluded.positions,
|
||||||
|
gross_total = excluded.gross_total,
|
||||||
|
paid_total = excluded.paid_total,
|
||||||
|
ordered_quantity = excluded.ordered_quantity,
|
||||||
|
shipped_quantity = excluded.shipped_quantity,
|
||||||
|
is_paid = excluded.is_paid,
|
||||||
|
is_shipped = excluded.is_shipped;
|
||||||
|
`;
|
||||||
|
await runner.query(sqlRebuildSqlite, { companyId, shipmentPrefix });
|
||||||
|
} else {
|
||||||
|
await runner.query('DELETE FROM ordersummary WHERE company_id = @companyId', { companyId });
|
||||||
|
const sqlRebuildMssql = `
|
||||||
|
WITH
|
||||||
|
order_articles AS (
|
||||||
|
SELECT
|
||||||
|
manifest_id,
|
||||||
|
COUNT(*) AS positions,
|
||||||
|
SUM(amount) AS ordered_quantity,
|
||||||
|
SUM(amount * (net * (1.0 - rebate / 100.0)) * (1.0 + taxrate / 100.0)) AS gross_total
|
||||||
|
FROM manifestarticle
|
||||||
|
GROUP BY manifest_id
|
||||||
|
),
|
||||||
|
order_payments AS (
|
||||||
|
SELECT
|
||||||
|
manifest_id,
|
||||||
|
SUM(amount) AS paid_total
|
||||||
|
FROM payment
|
||||||
|
GROUP BY manifest_id
|
||||||
|
),
|
||||||
|
shipment_totals AS (
|
||||||
|
SELECT
|
||||||
|
SUBSTRING(m_s.[number], 1, CHARINDEX(@shipmentPrefix, m_s.[number]) - 1) AS order_number,
|
||||||
|
SUM(ma_s.amount) AS shipped_quantity
|
||||||
|
FROM manifest m_s
|
||||||
|
JOIN manifestarticle ma_s ON ma_s.manifest_id = m_s.id
|
||||||
|
WHERE m_s.company_id = @companyId
|
||||||
|
AND m_s.[type] = 'shipment'
|
||||||
|
AND CHARINDEX(@shipmentPrefix, m_s.[number]) > 0
|
||||||
|
GROUP BY SUBSTRING(m_s.[number], 1, CHARINDEX(@shipmentPrefix, m_s.[number]) - 1)
|
||||||
|
)
|
||||||
|
INSERT INTO ordersummary (
|
||||||
|
company_id, manifest_id, order_number, order_date, created_at,
|
||||||
|
entity_id, customer_name, positions, gross_total, paid_total,
|
||||||
|
ordered_quantity, shipped_quantity, is_paid, is_shipped
|
||||||
|
)
|
||||||
|
SELECT
|
||||||
|
m.company_id,
|
||||||
|
m.id AS manifest_id,
|
||||||
|
m.[number] AS order_number,
|
||||||
|
m.[date] AS order_date,
|
||||||
|
m.created_at,
|
||||||
|
m.entity_id,
|
||||||
|
LTRIM(RTRIM(ISNULL(e.first_name + ' ', '') + ISNULL(e.name, ''))) AS customer_name,
|
||||||
|
COALESCE(oa.positions, 0) AS positions,
|
||||||
|
ROUND(COALESCE(oa.gross_total, 0), 2) AS gross_total,
|
||||||
|
ROUND(COALESCE(op.paid_total, 0), 2) AS paid_total,
|
||||||
|
ROUND(COALESCE(oa.ordered_quantity, 0), 3) AS ordered_quantity,
|
||||||
|
ROUND(COALESCE(st.shipped_quantity, 0), 3) AS shipped_quantity,
|
||||||
|
CASE WHEN COALESCE(oa.gross_total, 0) > 0 AND ABS(COALESCE(op.paid_total, 0) - oa.gross_total) < 0.01 THEN 1 ELSE 0 END AS is_paid,
|
||||||
|
CASE WHEN COALESCE(oa.ordered_quantity, 0) > 0 AND ABS(COALESCE(st.shipped_quantity, 0) - oa.ordered_quantity) < 0.001 THEN 1 ELSE 0 END AS is_shipped
|
||||||
|
FROM manifest m
|
||||||
|
LEFT JOIN entity e ON e.id = m.entity_id
|
||||||
|
LEFT JOIN order_articles oa ON oa.manifest_id = m.id
|
||||||
|
LEFT JOIN order_payments op ON op.manifest_id = m.id
|
||||||
|
LEFT JOIN shipment_totals st ON st.order_number = m.[number]
|
||||||
|
WHERE m.company_id = @companyId AND m.[type] = 'order';
|
||||||
|
`;
|
||||||
|
await runner.query(sqlRebuildMssql, { companyId, shipmentPrefix });
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -14,6 +14,7 @@ import resolveSelectedCompanyAccess from '../companyuser/resolveSelectedCompanyA
|
|||||||
import taxEnsure from '../tax/ensure.js';
|
import taxEnsure from '../tax/ensure.js';
|
||||||
import { insertLines, normalizeLines, parseDate } from '../manifestLines.js';
|
import { insertLines, normalizeLines, parseDate } from '../manifestLines.js';
|
||||||
import { assertCustomerEntity, loadDoc, shapeSummary } from '../manifestDoc/helpers.js';
|
import { assertCustomerEntity, loadDoc, shapeSummary } from '../manifestDoc/helpers.js';
|
||||||
|
import { syncOrderSummary } from './syncSummary.js';
|
||||||
import makeRunner from '../runner.js';
|
import makeRunner from '../runner.js';
|
||||||
|
|
||||||
export default function update(provider) {
|
export default function update(provider) {
|
||||||
@@ -146,6 +147,7 @@ export default function update(provider) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const doc = await loadDoc(runner, { type: orderType, companyId, id });
|
const doc = await loadDoc(runner, { type: orderType, companyId, id });
|
||||||
|
await syncOrderSummary(runner, { companyId, manifestId: id });
|
||||||
return doc;
|
return doc;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { queriesFor, requireId, requireText } from '../logistics/helpers.js';
|
import { queriesFor, requireId, requireText } from '../logistics/helpers.js';
|
||||||
import resolveSelectedCompanyAccess from '../companyuser/resolveSelectedCompanyAccess.js';
|
import resolveSelectedCompanyAccess from '../companyuser/resolveSelectedCompanyAccess.js';
|
||||||
import resolveManifestAccess from '../manifestattachment/resolveManifestAccess.js';
|
import resolveManifestAccess from '../manifestattachment/resolveManifestAccess.js';
|
||||||
|
import { syncOrderSummary } from '../order/syncSummary.js';
|
||||||
import makeRunner from '../runner.js';
|
import makeRunner from '../runner.js';
|
||||||
|
|
||||||
function shape(row) {
|
function shape(row) {
|
||||||
@@ -64,6 +65,7 @@ export default function create(provider) {
|
|||||||
type,
|
type,
|
||||||
amount: input.amount,
|
amount: input.amount,
|
||||||
};
|
};
|
||||||
|
await syncOrderSummary(runner, { companyId, manifestId });
|
||||||
return shape(row);
|
return shape(row);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import { queriesFor, requireId } from '../logistics/helpers.js';
|
import { queriesFor, requireId } from '../logistics/helpers.js';
|
||||||
import resolveSelectedCompanyAccess from '../companyuser/resolveSelectedCompanyAccess.js';
|
import resolveSelectedCompanyAccess from '../companyuser/resolveSelectedCompanyAccess.js';
|
||||||
|
import { syncOrderSummary } from '../order/syncSummary.js';
|
||||||
import makeRunner from '../runner.js';
|
import makeRunner from '../runner.js';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -21,6 +22,17 @@ export default function del(provider) {
|
|||||||
const paymentId = requireId(id, 'Payment');
|
const paymentId = requireId(id, 'Payment');
|
||||||
const runner = makeRunner(provider, tx);
|
const runner = makeRunner(provider, tx);
|
||||||
const { companyId } = await access(googleAuthId, runner);
|
const { companyId } = await access(googleAuthId, runner);
|
||||||
|
|
||||||
|
const paymentRow = await runner.query(
|
||||||
|
'SELECT manifest_id FROM payment WHERE id = @id',
|
||||||
|
{ id: paymentId },
|
||||||
|
);
|
||||||
|
const manifestId = paymentRow.rows[0]?.manifest_id;
|
||||||
|
|
||||||
await runner.query(q.PAYMENT_DELETE, { id: paymentId, companyId });
|
await runner.query(q.PAYMENT_DELETE, { id: paymentId, companyId });
|
||||||
|
|
||||||
|
if (manifestId) {
|
||||||
|
await syncOrderSummary(runner, { companyId, manifestId });
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import taxEnsure from '../tax/ensure.js';
|
|||||||
import { insertLines, parseDate } from '../manifestLines.js';
|
import { insertLines, parseDate } from '../manifestLines.js';
|
||||||
import makeRunner from '../runner.js';
|
import makeRunner from '../runner.js';
|
||||||
import { loadShipment, queriesFor } from './helpers.js';
|
import { loadShipment, queriesFor } from './helpers.js';
|
||||||
|
import { syncOrderSummary } from '../order/syncSummary.js';
|
||||||
|
|
||||||
function requireId(val, name) {
|
function requireId(val, name) {
|
||||||
const n = Number(val);
|
const n = Number(val);
|
||||||
@@ -181,6 +182,8 @@ export default function create(provider) {
|
|||||||
ensureTax,
|
ensureTax,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
await syncOrderSummary(runner, { companyId, manifestId: orderId });
|
||||||
|
|
||||||
return loadShipment(runner, q, companyId, manifestId);
|
return loadShipment(runner, q, companyId, manifestId);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import resolveSelectedCompanyAccess from '../companyuser/resolveSelectedCompanyAccess.js';
|
import resolveSelectedCompanyAccess from '../companyuser/resolveSelectedCompanyAccess.js';
|
||||||
import makeRunner from '../runner.js';
|
import makeRunner from '../runner.js';
|
||||||
import { queriesFor } from './helpers.js';
|
import { queriesFor } from './helpers.js';
|
||||||
|
import { syncOrderSummary } from '../order/syncSummary.js';
|
||||||
|
|
||||||
function requireId(val, name) {
|
function requireId(val, name) {
|
||||||
const n = Number(val);
|
const n = Number(val);
|
||||||
@@ -52,9 +53,19 @@ export default function del(provider) {
|
|||||||
throw new Error('Shipped shipment cannot be deleted');
|
throw new Error('Shipped shipment cannot be deleted');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const shipmentNumber = String(check.rows[0].number || '');
|
||||||
|
const prefixRes = await runner.query(q.GET_SHIPMENT_PREFIX, { companyId });
|
||||||
|
const shipmentPrefix = prefixRes.rows[0]?.prefix?.trim?.() || '-L-';
|
||||||
|
const pIdx = shipmentNumber.indexOf(shipmentPrefix);
|
||||||
|
const orderNumber = pIdx > 0 ? shipmentNumber.slice(0, pIdx) : null;
|
||||||
|
|
||||||
await runner.query(q.DELETE_SHIPMENT, {
|
await runner.query(q.DELETE_SHIPMENT, {
|
||||||
id: shipmentId,
|
id: shipmentId,
|
||||||
companyId,
|
companyId,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (orderNumber) {
|
||||||
|
await syncOrderSummary(runner, { companyId, orderNumber });
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user