@things-factory/warehouse-base 4.3.686 → 4.3.689
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist-server/service/inventory-change/inventory-change-mutation.js +1 -1
- package/dist-server/service/inventory-change/inventory-change-mutation.js.map +1 -1
- package/dist-server/service/inventory-history/inventory-history-query.js +208 -234
- package/dist-server/service/inventory-history/inventory-history-query.js.map +1 -1
- package/package.json +10 -10
- package/server/service/inventory-change/inventory-change-mutation.ts +0 -1
- package/server/service/inventory-history/inventory-history-query.ts +233 -243
|
@@ -1700,253 +1700,211 @@ async function massageInventoryPalletSummary(tx: EntityManager, params: ListPara
|
|
|
1700
1700
|
let toDate = params.filters.find(data => data.name === 'toDate')
|
|
1701
1701
|
let hasTransactionOrBalanceFilter = params.filters.find(data => data.name === 'hasTransactionOrBalance')
|
|
1702
1702
|
|
|
1703
|
-
let hasTransactionOrBalanceQuery = ''
|
|
1703
|
+
let hasTransactionOrBalanceQuery = 'TRUE'
|
|
1704
1704
|
if (hasTransactionOrBalanceFilter && hasTransactionOrBalanceFilter.value) {
|
|
1705
|
-
hasTransactionOrBalanceQuery = '
|
|
1705
|
+
hasTransactionOrBalanceQuery = '(merged.opening_qty > 0 or merged.total_in_qty > 0 or merged.adjustment_qty > 0)'
|
|
1706
1706
|
}
|
|
1707
1707
|
|
|
1708
|
+
// Build a slimmer history table for pallet summary to minimize scans
|
|
1708
1709
|
await tx.query(
|
|
1709
1710
|
`
|
|
1710
|
-
|
|
1711
|
-
|
|
1712
|
-
|
|
1713
|
-
|
|
1714
|
-
|
|
1715
|
-
|
|
1716
|
-
|
|
1717
|
-
|
|
1718
|
-
|
|
1719
|
-
|
|
1720
|
-
|
|
1721
|
-
|
|
1722
|
-
|
|
1723
|
-
)
|
|
1724
|
-
|
|
1725
|
-
|
|
1726
|
-
|
|
1727
|
-
|
|
1728
|
-
|
|
1729
|
-
|
|
1730
|
-
|
|
1731
|
-
|
|
1732
|
-
|
|
1733
|
-
row_number() over (partition by h.pallet_id order by h.created_at desc, h.seq desc) as rn
|
|
1734
|
-
from temp_inv_history h
|
|
1735
|
-
join params p on true
|
|
1736
|
-
where h.created_at <= p.t1
|
|
1737
|
-
) x
|
|
1738
|
-
where rn = 1 and status = 'STORED'
|
|
1739
|
-
),
|
|
1740
|
-
opening_agg as (
|
|
1741
|
-
select
|
|
1742
|
-
p.sku as product_sku,
|
|
1743
|
-
p.id as product_id,
|
|
1744
|
-
p.name as product_name,
|
|
1745
|
-
p.description as product_description,
|
|
1746
|
-
p.type as product_type,
|
|
1747
|
-
count(*)::int as opening_qty
|
|
1748
|
-
from opening_last_asof o
|
|
1749
|
-
join temp_products p on p.id = o.product_id
|
|
1750
|
-
group by p.sku, p.id, p.name, p.description, p.type
|
|
1751
|
-
),
|
|
1752
|
-
|
|
1753
|
-
/* ---- Arrivals inside window: first arrival-like row per pallet (your rule) ---- */
|
|
1754
|
-
invIn as (
|
|
1755
|
-
select b.*,
|
|
1756
|
-
row_number() over (partition by b.pallet_id order by b.created_at, b.seq) as rn
|
|
1757
|
-
from base b
|
|
1758
|
-
join params p on true
|
|
1759
|
-
where b.transaction_type in ('UNLOADING','NEW','CANCEL_ORDER')
|
|
1760
|
-
and b.created_at >= p.t1
|
|
1761
|
-
),
|
|
1762
|
-
invIn_first as (
|
|
1763
|
-
select
|
|
1764
|
-
pallet_id, seq, status, transaction_type,
|
|
1765
|
-
product_sku, product_id, product_name, product_description, product_type,
|
|
1766
|
-
inventory_history_id, packing_type, packing_size, qty, opening_qty, created_at
|
|
1767
|
-
from invIn
|
|
1768
|
-
where rn = 1
|
|
1769
|
-
),
|
|
1770
|
-
|
|
1771
|
-
/* ---- TERMINATED reps (incl. ADJUSTMENT terminations), using your runs logic ---- */
|
|
1772
|
-
status_runs as (
|
|
1773
|
-
select
|
|
1774
|
-
endData.pallet_id,
|
|
1775
|
-
min(endData.created_at) as started_at,
|
|
1776
|
-
max(endData.created_at) as ended_at,
|
|
1777
|
-
min(endData.seq) as min_seq,
|
|
1778
|
-
max(endData.seq) as max_seq,
|
|
1779
|
-
endData.status
|
|
1780
|
-
from (
|
|
1781
|
-
select startData.*,
|
|
1782
|
-
sum(startflag) over (partition by startData.pallet_id order by startData.seq) as grp
|
|
1783
|
-
from (
|
|
1784
|
-
select s.*,
|
|
1785
|
-
case when lag(s.status) over (partition by s.pallet_id order by s.seq) = s.status then 0 else 1 end as startflag
|
|
1786
|
-
from temp_inv_history s
|
|
1787
|
-
) startData
|
|
1788
|
-
) endData
|
|
1789
|
-
group by endData.pallet_id, endData.status, endData.grp
|
|
1790
|
-
),
|
|
1791
|
-
invOut_base as (
|
|
1792
|
-
select b.*, r.started_at
|
|
1793
|
-
from base b
|
|
1794
|
-
join status_runs r
|
|
1795
|
-
on r.pallet_id = b.pallet_id
|
|
1796
|
-
and r.min_seq <= b.seq
|
|
1797
|
-
and r.max_seq >= b.seq
|
|
1798
|
-
where b.status = 'TERMINATED'
|
|
1799
|
-
and b.transaction_type in ('TERMINATED','ADJUSTMENT')
|
|
1800
|
-
),
|
|
1801
|
-
|
|
1802
|
-
/* ---- Transfer pairing (seq-gap tolerant & tolerant txn tags) ---- */
|
|
1803
|
-
/* STORED side in-window; pair to nearest prior TERMINATED (from raw history), different product */
|
|
1804
|
-
adj_stored AS (
|
|
1805
|
-
SELECT b.*
|
|
1806
|
-
FROM base b
|
|
1807
|
-
JOIN params p ON TRUE
|
|
1808
|
-
WHERE b.status = 'STORED'
|
|
1809
|
-
AND b.created_at BETWEEN p.t1 AND p.t2
|
|
1810
|
-
),
|
|
1811
|
-
adj_pairs AS (
|
|
1812
|
-
SELECT
|
|
1813
|
-
s.pallet_id,
|
|
1814
|
-
s.seq AS stored_seq,
|
|
1815
|
-
t.seq AS terminated_seq,
|
|
1816
|
-
s.product_id AS new_product_id,
|
|
1817
|
-
t.product_id AS old_product_id,
|
|
1818
|
-
s.inventory_history_id AS stored_inventory_history_id,
|
|
1819
|
-
t.inventory_history_id AS terminated_inventory_history_id,
|
|
1820
|
-
s.created_at AS stored_at,
|
|
1821
|
-
t.created_at AS terminated_at,
|
|
1822
|
-
s.transaction_type AS stored_txn,
|
|
1823
|
-
t.transaction_type AS terminated_txn
|
|
1824
|
-
FROM adj_stored s
|
|
1825
|
-
JOIN LATERAL (
|
|
1826
|
-
SELECT t.*
|
|
1827
|
-
FROM temp_inv_history t -- use raw history (old product may be outside temp_products)
|
|
1828
|
-
WHERE t.pallet_id = s.pallet_id
|
|
1829
|
-
AND t.seq < s.seq
|
|
1830
|
-
AND t.status = 'TERMINATED'
|
|
1831
|
-
ORDER BY t.seq DESC
|
|
1832
|
-
LIMIT 1
|
|
1833
|
-
) t ON TRUE
|
|
1834
|
-
WHERE t.product_id IS DISTINCT FROM s.product_id
|
|
1835
|
-
AND (s.transaction_type='ADJUSTMENT' OR t.transaction_type='ADJUSTMENT')
|
|
1836
|
-
),
|
|
1837
|
-
adj_pairs_terminated_keys AS (
|
|
1838
|
-
SELECT pallet_id, terminated_seq AS seq
|
|
1839
|
-
FROM adj_pairs
|
|
1840
|
-
),
|
|
1841
|
-
|
|
1842
|
-
/* Representative TERMINATED per (pallet, product), EXCLUDING those used by a pair (avoid double-count) */
|
|
1843
|
-
invOut_rep AS (
|
|
1844
|
-
SELECT *
|
|
1845
|
-
FROM (
|
|
1846
|
-
SELECT iob.*,
|
|
1847
|
-
row_number() over (partition by iob.pallet_id, iob.product_id order by iob.seq desc) as rn
|
|
1848
|
-
FROM invOut_base iob
|
|
1849
|
-
LEFT JOIN adj_pairs_terminated_keys k
|
|
1850
|
-
ON k.pallet_id = iob.pallet_id
|
|
1851
|
-
AND k.seq = iob.seq
|
|
1852
|
-
WHERE k.pallet_id IS NULL
|
|
1853
|
-
) z
|
|
1854
|
-
WHERE rn = 1
|
|
1855
|
-
),
|
|
1856
|
-
|
|
1857
|
-
/* Materialize both sides of the paired transfer */
|
|
1858
|
-
adj_pairs_stored_rows AS (
|
|
1859
|
-
SELECT
|
|
1860
|
-
b.pallet_id, b.seq, b.status, b.transaction_type,
|
|
1861
|
-
b.product_sku, b.product_id, b.product_name, b.product_description, b.product_type,
|
|
1862
|
-
b.inventory_history_id, b.packing_type, b.packing_size, b.qty, b.opening_qty, b.created_at
|
|
1863
|
-
FROM base b
|
|
1864
|
-
JOIN adj_pairs ap
|
|
1865
|
-
ON ap.pallet_id = b.pallet_id
|
|
1866
|
-
AND ap.stored_seq = b.seq
|
|
1867
|
-
),
|
|
1868
|
-
adj_pairs_terminated_rows AS (
|
|
1869
|
-
SELECT
|
|
1870
|
-
b.pallet_id, b.seq, b.status, b.transaction_type,
|
|
1871
|
-
b.product_sku, b.product_id, b.product_name, b.product_description, b.product_type,
|
|
1872
|
-
b.inventory_history_id, b.packing_type, b.packing_size, b.qty, b.opening_qty, b.created_at
|
|
1873
|
-
FROM base b
|
|
1874
|
-
JOIN adj_pairs ap
|
|
1875
|
-
ON ap.pallet_id = b.pallet_id
|
|
1876
|
-
AND ap.terminated_seq = b.seq
|
|
1877
|
-
),
|
|
1878
|
-
|
|
1879
|
-
/* ---- Unified stream for window movement ---- */
|
|
1880
|
-
invHistory as (
|
|
1881
|
-
select * from invIn_first
|
|
1882
|
-
union all
|
|
1883
|
-
select
|
|
1884
|
-
pallet_id, seq, status, transaction_type,
|
|
1885
|
-
product_sku, product_id, product_name, product_description, product_type,
|
|
1886
|
-
inventory_history_id, packing_type, packing_size, qty, opening_qty, created_at
|
|
1887
|
-
from invOut_rep
|
|
1888
|
-
union all
|
|
1889
|
-
select * from adj_pairs_stored_rows
|
|
1890
|
-
union all
|
|
1891
|
-
select * from adj_pairs_terminated_rows
|
|
1892
|
-
),
|
|
1893
|
-
|
|
1894
|
-
/* ---- Movement aggregation only (no opening here) ---- */
|
|
1895
|
-
movement_agg as (
|
|
1896
|
-
select
|
|
1897
|
-
ih.product_sku,
|
|
1898
|
-
ih.product_id,
|
|
1899
|
-
ih.product_name,
|
|
1900
|
-
ih.product_description,
|
|
1901
|
-
ih.product_type,
|
|
1902
|
-
|
|
1903
|
-
sum(case when ih.created_at >= (select t1 from params)
|
|
1904
|
-
and ih.created_at <= (select t2 from params) then
|
|
1905
|
-
case when ih.transaction_type in ('UNLOADING','NEW','CANCEL_ORDER') then 1 else 0 end
|
|
1906
|
-
else 0 end)::int as total_in_qty,
|
|
1907
|
-
|
|
1908
|
-
sum(case when ih.created_at >= (select t1 from params)
|
|
1909
|
-
and ih.created_at <= (select t2 from params) then
|
|
1910
|
-
case when ih.status = 'TERMINATED'
|
|
1911
|
-
and ih.transaction_type <> 'ADJUSTMENT' then -1 else 0 end
|
|
1912
|
-
else 0 end)::int as total_out_qty,
|
|
1913
|
-
|
|
1914
|
-
sum(case when ih.created_at >= (select t1 from params)
|
|
1915
|
-
and ih.created_at <= (select t2 from params) then
|
|
1916
|
-
case when ih.status = 'TERMINATED' and ih.transaction_type = 'ADJUSTMENT' then -1
|
|
1917
|
-
when ih.status = 'STORED' and ih.transaction_type = 'ADJUSTMENT' then 1
|
|
1918
|
-
else 0 end
|
|
1919
|
-
else 0 end)::int as adjustment_qty
|
|
1920
|
-
|
|
1921
|
-
from invHistory ih
|
|
1922
|
-
group by ih.product_sku, ih.product_id, ih.product_name, ih.product_description, ih.product_type
|
|
1923
|
-
),
|
|
1924
|
-
|
|
1925
|
-
/* ---- Combine opening snapshot + window movement ---- */
|
|
1926
|
-
combined as (
|
|
1927
|
-
select
|
|
1928
|
-
coalesce(o.product_sku, m.product_sku) as product_sku,
|
|
1929
|
-
coalesce(o.product_id, m.product_id) as product_id,
|
|
1930
|
-
coalesce(o.product_name,m.product_name) as product_name,
|
|
1931
|
-
coalesce(o.product_description,m.product_description) as product_description,
|
|
1932
|
-
coalesce(o.product_type,m.product_type) as product_type,
|
|
1933
|
-
|
|
1934
|
-
coalesce(o.opening_qty, 0) as opening_qty,
|
|
1935
|
-
coalesce(m.total_in_qty, 0) as total_in_qty,
|
|
1936
|
-
coalesce(m.total_out_qty, 0) as total_out_qty,
|
|
1937
|
-
coalesce(m.adjustment_qty, 0) as adjustment_qty
|
|
1938
|
-
from opening_agg o
|
|
1939
|
-
full outer join movement_agg m
|
|
1940
|
-
on m.product_id = o.product_id
|
|
1941
|
-
)
|
|
1711
|
+
create temp table temp_inv_history_ps on commit drop as (
|
|
1712
|
+
select pallet_id, product_id, seq, status, transaction_type, created_at
|
|
1713
|
+
from temp_inv_history
|
|
1714
|
+
where (transaction_type in ('UNLOADING','NEW','CANCEL_ORDER','ADJUSTMENT')
|
|
1715
|
+
or status in ('STORED','TERMINATED'))
|
|
1716
|
+
and created_at <= $1::timestamp
|
|
1717
|
+
);
|
|
1718
|
+
`,
|
|
1719
|
+
[toDate.value]
|
|
1720
|
+
)
|
|
1721
|
+
|
|
1722
|
+
await tx.query(
|
|
1723
|
+
`
|
|
1724
|
+
CREATE INDEX IF NOT EXISTS idx_tihps_created_at ON temp_inv_history_ps (created_at);
|
|
1725
|
+
CREATE INDEX IF NOT EXISTS idx_tihps_pallet_seq ON temp_inv_history_ps (pallet_id, seq);
|
|
1726
|
+
CREATE INDEX IF NOT EXISTS idx_tihps_pallet_product_seq ON temp_inv_history_ps (pallet_id, product_id, seq);
|
|
1727
|
+
CREATE INDEX IF NOT EXISTS idx_tihps_product ON temp_inv_history_ps (product_id);
|
|
1728
|
+
CREATE INDEX IF NOT EXISTS idx_tihps_product_created ON temp_inv_history_ps (product_id, created_at);
|
|
1729
|
+
CREATE INDEX IF NOT EXISTS idx_tihps_status ON temp_inv_history_ps (status);
|
|
1730
|
+
CREATE INDEX IF NOT EXISTS idx_tihps_txn ON temp_inv_history_ps (transaction_type);
|
|
1731
|
+
ANALYZE temp_inv_history_ps;
|
|
1732
|
+
`
|
|
1733
|
+
)
|
|
1942
1734
|
|
|
1943
|
-
|
|
1944
|
-
|
|
1945
|
-
|
|
1946
|
-
|
|
1947
|
-
|
|
1948
|
-
|
|
1949
|
-
|
|
1735
|
+
await tx.query(
|
|
1736
|
+
`
|
|
1737
|
+
-- Params:
|
|
1738
|
+
-- $1 = t1 ::timestamp
|
|
1739
|
+
-- $2 = t2 ::timestamp
|
|
1740
|
+
|
|
1741
|
+
CREATE TEMP TABLE temp_inventory_pallet_summary ON COMMIT DROP AS
|
|
1742
|
+
WITH
|
|
1743
|
+
params AS (SELECT $1::timestamp AS t1, $2::timestamp AS t2),
|
|
1744
|
+
|
|
1745
|
+
/* Pre-filtered slices (minimal cols) */
|
|
1746
|
+
rows_le_t1 AS (
|
|
1747
|
+
SELECT pallet_id, product_id, seq, status
|
|
1748
|
+
FROM temp_inv_history_ps
|
|
1749
|
+
WHERE created_at <= (SELECT t1 FROM params)
|
|
1750
|
+
),
|
|
1751
|
+
rows_win AS (
|
|
1752
|
+
SELECT pallet_id, product_id, seq, status, transaction_type
|
|
1753
|
+
FROM temp_inv_history_ps
|
|
1754
|
+
WHERE created_at BETWEEN (SELECT t1 FROM params) AND (SELECT t2 FROM params)
|
|
1755
|
+
),
|
|
1756
|
+
rows_le_t2 AS (
|
|
1757
|
+
SELECT pallet_id, product_id, seq, status, transaction_type
|
|
1758
|
+
FROM temp_inv_history_ps
|
|
1759
|
+
WHERE created_at <= (SELECT t2 FROM params)
|
|
1760
|
+
),
|
|
1761
|
+
|
|
1762
|
+
/* Opening (<= t1): last-by-seq per pallet, must be STORED */
|
|
1763
|
+
opening_last_asof AS (
|
|
1764
|
+
SELECT DISTINCT ON (h.pallet_id) h.pallet_id, h.product_id, h.seq, h.status
|
|
1765
|
+
FROM rows_le_t1 h
|
|
1766
|
+
ORDER BY h.pallet_id, h.seq DESC
|
|
1767
|
+
),
|
|
1768
|
+
opening_anchor AS (
|
|
1769
|
+
SELECT pallet_id, product_id
|
|
1770
|
+
FROM opening_last_asof
|
|
1771
|
+
WHERE status = 'STORED'
|
|
1772
|
+
),
|
|
1773
|
+
|
|
1774
|
+
/* Closing (<= t2): last STORED per (pallet, product) by seq + validity */
|
|
1775
|
+
closing_last_stored AS (
|
|
1776
|
+
SELECT DISTINCT ON (h.pallet_id, h.product_id) h.pallet_id, h.product_id, h.seq
|
|
1777
|
+
FROM rows_le_t2 h
|
|
1778
|
+
WHERE h.status = 'STORED'
|
|
1779
|
+
ORDER BY h.pallet_id, h.product_id, h.seq DESC
|
|
1780
|
+
),
|
|
1781
|
+
last_term_by_pair AS (
|
|
1782
|
+
SELECT DISTINCT ON (h.pallet_id, h.product_id) h.pallet_id, h.product_id, h.seq AS last_term_seq
|
|
1783
|
+
FROM rows_le_t2 h
|
|
1784
|
+
WHERE h.status = 'TERMINATED'
|
|
1785
|
+
ORDER BY h.pallet_id, h.product_id, h.seq DESC
|
|
1786
|
+
),
|
|
1787
|
+
inbound_after_term AS (
|
|
1788
|
+
SELECT cls.pallet_id, cls.product_id
|
|
1789
|
+
FROM closing_last_stored cls
|
|
1790
|
+
LEFT JOIN last_term_by_pair lt
|
|
1791
|
+
ON lt.pallet_id = cls.pallet_id AND lt.product_id = cls.product_id
|
|
1792
|
+
WHERE EXISTS (
|
|
1793
|
+
SELECT 1
|
|
1794
|
+
FROM rows_le_t2 h
|
|
1795
|
+
WHERE h.pallet_id = cls.pallet_id
|
|
1796
|
+
AND h.product_id = cls.product_id
|
|
1797
|
+
AND h.transaction_type IN ('UNLOADING','NEW','CANCEL_ORDER')
|
|
1798
|
+
AND h.seq <= cls.seq
|
|
1799
|
+
AND (lt.last_term_seq IS NULL OR h.seq > lt.last_term_seq)
|
|
1800
|
+
)
|
|
1801
|
+
),
|
|
1802
|
+
valid_closing AS (
|
|
1803
|
+
SELECT cls.pallet_id, cls.product_id
|
|
1804
|
+
FROM closing_last_stored cls
|
|
1805
|
+
LEFT JOIN inbound_after_term ia
|
|
1806
|
+
ON ia.pallet_id = cls.pallet_id AND ia.product_id = cls.product_id
|
|
1807
|
+
LEFT JOIN last_term_by_pair lt
|
|
1808
|
+
ON lt.pallet_id = cls.pallet_id AND lt.product_id = cls.product_id
|
|
1809
|
+
WHERE lt.last_term_seq IS NULL OR ia.pallet_id IS NOT NULL
|
|
1810
|
+
),
|
|
1811
|
+
closing_anchor AS (
|
|
1812
|
+
SELECT pallet_id, product_id FROM valid_closing
|
|
1813
|
+
),
|
|
1814
|
+
|
|
1815
|
+
/* Movement presence in window */
|
|
1816
|
+
inbound_pairs AS (
|
|
1817
|
+
SELECT pallet_id, product_id
|
|
1818
|
+
FROM rows_win
|
|
1819
|
+
WHERE transaction_type IN ('UNLOADING','NEW','CANCEL_ORDER')
|
|
1820
|
+
GROUP BY pallet_id, product_id
|
|
1821
|
+
),
|
|
1822
|
+
terminated_pairs AS (
|
|
1823
|
+
SELECT pallet_id, product_id
|
|
1824
|
+
FROM rows_win
|
|
1825
|
+
WHERE status = 'TERMINATED' AND transaction_type <> 'ADJUSTMENT'
|
|
1826
|
+
GROUP BY pallet_id, product_id
|
|
1827
|
+
),
|
|
1828
|
+
adjustment_last AS (
|
|
1829
|
+
SELECT x.pallet_id, x.product_id,
|
|
1830
|
+
CASE WHEN x.status = 'TERMINATED' THEN -1
|
|
1831
|
+
WHEN x.status = 'STORED' THEN 1
|
|
1832
|
+
ELSE 0 END AS adj_sign
|
|
1833
|
+
FROM (
|
|
1834
|
+
SELECT a.pallet_id, a.product_id, MAX(a.seq) AS max_seq
|
|
1835
|
+
FROM rows_win a
|
|
1836
|
+
WHERE a.transaction_type = 'ADJUSTMENT'
|
|
1837
|
+
GROUP BY a.pallet_id, a.product_id
|
|
1838
|
+
) s
|
|
1839
|
+
JOIN rows_win x
|
|
1840
|
+
ON x.pallet_id = s.pallet_id AND x.product_id = s.product_id AND x.seq = s.max_seq
|
|
1841
|
+
),
|
|
1842
|
+
|
|
1843
|
+
/* Union anchor (opening OR any movement OR valid closing) */
|
|
1844
|
+
anchor_union AS (
|
|
1845
|
+
SELECT * FROM opening_anchor
|
|
1846
|
+
UNION ALL
|
|
1847
|
+
SELECT * FROM inbound_pairs
|
|
1848
|
+
UNION ALL
|
|
1849
|
+
SELECT * FROM terminated_pairs
|
|
1850
|
+
UNION ALL
|
|
1851
|
+
SELECT * FROM closing_anchor
|
|
1852
|
+
),
|
|
1853
|
+
anchor_distinct AS (
|
|
1854
|
+
SELECT DISTINCT pallet_id, product_id FROM anchor_union
|
|
1855
|
+
),
|
|
1856
|
+
|
|
1857
|
+
/* Opening aggregation (anchored) */
|
|
1858
|
+
opening_agg AS (
|
|
1859
|
+
SELECT ol.product_id,
|
|
1860
|
+
COUNT(*) FILTER (WHERE ol.status = 'STORED')::int AS opening_qty
|
|
1861
|
+
FROM opening_last_asof ol
|
|
1862
|
+
JOIN anchor_distinct au ON au.pallet_id = ol.pallet_id AND au.product_id = ol.product_id
|
|
1863
|
+
GROUP BY ol.product_id
|
|
1864
|
+
),
|
|
1865
|
+
|
|
1866
|
+
/* Movement aggregation (anchored) */
|
|
1867
|
+
movement_agg AS (
|
|
1868
|
+
SELECT
|
|
1869
|
+
COALESCE(inb.product_id, term.product_id, adj.product_id) AS product_id,
|
|
1870
|
+
SUM((inb.pallet_id IS NOT NULL)::int) AS total_in_qty,
|
|
1871
|
+
SUM((term.pallet_id IS NOT NULL)::int) AS total_out_qty,
|
|
1872
|
+
COALESCE(SUM(adj.adj_sign), 0)::int AS adjustment_qty
|
|
1873
|
+
FROM anchor_distinct au
|
|
1874
|
+
LEFT JOIN inbound_pairs inb ON inb.pallet_id = au.pallet_id AND inb.product_id = au.product_id
|
|
1875
|
+
LEFT JOIN terminated_pairs term ON term.pallet_id = au.pallet_id AND term.product_id = au.product_id
|
|
1876
|
+
LEFT JOIN adjustment_last adj ON adj.pallet_id = au.pallet_id AND adj.product_id = au.product_id
|
|
1877
|
+
GROUP BY COALESCE(inb.product_id, term.product_id, adj.product_id)
|
|
1878
|
+
),
|
|
1879
|
+
|
|
1880
|
+
merged AS (
|
|
1881
|
+
SELECT
|
|
1882
|
+
COALESCE(o.product_id, m.product_id) AS product_id,
|
|
1883
|
+
COALESCE(o.opening_qty, 0) AS opening_qty,
|
|
1884
|
+
COALESCE(m.total_in_qty, 0) AS total_in_qty,
|
|
1885
|
+
COALESCE(m.total_out_qty, 0) AS total_out_qty,
|
|
1886
|
+
COALESCE(m.adjustment_qty, 0) AS adjustment_qty
|
|
1887
|
+
FROM opening_agg o
|
|
1888
|
+
FULL JOIN movement_agg m ON m.product_id = o.product_id
|
|
1889
|
+
)
|
|
1890
|
+
|
|
1891
|
+
SELECT
|
|
1892
|
+
p.sku AS product_sku,
|
|
1893
|
+
p.id AS product_id,
|
|
1894
|
+
p.name AS product_name,
|
|
1895
|
+
p.description AS product_description,
|
|
1896
|
+
p.type AS product_type,
|
|
1897
|
+
COALESCE(merged.opening_qty, 0) AS opening_qty,
|
|
1898
|
+
COALESCE(merged.total_in_qty, 0) AS total_in_qty,
|
|
1899
|
+
COALESCE(merged.total_out_qty, 0) AS total_out_qty,
|
|
1900
|
+
COALESCE(merged.adjustment_qty, 0) AS adjustment_qty,
|
|
1901
|
+
(COALESCE(merged.opening_qty, 0)
|
|
1902
|
+
+ COALESCE(merged.total_in_qty, 0)
|
|
1903
|
+
+ COALESCE(merged.total_out_qty, 0)
|
|
1904
|
+
+ COALESCE(merged.adjustment_qty, 0))::int AS closing_qty
|
|
1905
|
+
FROM merged
|
|
1906
|
+
JOIN temp_products p ON p.id = merged.product_id
|
|
1907
|
+
WHERE ${hasTransactionOrBalanceQuery};
|
|
1950
1908
|
`,
|
|
1951
1909
|
[fromDate.value, toDate.value]
|
|
1952
1910
|
)
|
|
@@ -2012,6 +1970,13 @@ async function productsQuery(tx: EntityManager, params: ListParam, bizplace: Biz
|
|
|
2012
1970
|
)`,
|
|
2013
1971
|
[bizplace.id]
|
|
2014
1972
|
)
|
|
1973
|
+
|
|
1974
|
+
await tx.query(
|
|
1975
|
+
`
|
|
1976
|
+
CREATE INDEX IF NOT EXISTS idx_tprod_id ON temp_products (id);
|
|
1977
|
+
ANALYZE temp_products;
|
|
1978
|
+
`
|
|
1979
|
+
)
|
|
2015
1980
|
}
|
|
2016
1981
|
|
|
2017
1982
|
async function filterInventoryQuery(tx: EntityManager, params: ListParam, bizplace: Bizplace, context: any) {
|
|
@@ -2054,12 +2019,24 @@ async function filterInventoryQuery(tx: EntityManager, params: ListParam, bizpla
|
|
|
2054
2019
|
WHERE ih.domain_id = $1
|
|
2055
2020
|
AND ih.bizplace_id = $2
|
|
2056
2021
|
AND ih.created_at <= $3
|
|
2057
|
-
AND (
|
|
2022
|
+
AND EXISTS (SELECT 1 FROM temp_products prd WHERE prd.id = ih.product_id::uuid)
|
|
2023
|
+
${batchNoQuery}
|
|
2058
2024
|
)
|
|
2059
2025
|
`,
|
|
2060
2026
|
[context.state.domain.id, bizplace.id, toDate.value]
|
|
2061
2027
|
)
|
|
2062
2028
|
|
|
2029
|
+
// Speed up joins and windowed lookups that follow
|
|
2030
|
+
await tx.query(
|
|
2031
|
+
`
|
|
2032
|
+
CREATE INDEX IF NOT EXISTS idx_tfh_pallet_domain ON temp_filtered_histories (pallet_id, domain_id);
|
|
2033
|
+
CREATE INDEX IF NOT EXISTS idx_tfh_product ON temp_filtered_histories (product_id);
|
|
2034
|
+
CREATE INDEX IF NOT EXISTS idx_tfh_created_at ON temp_filtered_histories (created_at);
|
|
2035
|
+
CREATE INDEX IF NOT EXISTS idx_tfh_pallet_seq ON temp_filtered_histories (pallet_id, seq);
|
|
2036
|
+
ANALYZE temp_filtered_histories;
|
|
2037
|
+
`
|
|
2038
|
+
)
|
|
2039
|
+
|
|
2063
2040
|
/* Step 2: build temp_inv_history by joining inventories with indexed temp_filtered_histories and temp_products */
|
|
2064
2041
|
await tx.query(
|
|
2065
2042
|
`
|
|
@@ -2072,8 +2049,21 @@ async function filterInventoryQuery(tx: EntityManager, params: ListParam, bizpla
|
|
|
2072
2049
|
AND ih.domain_id = i2.domain_id
|
|
2073
2050
|
INNER JOIN temp_products prd
|
|
2074
2051
|
ON prd.id = ih.product_id::uuid
|
|
2075
|
-
${batchNoQuery}
|
|
2076
2052
|
)
|
|
2077
2053
|
`
|
|
2078
2054
|
)
|
|
2055
|
+
|
|
2056
|
+
// Critical indexes for the heavy pallet summary query
|
|
2057
|
+
await tx.query(
|
|
2058
|
+
`
|
|
2059
|
+
CREATE INDEX IF NOT EXISTS idx_tih_created_at ON temp_inv_history (created_at);
|
|
2060
|
+
CREATE INDEX IF NOT EXISTS idx_tih_pallet_seq ON temp_inv_history (pallet_id, seq);
|
|
2061
|
+
CREATE INDEX IF NOT EXISTS idx_tih_pallet_product_seq ON temp_inv_history (pallet_id, product_id, seq);
|
|
2062
|
+
CREATE INDEX IF NOT EXISTS idx_tih_product ON temp_inv_history (product_id);
|
|
2063
|
+
CREATE INDEX IF NOT EXISTS idx_tih_pallet_product ON temp_inv_history (pallet_id, product_id);
|
|
2064
|
+
CREATE INDEX IF NOT EXISTS idx_tih_status ON temp_inv_history (status);
|
|
2065
|
+
CREATE INDEX IF NOT EXISTS idx_tih_txn ON temp_inv_history (transaction_type);
|
|
2066
|
+
ANALYZE temp_inv_history;
|
|
2067
|
+
`
|
|
2068
|
+
)
|
|
2079
2069
|
}
|