This commit is contained in:
seb
2026-10-17 00:52:45 +02:00
parent e16c3b3f67
commit 8ee080b744
4 changed files with 132 additions and 79 deletions

View File

@@ -43,29 +43,23 @@ SELECT
m.external_number AS externalNumber,
m.[date],
m.created_at AS createdAt,
COUNT(ma.id) AS totalPositions,
COUNT(CASE WHEN ma.id IS NOT NULL AND (
(ma.amount > 0 AND COALESCE(ma_ledger.booked_amount, 0) >= ma.amount) OR
(ma.amount <= 0 AND COALESCE(ma_ledger.booked_amount, 0) > 0)
) THEN 1 END) AS completelyOnLedgerPositions
ds.positions,
ds.gross_total AS grossTotal,
ds.net_total AS netTotal,
ds.total_quantity AS totalQuantity,
ds.stock_positions AS stockPositions,
ds.booked_positions AS bookedPositions,
ds.unbooked_positions AS unbookedPositions,
ds.stock_quantity AS stockQuantity,
ds.booked_quantity AS bookedQuantity,
ds.unbooked_quantity AS unbookedQuantity,
ds.is_booked AS isBooked,
ds.supplier_name AS supplierName
FROM manifest m
LEFT JOIN manifestarticle ma ON ma.manifest_id = m.id
LEFT JOIN (
SELECT manifestarticle_id, SUM(amount) AS booked_amount
FROM ledger
GROUP BY manifestarticle_id
) ma_ledger ON ma_ledger.manifestarticle_id = ma.id
LEFT JOIN deliverysummary ds ON ds.manifest_id = m.id
WHERE m.id = @id
AND m.company_id = @companyId
AND m.[type] = @type
GROUP BY
m.id,
m.[number],
m.[type],
m.entity_id,
m.external_number,
m.[date],
m.created_at
`;
export const GET_DELIVERY_LINES = `

View File

@@ -3,33 +3,54 @@ import * as sqliteQueries from '../../providers/sqlite3/queries/delivery.js';
import makeRunner from '../runner.js';
import { shapeLine } from '../manifestLines.js';
import { loadAttachments } from './attachments.js';
import { syncDeliverySummary } from './syncSummary.js';
export const DELIVERY_TYPE = mssqlQueries.DELIVERY_TYPE;
export function shapeSummary(row) {
const stockPositions = Number(row.stockPositions ?? 0);
const totalPositions = Number(row.stockPositions ?? row.totalPositions ?? row.positions ?? 0);
const bookedPositions = Number(row.bookedPositions ?? row.completelyOnLedgerPositions ?? 0);
const unbookedPositions = Number(row.unbookedPositions ?? Math.max(0, totalPositions - bookedPositions));
const totalQuantity = Number(row.totalQuantity ?? row.stockQuantity ?? 0);
const stockQuantity = Number(row.stockQuantity ?? 0);
const bookedQuantity = Number(row.bookedQuantity ?? 0);
const unbookedQuantity = Number(row.unbookedQuantity ?? Math.max(0, (stockQuantity || totalQuantity) - bookedQuantity));
const isBooked = row.isBooked !== undefined && row.isBooked !== null
? Boolean(row.isBooked)
: (totalPositions > 0 && bookedPositions >= totalPositions);
const summary = {
id: row.id,
number: row.number,
type: DELIVERY_TYPE,
supplierId: row.supplierId ?? null,
supplierName: row.supplierName ?? undefined,
externalNumber: row.externalNumber ?? null,
date: row.date,
createdAt: row.createdAt ?? row.created_at ?? null,
};
const totalPositions = Number(row.stockPositions ?? row.totalPositions ?? row.positions ?? 0);
const bookedPositions = Number(row.completelyOnLedgerPositions ?? row.bookedPositions ?? 0);
const unbookedPositions = Number(row.unbookedPositions ?? Math.max(0, totalPositions - bookedPositions));
summary.ledger = {
totalPositions,
completelyOnLedgerPositions: bookedPositions,
positions: Number(row.positions ?? totalPositions),
grossTotal: row.grossTotal !== undefined && row.grossTotal !== null ? Number(row.grossTotal) : 0,
netTotal: row.netTotal !== undefined && row.netTotal !== null ? Number(row.netTotal) : 0,
totalQuantity,
stockPositions,
bookedPositions,
unbookedPositions,
totalQuantity: Number(row.stockQuantity ?? row.totalQuantity ?? 0),
bookedQuantity: Number(row.bookedQuantity ?? 0),
unbookedQuantity: Number(row.unbookedQuantity ?? 0),
isBooked: row.isBooked !== undefined ? Boolean(row.isBooked) : (totalPositions > 0 && bookedPositions >= totalPositions),
stockQuantity,
bookedQuantity,
unbookedQuantity,
isBooked,
ledger: {
totalPositions,
completelyOnLedgerPositions: bookedPositions,
bookedPositions,
unbookedPositions,
totalQuantity: stockQuantity || totalQuantity,
bookedQuantity,
unbookedQuantity,
isBooked,
},
};
return summary;
@@ -40,17 +61,27 @@ export async function loadDelivery(provider, tx, companyId, id) {
const isSqlite = provider?.dialect === 'sqlite3';
const queries = isSqlite ? sqliteQueries : mssqlQueries;
const header = await runner(queries.GET_DELIVERY_HEADER, {
let header = await runner(queries.GET_DELIVERY_HEADER, {
id,
companyId,
type: DELIVERY_TYPE,
});
const row = header.rows[0];
let row = header.rows[0];
if (!row) {
return null;
}
if (row.positions === null || row.positions === undefined) {
await syncDeliverySummary(runner, { companyId, manifestId: id });
header = await runner(queries.GET_DELIVERY_HEADER, {
id,
companyId,
type: DELIVERY_TYPE,
});
row = header.rows[0];
}
const lines = await runner(queries.GET_DELIVERY_LINES, {
manifestId: id,
});

View File

@@ -286,28 +286,6 @@ export default function list(provider) {
const deliveries = manifestRows.map((row) => ({
...shapeSummary(row),
positions: row.positions !== undefined && row.positions !== null ? Number(row.positions) : 0,
grossTotal: row.grossTotal !== undefined && row.grossTotal !== null ? Number(row.grossTotal) : 0,
netTotal: row.netTotal !== undefined && row.netTotal !== null ? Number(row.netTotal) : 0,
totalQuantity: row.totalQuantity !== undefined && row.totalQuantity !== null ? Number(row.totalQuantity) : 0,
stockPositions: row.stockPositions !== undefined && row.stockPositions !== null ? Number(row.stockPositions) : 0,
bookedPositions: row.bookedPositions !== undefined && row.bookedPositions !== null ? Number(row.bookedPositions) : 0,
unbookedPositions: row.unbookedPositions !== undefined && row.unbookedPositions !== null ? Number(row.unbookedPositions) : 0,
stockQuantity: row.stockQuantity !== undefined && row.stockQuantity !== null ? Number(row.stockQuantity) : 0,
bookedQuantity: row.bookedQuantity !== undefined && row.bookedQuantity !== null ? Number(row.bookedQuantity) : 0,
unbookedQuantity: row.unbookedQuantity !== undefined && row.unbookedQuantity !== null ? Number(row.unbookedQuantity) : 0,
isBooked: row.isBooked !== undefined && row.isBooked !== null ? Boolean(row.isBooked) : false,
supplierName: row.supplierName ?? undefined,
ledger: {
totalPositions: Number(row.stockPositions ?? row.totalPositions ?? 0),
completelyOnLedgerPositions: Number(row.bookedPositions ?? row.completelyOnLedgerPositions ?? 0),
bookedPositions: Number(row.bookedPositions ?? 0),
unbookedPositions: Number(row.unbookedPositions ?? 0),
totalQuantity: Number(row.stockQuantity ?? 0),
bookedQuantity: Number(row.bookedQuantity ?? 0),
unbookedQuantity: Number(row.unbookedQuantity ?? 0),
isBooked: Boolean(row.isBooked),
},
files: filesByManifest.get(row.id) ?? [],
}));

View File

@@ -70,9 +70,11 @@ const SQL_DELIVERY_TOTALS_SQLITE = `
COALESCE(SUM(line_net), 0) AS net_total,
COALESCE(SUM(amount), 0) AS total_quantity,
COALESCE(SUM(CASE WHEN track_stock = 1 THEN 1 ELSE 0 END), 0) AS stock_positions,
COALESCE(SUM(CASE WHEN track_stock = 1 AND (CASE WHEN amount > 0 THEN booked_amount >= amount ELSE booked_amount > 0 END) THEN 1 ELSE 0 END), 0) AS booked_positions,
COALESCE(SUM(CASE WHEN track_stock = 1 AND (CASE WHEN amount > 0 THEN booked_amount >= amount ELSE booked_amount > 0 END) THEN 1 ELSE 0 END), 0) AS stock_booked_positions,
COALESCE(SUM(CASE WHEN track_stock = 1 THEN amount ELSE 0 END), 0) AS stock_quantity,
COALESCE(SUM(CASE WHEN track_stock = 1 THEN booked_amount ELSE 0 END), 0) AS booked_quantity
COALESCE(SUM(CASE WHEN track_stock = 1 THEN booked_amount ELSE 0 END), 0) AS stock_booked_quantity,
COALESCE(SUM(CASE WHEN (CASE WHEN amount > 0 THEN booked_amount >= amount ELSE booked_amount > 0 END) THEN 1 ELSE 0 END), 0) AS all_booked_positions,
COALESCE(SUM(booked_amount), 0) AS all_booked_quantity
FROM line_data
`;
@@ -105,9 +107,11 @@ const SQL_DELIVERY_TOTALS_MSSQL = `
COALESCE(SUM(line_net), 0) AS net_total,
COALESCE(SUM(amount), 0) AS total_quantity,
COALESCE(SUM(CASE WHEN track_stock = 1 THEN 1 ELSE 0 END), 0) AS stock_positions,
COALESCE(SUM(CASE WHEN track_stock = 1 AND (CASE WHEN amount > 0 THEN booked_amount >= amount ELSE booked_amount > 0 END) THEN 1 ELSE 0 END), 0) AS booked_positions,
COALESCE(SUM(CASE WHEN track_stock = 1 AND (CASE WHEN amount > 0 THEN booked_amount >= amount ELSE booked_amount > 0 END) THEN 1 ELSE 0 END), 0) AS stock_booked_positions,
COALESCE(SUM(CASE WHEN track_stock = 1 THEN amount ELSE 0 END), 0) AS stock_quantity,
COALESCE(SUM(CASE WHEN track_stock = 1 THEN booked_amount ELSE 0 END), 0) AS booked_quantity
COALESCE(SUM(CASE WHEN track_stock = 1 THEN booked_amount ELSE 0 END), 0) AS stock_booked_quantity,
COALESCE(SUM(CASE WHEN (CASE WHEN amount > 0 THEN booked_amount >= amount ELSE booked_amount > 0 END) THEN 1 ELSE 0 END), 0) AS all_booked_positions,
COALESCE(SUM(booked_amount), 0) AS all_booked_quantity
FROM line_data
`;
@@ -237,12 +241,22 @@ export async function syncDeliverySummary(runner, { companyId, manifestId, deliv
const netTotal = Math.round(Number(totals.net_total || 0) * 100) / 100;
const totalQuantity = Math.round(Number(totals.total_quantity || 0) * 1000) / 1000;
const stockPositions = Number(totals.stock_positions || 0);
const bookedPositions = Number(totals.booked_positions || 0);
const unbookedPositions = Math.max(0, stockPositions - bookedPositions);
const hasStockPositions = stockPositions > 0;
const bookedPositions = hasStockPositions
? Number(totals.stock_booked_positions || 0)
: Number(totals.all_booked_positions || 0);
const targetPositions = hasStockPositions ? stockPositions : positions;
const unbookedPositions = Math.max(0, targetPositions - bookedPositions);
const stockQuantity = Math.round(Number(totals.stock_quantity || 0) * 1000) / 1000;
const bookedQuantity = Math.round(Number(totals.booked_quantity || 0) * 1000) / 1000;
const unbookedQuantity = Math.round(Math.max(0, stockQuantity - bookedQuantity) * 1000) / 1000;
const isBooked = stockPositions > 0 && bookedPositions >= stockPositions ? 1 : 0;
const bookedQuantity = hasStockPositions
? Math.round(Number(totals.stock_booked_quantity || 0) * 1000) / 1000
: Math.round(Number(totals.all_booked_quantity || 0) * 1000) / 1000;
const targetQuantity = hasStockPositions ? stockQuantity : totalQuantity;
const unbookedQuantity = Math.round(Math.max(0, targetQuantity - bookedQuantity) * 1000) / 1000;
const isBooked = targetPositions > 0 && bookedPositions >= targetPositions ? 1 : 0;
await runner.query(isSqlite ? SQL_UPSERT_SUMMARY_SQLITE : SQL_UPSERT_SUMMARY_MSSQL, {
companyId,
@@ -311,9 +325,11 @@ export async function rebuildDeliverySummaries(runner, companyId) {
SUM(line_net) AS net_total,
SUM(amount) AS total_quantity,
SUM(CASE WHEN track_stock = 1 THEN 1 ELSE 0 END) AS stock_positions,
SUM(CASE WHEN track_stock = 1 AND (CASE WHEN amount > 0 THEN booked_amount >= amount ELSE booked_amount > 0 END) THEN 1 ELSE 0 END) AS booked_positions,
SUM(CASE WHEN track_stock = 1 AND (CASE WHEN amount > 0 THEN booked_amount >= amount ELSE booked_amount > 0 END) THEN 1 ELSE 0 END) AS stock_booked_positions,
SUM(CASE WHEN track_stock = 1 THEN amount ELSE 0 END) AS stock_quantity,
SUM(CASE WHEN track_stock = 1 THEN booked_amount ELSE 0 END) AS booked_quantity
SUM(CASE WHEN track_stock = 1 THEN booked_amount ELSE 0 END) AS stock_booked_quantity,
SUM(CASE WHEN (CASE WHEN amount > 0 THEN booked_amount >= amount ELSE booked_amount > 0 END) THEN 1 ELSE 0 END) AS all_booked_positions,
SUM(booked_amount) AS all_booked_quantity
FROM line_data
GROUP BY manifest_id
)
@@ -337,12 +353,28 @@ export async function rebuildDeliverySummaries(runner, companyId) {
ROUND(COALESCE(da.net_total, 0), 2) AS net_total,
ROUND(COALESCE(da.total_quantity, 0), 3) AS total_quantity,
COALESCE(da.stock_positions, 0) AS stock_positions,
COALESCE(da.booked_positions, 0) AS booked_positions,
MAX(0, COALESCE(da.stock_positions, 0) - COALESCE(da.booked_positions, 0)) AS unbooked_positions,
CASE
WHEN COALESCE(da.stock_positions, 0) > 0 THEN COALESCE(da.stock_booked_positions, 0)
ELSE COALESCE(da.all_booked_positions, 0)
END AS booked_positions,
CASE
WHEN COALESCE(da.stock_positions, 0) > 0 THEN MAX(0, COALESCE(da.stock_positions, 0) - COALESCE(da.stock_booked_positions, 0))
ELSE MAX(0, COALESCE(da.positions, 0) - COALESCE(da.all_booked_positions, 0))
END AS unbooked_positions,
ROUND(COALESCE(da.stock_quantity, 0), 3) AS stock_quantity,
ROUND(COALESCE(da.booked_quantity, 0), 3) AS booked_quantity,
ROUND(MAX(0, COALESCE(da.stock_quantity, 0) - COALESCE(da.booked_quantity, 0)), 3) AS unbooked_quantity,
CASE WHEN COALESCE(da.stock_positions, 0) > 0 AND COALESCE(da.booked_positions, 0) >= COALESCE(da.stock_positions, 0) THEN 1 ELSE 0 END AS is_booked
CASE
WHEN COALESCE(da.stock_positions, 0) > 0 THEN ROUND(COALESCE(da.stock_booked_quantity, 0), 3)
ELSE ROUND(COALESCE(da.all_booked_quantity, 0), 3)
END AS booked_quantity,
CASE
WHEN COALESCE(da.stock_positions, 0) > 0 THEN ROUND(MAX(0, COALESCE(da.stock_quantity, 0) - COALESCE(da.stock_booked_quantity, 0)), 3)
ELSE ROUND(MAX(0, COALESCE(da.total_quantity, 0) - COALESCE(da.all_booked_quantity, 0)), 3)
END AS unbooked_quantity,
CASE
WHEN COALESCE(da.stock_positions, 0) > 0 AND COALESCE(da.stock_booked_positions, 0) >= COALESCE(da.stock_positions, 0) THEN 1
WHEN COALESCE(da.stock_positions, 0) = 0 AND COALESCE(da.positions, 0) > 0 AND COALESCE(da.all_booked_positions, 0) >= COALESCE(da.positions, 0) THEN 1
ELSE 0
END AS is_booked
FROM manifest m
LEFT JOIN entity e ON e.id = m.entity_id
LEFT JOIN delivery_agg da ON da.manifest_id = m.id
@@ -403,9 +435,11 @@ export async function rebuildDeliverySummaries(runner, companyId) {
SUM(line_net) AS net_total,
SUM(amount) AS total_quantity,
SUM(CASE WHEN track_stock = 1 THEN 1 ELSE 0 END) AS stock_positions,
SUM(CASE WHEN track_stock = 1 AND (CASE WHEN amount > 0 THEN booked_amount >= amount ELSE booked_amount > 0 END) THEN 1 ELSE 0 END) AS booked_positions,
SUM(CASE WHEN track_stock = 1 AND (CASE WHEN amount > 0 THEN booked_amount >= amount ELSE booked_amount > 0 END) THEN 1 ELSE 0 END) AS stock_booked_positions,
SUM(CASE WHEN track_stock = 1 THEN amount ELSE 0 END) AS stock_quantity,
SUM(CASE WHEN track_stock = 1 THEN booked_amount ELSE 0 END) AS booked_quantity
SUM(CASE WHEN track_stock = 1 THEN booked_amount ELSE 0 END) AS stock_booked_quantity,
SUM(CASE WHEN (CASE WHEN amount > 0 THEN booked_amount >= amount ELSE booked_amount > 0 END) THEN 1 ELSE 0 END) AS all_booked_positions,
SUM(booked_amount) AS all_booked_quantity
FROM line_data
GROUP BY manifest_id
)
@@ -429,12 +463,28 @@ export async function rebuildDeliverySummaries(runner, companyId) {
ROUND(COALESCE(da.net_total, 0), 2) AS net_total,
ROUND(COALESCE(da.total_quantity, 0), 3) AS total_quantity,
COALESCE(da.stock_positions, 0) AS stock_positions,
COALESCE(da.booked_positions, 0) AS booked_positions,
CASE WHEN COALESCE(da.stock_positions, 0) > COALESCE(da.booked_positions, 0) THEN COALESCE(da.stock_positions, 0) - COALESCE(da.booked_positions, 0) ELSE 0 END AS unbooked_positions,
CASE
WHEN COALESCE(da.stock_positions, 0) > 0 THEN COALESCE(da.stock_booked_positions, 0)
ELSE COALESCE(da.all_booked_positions, 0)
END AS booked_positions,
CASE
WHEN COALESCE(da.stock_positions, 0) > 0 THEN CASE WHEN COALESCE(da.stock_positions, 0) > COALESCE(da.stock_booked_positions, 0) THEN COALESCE(da.stock_positions, 0) - COALESCE(da.stock_booked_positions, 0) ELSE 0 END
ELSE CASE WHEN COALESCE(da.positions, 0) > COALESCE(da.all_booked_positions, 0) THEN COALESCE(da.positions, 0) - COALESCE(da.all_booked_positions, 0) ELSE 0 END
END AS unbooked_positions,
ROUND(COALESCE(da.stock_quantity, 0), 3) AS stock_quantity,
ROUND(COALESCE(da.booked_quantity, 0), 3) AS booked_quantity,
ROUND(CASE WHEN COALESCE(da.stock_quantity, 0) > COALESCE(da.booked_quantity, 0) THEN COALESCE(da.stock_quantity, 0) - COALESCE(da.booked_quantity, 0) ELSE 0 END, 3) AS unbooked_quantity,
CASE WHEN COALESCE(da.stock_positions, 0) > 0 AND COALESCE(da.booked_positions, 0) >= COALESCE(da.stock_positions, 0) THEN 1 ELSE 0 END AS is_booked
CASE
WHEN COALESCE(da.stock_positions, 0) > 0 THEN ROUND(COALESCE(da.stock_booked_quantity, 0), 3)
ELSE ROUND(COALESCE(da.all_booked_quantity, 0), 3)
END AS booked_quantity,
CASE
WHEN COALESCE(da.stock_positions, 0) > 0 THEN ROUND(CASE WHEN COALESCE(da.stock_quantity, 0) > COALESCE(da.stock_booked_quantity, 0) THEN COALESCE(da.stock_quantity, 0) - COALESCE(da.stock_booked_quantity, 0) ELSE 0 END, 3)
ELSE ROUND(CASE WHEN COALESCE(da.total_quantity, 0) > COALESCE(da.all_booked_quantity, 0) THEN COALESCE(da.total_quantity, 0) - COALESCE(da.all_booked_quantity, 0) ELSE 0 END, 3)
END AS unbooked_quantity,
CASE
WHEN COALESCE(da.stock_positions, 0) > 0 AND COALESCE(da.stock_booked_positions, 0) >= COALESCE(da.stock_positions, 0) THEN 1
WHEN COALESCE(da.stock_positions, 0) = 0 AND COALESCE(da.positions, 0) > 0 AND COALESCE(da.all_booked_positions, 0) >= COALESCE(da.positions, 0) THEN 1
ELSE 0
END AS is_booked
FROM manifest m
LEFT JOIN entity e ON e.id = m.entity_id
LEFT JOIN delivery_agg da ON da.manifest_id = m.id