Check lot quantities

This commit is contained in:
2026-05-13 19:29:24 +02:00
parent 26c955ef53
commit 14ba0361d2
5 changed files with 116 additions and 18 deletions

View File

@@ -1,3 +1,5 @@
-- Active: 1778691597138@@72.61.163.139@5433@tradon
-- Active: 1778686654594@@72.61.163.139@5435@tradon
/*
Purchase Trade quantity consistency diagnostics.
@@ -9,16 +11,20 @@ Rules checked:
= line quantity_theorical.
2. For each virtual purchase lot:
sum(lot_qt.lot_quantity where lot_p = virtual lot)
sum(non-zero lot_qt.lot_quantity where lot_p = virtual lot)
= virtual lot current quantity.
Matched and unmatched lot_qt rows are both included.
3. For each virtual sale lot:
sum(lot_qt.lot_quantity where lot_s = virtual lot)
sum(non-zero lot_qt.lot_quantity where lot_s = virtual lot)
= virtual lot current quantity.
Rows linked to a purchase lot and rows without purchase lot are both
included.
Zero lot_qt rows are allowed when they keep the memory of an open quantity
consumed by a physical lot, as long as at least lot_p or lot_s is set. Unlinked
lot_qt rows are reported as anomalies.
Notes:
- The script uses the lot current state, i.e. lot_lot.lot_state joined to
lot_qt_hist.quantity_type.
@@ -55,36 +61,46 @@ lot_current AS (
purchase_line_base AS (
SELECT
pl.id AS line_id,
pp.id AS contract_id,
pp.number AS contract_number,
pl.quantity_theorical::numeric AS theoretical_quantity,
pl.quantity::numeric AS line_quantity,
pl.unit AS line_unit,
COUNT(vlot.id) AS virtual_count,
MIN(vlot.id) AS virtual_lot_id
FROM purchase_line pl
LEFT JOIN purchase_purchase pp ON pp.id = pl.purchase
LEFT JOIN lot_lot vlot
ON vlot.line = pl.id
AND vlot.lot_type = 'virtual'
WHERE pl.quantity_theorical IS NOT NULL
GROUP BY pl.id, pl.quantity_theorical, pl.quantity, pl.unit
GROUP BY
pl.id, pp.id, pp.number, pl.quantity_theorical, pl.quantity, pl.unit
),
sale_line_base AS (
SELECT
sl.id AS line_id,
ss.id AS contract_id,
ss.number AS contract_number,
sl.quantity_theorical::numeric AS theoretical_quantity,
sl.quantity::numeric AS line_quantity,
sl.unit AS line_unit,
COUNT(vlot.id) AS virtual_count,
MIN(vlot.id) AS virtual_lot_id
FROM sale_line sl
LEFT JOIN sale_sale ss ON ss.id = sl.sale
LEFT JOIN lot_lot vlot
ON vlot.sale_line = sl.id
AND vlot.lot_type = 'virtual'
WHERE sl.quantity_theorical IS NOT NULL
GROUP BY sl.id, sl.quantity_theorical, sl.quantity, sl.unit
GROUP BY
sl.id, ss.id, ss.number, sl.quantity_theorical, sl.quantity, sl.unit
),
purchase_line_quantities AS (
SELECT
base.line_id,
base.contract_id,
base.contract_number,
base.theoretical_quantity,
base.line_quantity,
base.line_unit,
@@ -120,7 +136,8 @@ purchase_line_quantities AS (
AND phys.lot_type = 'physic'
LEFT JOIN uom phys_uom ON phys_uom.id = phys.lot_unit_line
GROUP BY
base.line_id, base.theoretical_quantity, base.line_quantity,
base.line_id, base.contract_id, base.contract_number,
base.theoretical_quantity, base.line_quantity,
base.line_unit, base.virtual_count, base.virtual_lot_id,
vlot.lot_id, vlot.current_quantity, vlot_uom.category,
vlot_uom.factor, line_uom.category, line_uom.factor
@@ -128,6 +145,8 @@ purchase_line_quantities AS (
sale_line_quantities AS (
SELECT
base.line_id,
base.contract_id,
base.contract_number,
base.theoretical_quantity,
base.line_quantity,
base.line_unit,
@@ -163,7 +182,8 @@ sale_line_quantities AS (
AND phys.lot_type = 'physic'
LEFT JOIN uom phys_uom ON phys_uom.id = phys.lot_unit_line
GROUP BY
base.line_id, base.theoretical_quantity, base.line_quantity,
base.line_id, base.contract_id, base.contract_number,
base.theoretical_quantity, base.line_quantity,
base.line_unit, base.virtual_count, base.virtual_lot_id,
vlot.lot_id, vlot.current_quantity, vlot_uom.category,
vlot_uom.factor, line_uom.category, line_uom.factor
@@ -172,6 +192,8 @@ purchase_lot_qt_balance AS (
SELECT
vlot.id AS virtual_lot_id,
vlot.line AS line_id,
pp.id AS contract_id,
pp.number AS contract_number,
COALESCE(SUM(
CASE
WHEN lqt_uom.category = line_uom.category
@@ -191,18 +213,23 @@ purchase_lot_qt_balance AS (
) AS lot_qt_cross_category_count
FROM lot_lot vlot
JOIN purchase_line pl ON pl.id = vlot.line
LEFT JOIN purchase_purchase pp ON pp.id = pl.purchase
JOIN uom line_uom ON line_uom.id = pl.unit
LEFT JOIN lot_current current ON current.lot_id = vlot.id
LEFT JOIN uom vlot_uom ON vlot_uom.id = current.lot_unit_line
LEFT JOIN lot_qt lqt ON lqt.lot_p = vlot.id
LEFT JOIN lot_qt lqt
ON lqt.lot_p = vlot.id
AND COALESCE(lqt.lot_quantity, 0) <> 0
LEFT JOIN uom lqt_uom ON lqt_uom.id = lqt.lot_unit
WHERE vlot.lot_type = 'virtual'
GROUP BY vlot.id, vlot.line
GROUP BY vlot.id, vlot.line, pp.id, pp.number
),
sale_lot_qt_balance AS (
SELECT
vlot.id AS virtual_lot_id,
vlot.sale_line AS line_id,
ss.id AS contract_id,
ss.number AS contract_number,
COALESCE(SUM(
CASE
WHEN lqt_uom.category = line_uom.category
@@ -222,18 +249,24 @@ sale_lot_qt_balance AS (
) AS lot_qt_cross_category_count
FROM lot_lot vlot
JOIN sale_line sl ON sl.id = vlot.sale_line
LEFT JOIN sale_sale ss ON ss.id = sl.sale
JOIN uom line_uom ON line_uom.id = sl.unit
LEFT JOIN lot_current current ON current.lot_id = vlot.id
LEFT JOIN uom vlot_uom ON vlot_uom.id = current.lot_unit_line
LEFT JOIN lot_qt lqt ON lqt.lot_s = vlot.id
LEFT JOIN lot_qt lqt
ON lqt.lot_s = vlot.id
AND COALESCE(lqt.lot_quantity, 0) <> 0
LEFT JOIN uom lqt_uom ON lqt_uom.id = lqt.lot_unit
WHERE vlot.lot_type = 'virtual'
GROUP BY vlot.id, vlot.sale_line
GROUP BY vlot.id, vlot.sale_line, ss.id, ss.number
)
SELECT *
FROM (
SELECT
'purchase_line_virtual_count' AS check_name,
'purchase.purchase' AS contract_model,
contract_id,
contract_number,
line_id,
virtual_lot_id,
virtual_count::numeric AS observed_value,
@@ -248,6 +281,9 @@ FROM (
SELECT
'sale_line_virtual_count' AS check_name,
'sale.sale' AS contract_model,
contract_id,
contract_number,
line_id,
virtual_lot_id,
virtual_count::numeric AS observed_value,
@@ -262,6 +298,9 @@ FROM (
SELECT
'purchase_line_physical_plus_virtual' AS check_name,
'purchase.purchase' AS contract_model,
q.contract_id,
q.contract_number,
q.line_id,
q.virtual_lot_id,
ROUND(q.physical_quantity + COALESCE(q.virtual_quantity, 0), 5)
@@ -284,6 +323,9 @@ FROM (
SELECT
'sale_line_physical_plus_virtual' AS check_name,
'sale.sale' AS contract_model,
q.contract_id,
q.contract_number,
q.line_id,
q.virtual_lot_id,
ROUND(q.physical_quantity + COALESCE(q.virtual_quantity, 0), 5)
@@ -306,6 +348,9 @@ FROM (
SELECT
'purchase_lot_qt_equals_virtual' AS check_name,
'purchase.purchase' AS contract_model,
b.contract_id,
b.contract_number,
b.line_id,
b.virtual_lot_id,
ROUND(b.lot_qt_quantity, 5) AS observed_value,
@@ -321,6 +366,9 @@ FROM (
SELECT
'sale_lot_qt_equals_virtual' AS check_name,
'sale.sale' AS contract_model,
b.contract_id,
b.contract_number,
b.line_id,
b.virtual_lot_id,
ROUND(b.lot_qt_quantity, 5) AS observed_value,
@@ -336,6 +384,9 @@ FROM (
SELECT
'purchase_cross_category_manual_review' AS check_name,
'purchase.purchase' AS contract_model,
q.contract_id,
q.contract_number,
q.line_id,
q.virtual_lot_id,
(q.physical_cross_category_count + q.virtual_cross_category_count)::numeric,
@@ -350,6 +401,9 @@ FROM (
SELECT
'sale_cross_category_manual_review' AS check_name,
'sale.sale' AS contract_model,
q.contract_id,
q.contract_number,
q.line_id,
q.virtual_lot_id,
(q.physical_cross_category_count + q.virtual_cross_category_count)::numeric,
@@ -364,6 +418,9 @@ FROM (
SELECT
'lot_qt_cross_category_manual_review' AS check_name,
'purchase.purchase' AS contract_model,
b.contract_id,
b.contract_number,
b.line_id,
b.virtual_lot_id,
b.lot_qt_cross_category_count::numeric,
@@ -378,6 +435,9 @@ FROM (
SELECT
'sale_lot_qt_cross_category_manual_review' AS check_name,
'sale.sale' AS contract_model,
b.contract_id,
b.contract_number,
b.line_id,
b.virtual_lot_id,
b.lot_qt_cross_category_count::numeric,
@@ -387,5 +447,23 @@ FROM (
AS detail
FROM sale_lot_qt_balance b
WHERE b.lot_qt_cross_category_count > 0
UNION ALL
SELECT
'lot_qt_without_lot_link' AS check_name,
NULL::text AS contract_model,
NULL::integer AS contract_id,
NULL::text AS contract_number,
NULL::integer AS line_id,
NULL::integer AS virtual_lot_id,
COALESCE(lqt.lot_quantity, 0)::numeric AS observed_value,
0::numeric AS expected_value,
COALESCE(lqt.lot_quantity, 0)::numeric AS diff,
'lot_qt row has neither lot_p nor lot_s; zero rows are allowed only when linked to at least one virtual lot'
AS detail
FROM lot_qt lqt
WHERE lqt.lot_p IS NULL
AND lqt.lot_s IS NULL
) issues
ORDER BY check_name, line_id, virtual_lot_id;
ORDER BY check_name, contract_number, line_id, virtual_lot_id;