refactor(schema): rename received_items and timesheets to their real names

RECEIVED_ITEMS -> DELIVERY_NOTE_ITEMS (55 rows): they are the lines on a
delivery note; the old name described an event, not a thing.

TIMESHEETS -> TIMESHEET_ENTRIES (1367 rows): this collection is the time
log, not a timesheet. The name is freed for the uploaded-document
collection created in Task 6.

PocketBase stores relations by collection id, so every relation survived
untouched; row counts asserted intact on both renames.

Two call sites the plan missed: src/app/api/timesheets/import/route.ts
and src/lib/ocr-result-tier.ts. Deliberately preserved the "timesheets"
string literals in pb-types.ts and the import route — those are
data_import_batches.batch_type select values, not collection names, and
changing them would have violated the select constraint.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
DEls 2026-09-11 11:01:40 +02:00
parent a0d335b235
commit 0cdf385df2
12 changed files with 380 additions and 39 deletions

View file

@ -0,0 +1,147 @@
date_logged,vehicle_id,vehicle_description,unit_type,vehicle_qr,litres,odo_reading,latest_consumption,project_code,site_name,record_id,batch_reference,recommended_action
2026-09-01,03ofzpncx5t82z9,N1 Plant Excavator PC210,plant,1974,96,979,12,C26/09,,hemesmi423ny97p,,DELETE (orphan)
2026-09-01,03ofzpncx5t82z9,N1 Plant Excavator PC210,plant,1974,96,979,12,C26/09,,8oiywnjdeqv35f4,xbbzre09uup8nz1,KEEP (yesterday import)
2026-09-01,3jhs3ogv7f8ruj6,TLB centre point,plant,1604,54,5374,4.15384615384615,C26/09,,7ln21ii1bpzy1ol,,DELETE (orphan)
2026-09-01,3jhs3ogv7f8ruj6,TLB centre point,plant,1604,54,5374,4.15384615384615,C26/09,,z60njnwzuj5nvfj,xbbzre09uup8nz1,KEEP (yesterday import)
2026-09-01,6rsd1ugsd6q9msk,Roller ARD Yellow Group,plant,1625,58,12866,6.44444444444444,C26/09,,o36399oyj7gpo8g,,DELETE (orphan)
2026-09-01,6rsd1ugsd6q9msk,Roller ARD Yellow Group,plant,1625,58,12866,6.44444444444444,C26/09,,mu1mnferoat7ght,xbbzre09uup8nz1,KEEP (yesterday import)
2026-09-01,9pdbdmmwtehi6x9,MERC WB02 Mega Plant,plant,1091,84,39933,4.66666666666667,C26/09,,06891ife3d610rg,,DELETE (orphan)
2026-09-01,9pdbdmmwtehi6x9,MERC WB02 Mega Plant,plant,1091,84,39933,4.66666666666667,C26/09,,6p8vandlyomkwse,xbbzre09uup8nz1,KEEP (yesterday import)
2026-09-01,aau3dz4w8g2zled,N1 Plant Excavator CAT,plant,1983,123,7052,13.6666666666667,C26/09,,6kj8i22ryt4bz3m,,DELETE (orphan)
2026-09-01,aau3dz4w8g2zled,N1 Plant Excavator CAT,plant,1983,123,7052,13.6666666666667,C26/09,,e0matzjgzmi2fgq,xbbzre09uup8nz1,KEEP (yesterday import)
2026-09-01,abkx0zcfst41i8y,Bell TLB04 Mega Plant,plant,1167,70,15721,4.375,C26/09,,4phyh051xettimi,,DELETE (orphan)
2026-09-01,abkx0zcfst41i8y,Bell TLB04 Mega Plant,plant,1167,70,15721,4.375,C26/09,,vyajro6x40oh2rl,xbbzre09uup8nz1,KEEP (yesterday import)
2026-09-01,bxk0ezqopjpdo7u,Roller,plant,1007,44,2686,8.8,C26/09,,d7umdm54j8ns7k4,,DELETE (orphan)
2026-09-01,bxk0ezqopjpdo7u,Roller,plant,1007,44,2686,8.8,C26/09,,6b5m8tf4eqsqb1g,xbbzre09uup8nz1,KEEP (yesterday import)
2026-09-01,jby0yvg41384wtx,Loader Jupiter 821C,plant,1113,156,8048,14.1818181818182,C26/09,,ti96xa169870d6h,,DELETE (orphan)
2026-09-01,jby0yvg41384wtx,Loader Jupiter 821C,plant,1113,156,8048,14.1818181818182,C26/09,,f5k4ppn6ilnazyk,xbbzre09uup8nz1,KEEP (yesterday import)
2026-09-01,muppqwvwgh5e3m6,Isuzu Johannes,,1992,32,31156,10.65625,C26/09,,q77gmakv0f5g9hj,,DELETE (orphan)
2026-09-01,muppqwvwgh5e3m6,Isuzu Johannes,,1992,32,31156,10.65625,C26/09,,dt3pzdn6ya3qwch,xbbzre09uup8nz1,KEEP (yesterday import)
2026-09-01,phcy5a8untqbwpm,Center Point TLB 473,plant,1516,79,4525,5.26666666666667,C26/09,,q0qp5gcmcoba6qp,,DELETE (orphan)
2026-09-01,phcy5a8untqbwpm,Center Point TLB 473,plant,1516,79,4525,5.26666666666667,C26/09,,z7oix88n6bsdgdk,xbbzre09uup8nz1,KEEP (yesterday import)
2026-09-01,pkq2cjn4oata4t6,Grader Case Hire,plant,1590,133,932,19,C26/09,,n9k9j1obvt6hlvw,,DELETE (orphan)
2026-09-01,pkq2cjn4oata4t6,Grader Case Hire,plant,1590,133,932,19,C26/09,,anohde1jtenmqvr,xbbzre09uup8nz1,KEEP (yesterday import)
2026-09-01,shjv24qw7p4sksa,Center Point TLB 515,plant,1959,101,4060,3.88461538461538,C26/09,,tmvtzgvq996pudh,,DELETE (orphan)
2026-09-01,shjv24qw7p4sksa,Center Point TLB 515,plant,1959,101,4060,3.88461538461538,C26/09,,023eyqwcyllzziz,xbbzre09uup8nz1,KEEP (yesterday import)
2026-09-01,sw75yhfj05asoef,Isuzu HY58HVGP,,1934,38,15685,11.2894736842105,C26/09,,z6hdjgs9222jyuy,,DELETE (orphan)
2026-09-01,sw75yhfj05asoef,Isuzu HY58HVGP,,1934,38,15685,11.2894736842105,C26/09,,c2cwjyy1olgssbg,xbbzre09uup8nz1,KEEP (yesterday import)
2026-09-01,un37e6yl59z8ol8,Center Point Excavator CAT,plant,1985,214,6067,14.2666666666667,C26/09,,s47pcli75n3fyp1,,DELETE (orphan)
2026-09-01,un37e6yl59z8ol8,Center Point Excavator CAT,plant,1985,214,6067,14.2666666666667,C26/09,,hyrfeyej9c3v3ai,xbbzre09uup8nz1,KEEP (yesterday import)
2026-09-01,vac49hzww505q6t,Center Point Grader,plant,1626,137,5231,0.0583941605839416,C26/09,,b33027ha9r9gv5s,,DELETE (orphan)
2026-09-01,vac49hzww505q6t,Center Point Grader,plant,1626,137,5231,0.0583941605839416,C26/09,,104gv6pe71mfx09,xbbzre09uup8nz1,KEEP (yesterday import)
2026-09-01,vnyq71ybkgcyeqo,Crushing Machine Jupiter,plant,1622,97,0,0,C26/09,,vjgsxb8r01oxnv0,,DELETE (orphan)
2026-09-01,vnyq71ybkgcyeqo,Crushing Machine Jupiter,plant,1622,97,0,0,C26/09,,2c1aiwkleydljpf,xbbzre09uup8nz1,KEEP (yesterday import)
2026-09-01,vq4du1j6kf5jui3,N1 Plant Excavator PC200,plant,1572,127,8196,12.7,C26/09,,yci03ne1xbcdtvy,,DELETE (orphan)
2026-09-01,vq4du1j6kf5jui3,N1 Plant Excavator PC200,plant,1572,127,8196,12.7,C26/09,,siw2fqo7uy01lqv,xbbzre09uup8nz1,KEEP (yesterday import)
2026-09-01,z5ta7k16siceztm,TLB centre point,plant,1586,41,8389,3.72727272727273,C26/09,,cdt2owko229yh2z,,DELETE (orphan)
2026-09-01,z5ta7k16siceztm,TLB centre point,plant,1586,41,8389,3.72727272727273,C26/09,,s6u774l9r977byf,xbbzre09uup8nz1,KEEP (yesterday import)
2026-09-03,03ofzpncx5t82z9,N1 Plant Excavator PC210,plant,1974,141,988,15.6666666666667,C26/09,,wc9sxrskwlhnft8,,DELETE (orphan)
2026-09-03,03ofzpncx5t82z9,N1 Plant Excavator PC210,plant,1974,141,988,15.6666666666667,C26/09,,pf9bo40b2mgi1xj,xbbzre09uup8nz1,KEEP (yesterday import)
2026-09-03,6rsd1ugsd6q9msk,Roller ARD Yellow Group,plant,1625,46,12871,9.2,C26/09,,0ieslcsz6zgfpq3,,DELETE (orphan)
2026-09-03,6rsd1ugsd6q9msk,Roller ARD Yellow Group,plant,1625,46,12871,9.2,C26/09,,taof4t1e95vn1uw,xbbzre09uup8nz1,KEEP (yesterday import)
2026-09-03,9terh30urf4b3r5,Water Truck Go 2Guys,plant,1614,194,870880,0.402061855670103,C26/09,,h2mcu71rc9o5738,,DELETE (orphan)
2026-09-03,9terh30urf4b3r5,Water Truck Go 2Guys,plant,1614,194,870880,0.402061855670103,C26/09,,uagxthxdnjnifv0,xbbzre09uup8nz1,KEEP (yesterday import)
2026-09-03,aau3dz4w8g2zled,N1 Plant Excavator CAT,plant,1983,155,7062,15.5,C26/09,,dnw32c0ds73wpgd,,DELETE (orphan)
2026-09-03,aau3dz4w8g2zled,N1 Plant Excavator CAT,plant,1983,155,7062,15.5,C26/09,,9hnl28jj8echcxk,xbbzre09uup8nz1,KEEP (yesterday import)
2026-09-03,abkx0zcfst41i8y,Bell TLB04 Mega Plant,plant,1167,57,15733,4.75,C26/09,,337solxjygn5sde,,DELETE (orphan)
2026-09-03,abkx0zcfst41i8y,Bell TLB04 Mega Plant,plant,1167,57,15733,4.75,C26/09,,b5k8ptg5g16ax4m,xbbzre09uup8nz1,KEEP (yesterday import)
2026-09-03,dfrv3e65t9q7aem,Isuzu MF88YZGP Justice,,1999,36,38977,10.1111111111111,C26/09,,7scnb0zagq5p114,,DELETE (orphan)
2026-09-03,dfrv3e65t9q7aem,Isuzu MF88YZGP Justice,,1999,36,38977,10.1111111111111,C26/09,,d13t7nxobo7y711,xbbzre09uup8nz1,KEEP (yesterday import)
2026-09-03,jby0yvg41384wtx,Loader Jupiter 821C,plant,1113,214,8062,15.2857142857143,C26/09,,t9gfvosgy52quhs,,DELETE (orphan)
2026-09-03,jby0yvg41384wtx,Loader Jupiter 821C,plant,1113,214,8062,15.2857142857143,C26/09,,atnkay0zikdpxa0,xbbzre09uup8nz1,KEEP (yesterday import)
2026-09-03,pkq2cjn4oata4t6,Grader Case Hire,plant,1590,308,946,22,C26/09,,a7nplkkg0j6m54u,,DELETE (orphan)
2026-09-03,pkq2cjn4oata4t6,Grader Case Hire,plant,1590,308,946,22,C26/09,,x25iqpi7gczvlx0,xbbzre09uup8nz1,KEEP (yesterday import)
2026-09-03,qnig4z1earte98c,Isuzu MY85HGGP,,1936,50,8951,10,C26/09,,8pwp9xjfqzks94i,,DELETE (orphan)
2026-09-03,qnig4z1earte98c,Isuzu MY85HGGP,,1936,50,8951,10,C26/09,,kl9zupnrtfchoel,xbbzre09uup8nz1,KEEP (yesterday import)
2026-09-03,vac49hzww505q6t,Center Point Grader,plant,1626,156,5241,0.0641025641025641,C26/09,,0pdgblrmhsqh88e,,DELETE (orphan)
2026-09-03,vac49hzww505q6t,Center Point Grader,plant,1626,156,5241,0.0641025641025641,C26/09,,uryd5j1cc2q6lkd,xbbzre09uup8nz1,KEEP (yesterday import)
2026-09-03,vnyq71ybkgcyeqo,Crushing Machine Jupiter,plant,1622,147,0,0,C26/09,,e1c8af1g0pur2l5,,DELETE (orphan)
2026-09-03,vnyq71ybkgcyeqo,Crushing Machine Jupiter,plant,1622,147,0,0,C26/09,,s7jw449xz7498sj,xbbzre09uup8nz1,KEEP (yesterday import)
2026-09-07,03ofzpncx5t82z9,N1 Plant Excavator PC210,plant,1974,81,995,11.5714285714286,C26/09,,4w5csmbbznlppce,,DELETE (orphan)
2026-09-07,03ofzpncx5t82z9,N1 Plant Excavator PC210,plant,1974,81,995,11.5714285714286,C26/09,,pglg45tp8ivvqqb,xbbzre09uup8nz1,KEEP (yesterday import)
2026-09-07,3jhs3ogv7f8ruj6,TLB centre point,plant,1604,122,5399,4.88,C26/09,,5pcy2uwei818fsf,,DELETE (orphan)
2026-09-07,3jhs3ogv7f8ruj6,TLB centre point,plant,1604,122,5399,4.88,C26/09,,evzmk4jr6ugi4du,xbbzre09uup8nz1,KEEP (yesterday import)
2026-09-07,6rsd1ugsd6q9msk,Roller ARD Yellow Group,plant,1625,35,12874,11.6666666666667,C26/09,,orxpy7y0pzj5pvx,,DELETE (orphan)
2026-09-07,6rsd1ugsd6q9msk,Roller ARD Yellow Group,plant,1625,35,12874,11.6666666666667,C26/09,,i71znao8gzlrnv1,xbbzre09uup8nz1,KEEP (yesterday import)
2026-09-07,9pdbdmmwtehi6x9,MERC WB02 Mega Plant,plant,1091,116,39951,6.44444444444444,C26/09,,af05gxh7bsvavbz,,DELETE (orphan)
2026-09-07,9pdbdmmwtehi6x9,MERC WB02 Mega Plant,plant,1091,116,39951,6.44444444444444,C26/09,,shlizhr6au4hwhr,xbbzre09uup8nz1,KEEP (yesterday import)
2026-09-07,aau3dz4w8g2zled,N1 Plant Excavator CAT,plant,1983,49,7067,9.8,C26/09,,zwtwuctx6sqbvly,,DELETE (orphan)
2026-09-07,aau3dz4w8g2zled,N1 Plant Excavator CAT,plant,1983,49,7067,9.8,C26/09,,e0lzl3ddqgmzt17,xbbzre09uup8nz1,KEEP (yesterday import)
2026-09-07,abkx0zcfst41i8y,Bell TLB04 Mega Plant,plant,1167,47,15741,5.875,C26/09,,5h6zseiwqz6yio5,,DELETE (orphan)
2026-09-07,abkx0zcfst41i8y,Bell TLB04 Mega Plant,plant,1167,47,15741,5.875,C26/09,,6uiwgnm5m4p6z47,xbbzre09uup8nz1,KEEP (yesterday import)
2026-09-07,b6s0ptwj7s6vgky,Tipper truck The Big AB,plant,1623,166,0,0,C26/09,,bvvaxb5t346vu5q,,DELETE (orphan)
2026-09-07,b6s0ptwj7s6vgky,Tipper truck The Big AB,plant,1623,166,0,0,C26/09,,od3e950lh35psyq,xbbzre09uup8nz1,KEEP (yesterday import)
2026-09-07,b6s0ptwj7s6vgky,Tipper truck The Big AB,plant,1623,200,32623,0.00681082921845735,C26/09,,6u4g1emkg6y1csi,,DELETE (orphan)
2026-09-07,b6s0ptwj7s6vgky,Tipper truck The Big AB,plant,1623,200,32623,0.00681082921845735,C26/09,,wj3iq0u14g61sr2,xbbzre09uup8nz1,KEEP (yesterday import)
2026-09-07,bxk0ezqopjpdo7u,Roller,plant,1007,84,2694,10.5,C26/09,,vc8cd44fhtmq7zj,,DELETE (orphan)
2026-09-07,bxk0ezqopjpdo7u,Roller,plant,1007,84,2694,10.5,C26/09,,pezmylawmu5oxw8,xbbzre09uup8nz1,KEEP (yesterday import)
2026-09-07,e7yb7w7ug54yacf,Tipper truck,plant,1547,150,580613,0.973333333333333,C26/09,,tb1b9p2wgksyv8u,,DELETE (orphan)
2026-09-07,e7yb7w7ug54yacf,Tipper truck,plant,1547,150,580613,0.973333333333333,C26/09,,alrygnvmbpr8hi3,xbbzre09uup8nz1,KEEP (yesterday import)
2026-09-07,jby0yvg41384wtx,Loader Jupiter 821C,plant,1113,113,8070,14.125,C26/09,,9yix9ryf7r1v51y,,DELETE (orphan)
2026-09-07,jby0yvg41384wtx,Loader Jupiter 821C,plant,1113,113,8070,14.125,C26/09,,e41izw0bi7b4zvp,xbbzre09uup8nz1,KEEP (yesterday import)
2026-09-07,muppqwvwgh5e3m6,Isuzu Johannes,,1992,31,31481,10.4838709677419,C26/09,,pvn9t2g9frahvz4,,DELETE (orphan)
2026-09-07,muppqwvwgh5e3m6,Isuzu Johannes,,1992,31,31481,10.4838709677419,C26/09,,a8cgeictqrx9n8s,xbbzre09uup8nz1,KEEP (yesterday import)
2026-09-07,n21wwm4ndbfvktw,Tipper truck Jupiter,plant,1570,118,3829,2.8780487804878,C26/09,,rxrr4mdmcs343n7,,DELETE (orphan)
2026-09-07,n21wwm4ndbfvktw,Tipper truck Jupiter,plant,1570,118,3829,2.8780487804878,C26/09,,padsixufp084cnh,xbbzre09uup8nz1,KEEP (yesterday import)
2026-09-07,phcy5a8untqbwpm,Center Point TLB 473,plant,1516,118,4548,5.1304347826087,C26/09,,mft2g80hvzogfl2,,DELETE (orphan)
2026-09-07,phcy5a8untqbwpm,Center Point TLB 473,plant,1516,118,4548,5.1304347826087,C26/09,,4dnfys22rbvx3k8,xbbzre09uup8nz1,KEEP (yesterday import)
2026-09-07,pkq2cjn4oata4t6,Grader Case Hire,plant,1590,89,952,14.8333333333333,C26/09,,e1o35zc7vbwyjoh,,DELETE (orphan)
2026-09-07,pkq2cjn4oata4t6,Grader Case Hire,plant,1590,89,952,14.8333333333333,C26/09,,zjqspco93lajnt0,xbbzre09uup8nz1,KEEP (yesterday import)
2026-09-07,rkp6s3b40mvhqfr,Pick Up Truck 001,plant,1938,271,300,7.52777777777778,C26/09,,infpasex4akd61l,,DELETE (orphan)
2026-09-07,rkp6s3b40mvhqfr,Pick Up Truck 001,plant,1938,271,300,7.52777777777778,C26/09,,vs5e0zkuggswc0a,xbbzre09uup8nz1,KEEP (yesterday import)
2026-09-07,shjv24qw7p4sksa,Center Point TLB 515,plant,1959,102,4083,4.43478260869565,C26/09,,azz2a3t2xwccxhd,,DELETE (orphan)
2026-09-07,shjv24qw7p4sksa,Center Point TLB 515,plant,1959,102,4083,4.43478260869565,C26/09,,kesbj0zzyc2g6vd,xbbzre09uup8nz1,KEEP (yesterday import)
2026-09-07,sw75yhfj05asoef,Isuzu HY58HVGP,,1934,54,16300,11.3888888888889,C26/09,,oaykvw612kz1t57,,DELETE (orphan)
2026-09-07,sw75yhfj05asoef,Isuzu HY58HVGP,,1934,54,16300,11.3888888888889,C26/09,,pw37zyfyjedegvd,xbbzre09uup8nz1,KEEP (yesterday import)
2026-09-07,un37e6yl59z8ol8,Center Point Excavator CAT,plant,1985,124,6080,9.53846153846154,C26/09,,wqss7j5vey6bds8,,DELETE (orphan)
2026-09-07,un37e6yl59z8ol8,Center Point Excavator CAT,plant,1985,124,6080,9.53846153846154,C26/09,,r5cd5nikfrleucy,xbbzre09uup8nz1,KEEP (yesterday import)
2026-09-07,vac49hzww505q6t,Center Point Grader,plant,1626,105,5249,0.0761904761904762,C26/09,,3bo6qn2bp4tmij2,,DELETE (orphan)
2026-09-07,vac49hzww505q6t,Center Point Grader,plant,1626,105,5249,0.0761904761904762,C26/09,,8t1o0ydx7mfo5hn,xbbzre09uup8nz1,KEEP (yesterday import)
2026-09-07,vq4du1j6kf5jui3,N1 Plant Excavator PC200,plant,1572,319,8219,13.8695652173913,C26/09,,w0k3wzxgk818j9c,,DELETE (orphan)
2026-09-07,vq4du1j6kf5jui3,N1 Plant Excavator PC200,plant,1572,319,8219,13.8695652173913,C26/09,,zp9zqonrwfw6iwc,xbbzre09uup8nz1,KEEP (yesterday import)
2026-09-07,z5ta7k16siceztm,TLB centre point,plant,1586,106,8408,5.57894736842105,C26/09,,xyjpd57h9gyhcpn,,DELETE (orphan)
2026-09-07,z5ta7k16siceztm,TLB centre point,plant,1586,106,8408,5.57894736842105,C26/09,,okv117c28fi8eja,xbbzre09uup8nz1,KEEP (yesterday import)
2026-09-09,03ofzpncx5t82z9,N1 Plant Excavator PC210,plant,1974,112,1006,10.1818181818182,C26/09,,lngcy4x8y1txcmd,,DELETE (orphan)
2026-09-09,03ofzpncx5t82z9,N1 Plant Excavator PC210,plant,1974,112,1006,10.1818181818182,C26/09,,sdz1n4pt1usjdsp,xbbzre09uup8nz1,KEEP (yesterday import)
2026-09-09,3jhs3ogv7f8ruj6,TLB centre point,plant,1604,59,5411,4.91666666666667,C26/09,,g6fpxjttm2qd3g2,,DELETE (orphan)
2026-09-09,3jhs3ogv7f8ruj6,TLB centre point,plant,1604,59,5411,4.91666666666667,C26/09,,8sdh9gpgcagzbxl,xbbzre09uup8nz1,KEEP (yesterday import)
2026-09-09,68n3smofgkrwq93,Can The Hills,,1611,42,0,0,C26/09,,snle25g7jbx7gly,,DELETE (orphan)
2026-09-09,68n3smofgkrwq93,Can The Hills,,1611,42,0,0,C26/09,,cyofbtfuzdx89em,xbbzre09uup8nz1,KEEP (yesterday import)
2026-09-09,6rsd1ugsd6q9msk,Roller ARD Yellow Group,plant,1625,38,12879,7.6,C26/09,,so29f0s9bqps82w,,DELETE (orphan)
2026-09-09,6rsd1ugsd6q9msk,Roller ARD Yellow Group,plant,1625,38,12879,7.6,C26/09,,tpvswbwvmtjqhge,xbbzre09uup8nz1,KEEP (yesterday import)
2026-09-09,76tm3k0o32jneto,Tipper Truck,plant,1589,326,290,0.0950920245398773,C26/09,,k0l2jl6olrwvfh5,,DELETE (orphan)
2026-09-09,76tm3k0o32jneto,Tipper Truck,plant,1589,326,290,0.0950920245398773,C26/09,,vxqbj9feakucdcc,xbbzre09uup8nz1,KEEP (yesterday import)
2026-09-09,9terh30urf4b3r5,Water Truck Go 2Guys,plant,1614,164,870912,0.195121951219512,C26/09,,crff7d5h2l51xso,,DELETE (orphan)
2026-09-09,9terh30urf4b3r5,Water Truck Go 2Guys,plant,1614,164,870912,0.195121951219512,C26/09,,ec8dshvhv05u6pr,xbbzre09uup8nz1,KEEP (yesterday import)
2026-09-09,aau3dz4w8g2zled,N1 Plant Excavator CAT,plant,1983,138,7075,17.25,C26/09,,bomiofuxtb783ui,,DELETE (orphan)
2026-09-09,aau3dz4w8g2zled,N1 Plant Excavator CAT,plant,1983,138,7075,17.25,C26/09,,s9462qzgj6d88j6,xbbzre09uup8nz1,KEEP (yesterday import)
2026-09-09,abkx0zcfst41i8y,Bell TLB04 Mega Plant,plant,1167,73,15755,5.21428571428571,C26/09,,wut55nj2oi94hhk,,DELETE (orphan)
2026-09-09,abkx0zcfst41i8y,Bell TLB04 Mega Plant,plant,1167,73,15755,5.21428571428571,C26/09,,686mq8ybdfylby8,xbbzre09uup8nz1,KEEP (yesterday import)
2026-09-09,bxk0ezqopjpdo7u,Roller,plant,1007,74,2702,9.25,C26/09,,3mr9cfvvbwcnt8a,,DELETE (orphan)
2026-09-09,bxk0ezqopjpdo7u,Roller,plant,1007,74,2702,9.25,C26/09,,vayf90mfk46ahs2,xbbzre09uup8nz1,KEEP (yesterday import)
2026-09-09,dfrv3e65t9q7aem,Isuzu MF88YZGP Justice,,1999,42,39400,10.0714285714286,C26/09,,1dkeu2ni6fmcsv7,,DELETE (orphan)
2026-09-09,dfrv3e65t9q7aem,Isuzu MF88YZGP Justice,,1999,42,39400,10.0714285714286,C26/09,,fi9k9icty9wtycu,xbbzre09uup8nz1,KEEP (yesterday import)
2026-09-09,jby0yvg41384wtx,Loader Jupiter 821C,plant,1113,118,8079,13.1111111111111,C26/09,,cq41xzj4pc70e0x,,DELETE (orphan)
2026-09-09,jby0yvg41384wtx,Loader Jupiter 821C,plant,1113,118,8079,13.1111111111111,C26/09,,cts0lo786nd2pqn,xbbzre09uup8nz1,KEEP (yesterday import)
2026-09-09,muppqwvwgh5e3m6,Isuzu Johannes,,1992,17,31657,10.3529411764706,C26/09,,py3w6s073384e5g,,DELETE (orphan)
2026-09-09,muppqwvwgh5e3m6,Isuzu Johannes,,1992,17,31657,10.3529411764706,C26/09,,pep0z111ozg9g7i,xbbzre09uup8nz1,KEEP (yesterday import)
2026-09-09,phcy5a8untqbwpm,Center Point TLB 473,plant,1516,69,4560,5.75,C26/09,,rvtmdxz09604m8o,,DELETE (orphan)
2026-09-09,phcy5a8untqbwpm,Center Point TLB 473,plant,1516,69,4560,5.75,C26/09,,42cz372hr3at7mz,xbbzre09uup8nz1,KEEP (yesterday import)
2026-09-09,pkq2cjn4oata4t6,Grader Case Hire,plant,1590,219,963,19.9090909090909,C26/09,,mtitlhdlyq83e3p,,DELETE (orphan)
2026-09-09,pkq2cjn4oata4t6,Grader Case Hire,plant,1590,219,963,19.9090909090909,C26/09,,9zaht402raqm4rb,xbbzre09uup8nz1,KEEP (yesterday import)
2026-09-09,qnig4z1earte98c,Isuzu MY85HGGP,,1936,33,9285,10.1212121212121,C26/09,,9hhfz4xcyya9mrq,,DELETE (orphan)
2026-09-09,qnig4z1earte98c,Isuzu MY85HGGP,,1936,33,9285,10.1212121212121,C26/09,,z810mt12qdl4hnl,xbbzre09uup8nz1,KEEP (yesterday import)
2026-09-09,shjv24qw7p4sksa,Center Point TLB 515,plant,1959,26,4091,3.25,C26/09,,hja6auvyiam4e8a,,DELETE (orphan)
2026-09-09,shjv24qw7p4sksa,Center Point TLB 515,plant,1959,26,4091,3.25,C26/09,,m4qr9mphiosb3z2,xbbzre09uup8nz1,KEEP (yesterday import)
2026-09-09,sw75yhfj05asoef,Isuzu HY58HVGP,,1934,24,16595,12.2916666666667,C26/09,,cer4dfv3ag6bpve,,DELETE (orphan)
2026-09-09,sw75yhfj05asoef,Isuzu HY58HVGP,,1934,24,16595,12.2916666666667,C26/09,,t122e5655oz2r9y,xbbzre09uup8nz1,KEEP (yesterday import)
2026-09-09,un37e6yl59z8ol8,Center Point Excavator CAT,plant,1985,215,6097,12.6470588235294,C26/09,,mc6h5h5vp8e1s6s,,DELETE (orphan)
2026-09-09,un37e6yl59z8ol8,Center Point Excavator CAT,plant,1985,215,6097,12.6470588235294,C26/09,,64tgdibvqabfv9x,xbbzre09uup8nz1,KEEP (yesterday import)
2026-09-09,vac49hzww505q6t,Center Point Grader,plant,1626,130,5259,0.0769230769230769,C26/09,,r5ou0332lmc3o7y,,DELETE (orphan)
2026-09-09,vac49hzww505q6t,Center Point Grader,plant,1626,130,5259,0.0769230769230769,C26/09,,bk9i2t1cbnwl1ez,xbbzre09uup8nz1,KEEP (yesterday import)
2026-09-09,vnyq71ybkgcyeqo,Crushing Machine Jupiter,plant,1622,170,0,0,C26/09,,8c25qnehft0tj16,,DELETE (orphan)
2026-09-09,vnyq71ybkgcyeqo,Crushing Machine Jupiter,plant,1622,170,0,0,C26/09,,8u1kdvcx5c554ck,xbbzre09uup8nz1,KEEP (yesterday import)
2026-09-09,vq4du1j6kf5jui3,N1 Plant Excavator PC200,plant,1572,118,8229,11.8,C26/09,,mddwgitouz6g5ob,,DELETE (orphan)
2026-09-09,vq4du1j6kf5jui3,N1 Plant Excavator PC200,plant,1572,118,8229,11.8,C26/09,,tpvf5ckja07mlvt,xbbzre09uup8nz1,KEEP (yesterday import)
2026-09-09,z5ta7k16siceztm,TLB centre point,plant,1586,87,8425,5.11764705882353,C26/09,,tws6zsmny9gwurz,,DELETE (orphan)
2026-09-09,z5ta7k16siceztm,TLB centre point,plant,1586,87,8425,5.11764705882353,C26/09,,g5nqf70j9lrvrwh,xbbzre09uup8nz1,KEEP (yesterday import)
1 date_logged vehicle_id vehicle_description unit_type vehicle_qr litres odo_reading latest_consumption project_code site_name record_id batch_reference recommended_action
2 2026-09-01 03ofzpncx5t82z9 N1 Plant Excavator PC210 plant 1974 96 979 12 C26/09 hemesmi423ny97p DELETE (orphan)
3 2026-09-01 03ofzpncx5t82z9 N1 Plant Excavator PC210 plant 1974 96 979 12 C26/09 8oiywnjdeqv35f4 xbbzre09uup8nz1 KEEP (yesterday import)
4 2026-09-01 3jhs3ogv7f8ruj6 TLB centre point plant 1604 54 5374 4.15384615384615 C26/09 7ln21ii1bpzy1ol DELETE (orphan)
5 2026-09-01 3jhs3ogv7f8ruj6 TLB centre point plant 1604 54 5374 4.15384615384615 C26/09 z60njnwzuj5nvfj xbbzre09uup8nz1 KEEP (yesterday import)
6 2026-09-01 6rsd1ugsd6q9msk Roller ARD Yellow Group plant 1625 58 12866 6.44444444444444 C26/09 o36399oyj7gpo8g DELETE (orphan)
7 2026-09-01 6rsd1ugsd6q9msk Roller ARD Yellow Group plant 1625 58 12866 6.44444444444444 C26/09 mu1mnferoat7ght xbbzre09uup8nz1 KEEP (yesterday import)
8 2026-09-01 9pdbdmmwtehi6x9 MERC WB02 Mega Plant plant 1091 84 39933 4.66666666666667 C26/09 06891ife3d610rg DELETE (orphan)
9 2026-09-01 9pdbdmmwtehi6x9 MERC WB02 Mega Plant plant 1091 84 39933 4.66666666666667 C26/09 6p8vandlyomkwse xbbzre09uup8nz1 KEEP (yesterday import)
10 2026-09-01 aau3dz4w8g2zled N1 Plant Excavator CAT plant 1983 123 7052 13.6666666666667 C26/09 6kj8i22ryt4bz3m DELETE (orphan)
11 2026-09-01 aau3dz4w8g2zled N1 Plant Excavator CAT plant 1983 123 7052 13.6666666666667 C26/09 e0matzjgzmi2fgq xbbzre09uup8nz1 KEEP (yesterday import)
12 2026-09-01 abkx0zcfst41i8y Bell TLB04 Mega Plant plant 1167 70 15721 4.375 C26/09 4phyh051xettimi DELETE (orphan)
13 2026-09-01 abkx0zcfst41i8y Bell TLB04 Mega Plant plant 1167 70 15721 4.375 C26/09 vyajro6x40oh2rl xbbzre09uup8nz1 KEEP (yesterday import)
14 2026-09-01 bxk0ezqopjpdo7u Roller plant 1007 44 2686 8.8 C26/09 d7umdm54j8ns7k4 DELETE (orphan)
15 2026-09-01 bxk0ezqopjpdo7u Roller plant 1007 44 2686 8.8 C26/09 6b5m8tf4eqsqb1g xbbzre09uup8nz1 KEEP (yesterday import)
16 2026-09-01 jby0yvg41384wtx Loader Jupiter 821C plant 1113 156 8048 14.1818181818182 C26/09 ti96xa169870d6h DELETE (orphan)
17 2026-09-01 jby0yvg41384wtx Loader Jupiter 821C plant 1113 156 8048 14.1818181818182 C26/09 f5k4ppn6ilnazyk xbbzre09uup8nz1 KEEP (yesterday import)
18 2026-09-01 muppqwvwgh5e3m6 Isuzu Johannes 1992 32 31156 10.65625 C26/09 q77gmakv0f5g9hj DELETE (orphan)
19 2026-09-01 muppqwvwgh5e3m6 Isuzu Johannes 1992 32 31156 10.65625 C26/09 dt3pzdn6ya3qwch xbbzre09uup8nz1 KEEP (yesterday import)
20 2026-09-01 phcy5a8untqbwpm Center Point TLB 473 plant 1516 79 4525 5.26666666666667 C26/09 q0qp5gcmcoba6qp DELETE (orphan)
21 2026-09-01 phcy5a8untqbwpm Center Point TLB 473 plant 1516 79 4525 5.26666666666667 C26/09 z7oix88n6bsdgdk xbbzre09uup8nz1 KEEP (yesterday import)
22 2026-09-01 pkq2cjn4oata4t6 Grader Case Hire plant 1590 133 932 19 C26/09 n9k9j1obvt6hlvw DELETE (orphan)
23 2026-09-01 pkq2cjn4oata4t6 Grader Case Hire plant 1590 133 932 19 C26/09 anohde1jtenmqvr xbbzre09uup8nz1 KEEP (yesterday import)
24 2026-09-01 shjv24qw7p4sksa Center Point TLB 515 plant 1959 101 4060 3.88461538461538 C26/09 tmvtzgvq996pudh DELETE (orphan)
25 2026-09-01 shjv24qw7p4sksa Center Point TLB 515 plant 1959 101 4060 3.88461538461538 C26/09 023eyqwcyllzziz xbbzre09uup8nz1 KEEP (yesterday import)
26 2026-09-01 sw75yhfj05asoef Isuzu HY58HVGP 1934 38 15685 11.2894736842105 C26/09 z6hdjgs9222jyuy DELETE (orphan)
27 2026-09-01 sw75yhfj05asoef Isuzu HY58HVGP 1934 38 15685 11.2894736842105 C26/09 c2cwjyy1olgssbg xbbzre09uup8nz1 KEEP (yesterday import)
28 2026-09-01 un37e6yl59z8ol8 Center Point Excavator CAT plant 1985 214 6067 14.2666666666667 C26/09 s47pcli75n3fyp1 DELETE (orphan)
29 2026-09-01 un37e6yl59z8ol8 Center Point Excavator CAT plant 1985 214 6067 14.2666666666667 C26/09 hyrfeyej9c3v3ai xbbzre09uup8nz1 KEEP (yesterday import)
30 2026-09-01 vac49hzww505q6t Center Point Grader plant 1626 137 5231 0.0583941605839416 C26/09 b33027ha9r9gv5s DELETE (orphan)
31 2026-09-01 vac49hzww505q6t Center Point Grader plant 1626 137 5231 0.0583941605839416 C26/09 104gv6pe71mfx09 xbbzre09uup8nz1 KEEP (yesterday import)
32 2026-09-01 vnyq71ybkgcyeqo Crushing Machine Jupiter plant 1622 97 0 0 C26/09 vjgsxb8r01oxnv0 DELETE (orphan)
33 2026-09-01 vnyq71ybkgcyeqo Crushing Machine Jupiter plant 1622 97 0 0 C26/09 2c1aiwkleydljpf xbbzre09uup8nz1 KEEP (yesterday import)
34 2026-09-01 vq4du1j6kf5jui3 N1 Plant Excavator PC200 plant 1572 127 8196 12.7 C26/09 yci03ne1xbcdtvy DELETE (orphan)
35 2026-09-01 vq4du1j6kf5jui3 N1 Plant Excavator PC200 plant 1572 127 8196 12.7 C26/09 siw2fqo7uy01lqv xbbzre09uup8nz1 KEEP (yesterday import)
36 2026-09-01 z5ta7k16siceztm TLB centre point plant 1586 41 8389 3.72727272727273 C26/09 cdt2owko229yh2z DELETE (orphan)
37 2026-09-01 z5ta7k16siceztm TLB centre point plant 1586 41 8389 3.72727272727273 C26/09 s6u774l9r977byf xbbzre09uup8nz1 KEEP (yesterday import)
38 2026-09-03 03ofzpncx5t82z9 N1 Plant Excavator PC210 plant 1974 141 988 15.6666666666667 C26/09 wc9sxrskwlhnft8 DELETE (orphan)
39 2026-09-03 03ofzpncx5t82z9 N1 Plant Excavator PC210 plant 1974 141 988 15.6666666666667 C26/09 pf9bo40b2mgi1xj xbbzre09uup8nz1 KEEP (yesterday import)
40 2026-09-03 6rsd1ugsd6q9msk Roller ARD Yellow Group plant 1625 46 12871 9.2 C26/09 0ieslcsz6zgfpq3 DELETE (orphan)
41 2026-09-03 6rsd1ugsd6q9msk Roller ARD Yellow Group plant 1625 46 12871 9.2 C26/09 taof4t1e95vn1uw xbbzre09uup8nz1 KEEP (yesterday import)
42 2026-09-03 9terh30urf4b3r5 Water Truck Go 2Guys plant 1614 194 870880 0.402061855670103 C26/09 h2mcu71rc9o5738 DELETE (orphan)
43 2026-09-03 9terh30urf4b3r5 Water Truck Go 2Guys plant 1614 194 870880 0.402061855670103 C26/09 uagxthxdnjnifv0 xbbzre09uup8nz1 KEEP (yesterday import)
44 2026-09-03 aau3dz4w8g2zled N1 Plant Excavator CAT plant 1983 155 7062 15.5 C26/09 dnw32c0ds73wpgd DELETE (orphan)
45 2026-09-03 aau3dz4w8g2zled N1 Plant Excavator CAT plant 1983 155 7062 15.5 C26/09 9hnl28jj8echcxk xbbzre09uup8nz1 KEEP (yesterday import)
46 2026-09-03 abkx0zcfst41i8y Bell TLB04 Mega Plant plant 1167 57 15733 4.75 C26/09 337solxjygn5sde DELETE (orphan)
47 2026-09-03 abkx0zcfst41i8y Bell TLB04 Mega Plant plant 1167 57 15733 4.75 C26/09 b5k8ptg5g16ax4m xbbzre09uup8nz1 KEEP (yesterday import)
48 2026-09-03 dfrv3e65t9q7aem Isuzu MF88YZGP Justice 1999 36 38977 10.1111111111111 C26/09 7scnb0zagq5p114 DELETE (orphan)
49 2026-09-03 dfrv3e65t9q7aem Isuzu MF88YZGP Justice 1999 36 38977 10.1111111111111 C26/09 d13t7nxobo7y711 xbbzre09uup8nz1 KEEP (yesterday import)
50 2026-09-03 jby0yvg41384wtx Loader Jupiter 821C plant 1113 214 8062 15.2857142857143 C26/09 t9gfvosgy52quhs DELETE (orphan)
51 2026-09-03 jby0yvg41384wtx Loader Jupiter 821C plant 1113 214 8062 15.2857142857143 C26/09 atnkay0zikdpxa0 xbbzre09uup8nz1 KEEP (yesterday import)
52 2026-09-03 pkq2cjn4oata4t6 Grader Case Hire plant 1590 308 946 22 C26/09 a7nplkkg0j6m54u DELETE (orphan)
53 2026-09-03 pkq2cjn4oata4t6 Grader Case Hire plant 1590 308 946 22 C26/09 x25iqpi7gczvlx0 xbbzre09uup8nz1 KEEP (yesterday import)
54 2026-09-03 qnig4z1earte98c Isuzu MY85HGGP 1936 50 8951 10 C26/09 8pwp9xjfqzks94i DELETE (orphan)
55 2026-09-03 qnig4z1earte98c Isuzu MY85HGGP 1936 50 8951 10 C26/09 kl9zupnrtfchoel xbbzre09uup8nz1 KEEP (yesterday import)
56 2026-09-03 vac49hzww505q6t Center Point Grader plant 1626 156 5241 0.0641025641025641 C26/09 0pdgblrmhsqh88e DELETE (orphan)
57 2026-09-03 vac49hzww505q6t Center Point Grader plant 1626 156 5241 0.0641025641025641 C26/09 uryd5j1cc2q6lkd xbbzre09uup8nz1 KEEP (yesterday import)
58 2026-09-03 vnyq71ybkgcyeqo Crushing Machine Jupiter plant 1622 147 0 0 C26/09 e1c8af1g0pur2l5 DELETE (orphan)
59 2026-09-03 vnyq71ybkgcyeqo Crushing Machine Jupiter plant 1622 147 0 0 C26/09 s7jw449xz7498sj xbbzre09uup8nz1 KEEP (yesterday import)
60 2026-09-07 03ofzpncx5t82z9 N1 Plant Excavator PC210 plant 1974 81 995 11.5714285714286 C26/09 4w5csmbbznlppce DELETE (orphan)
61 2026-09-07 03ofzpncx5t82z9 N1 Plant Excavator PC210 plant 1974 81 995 11.5714285714286 C26/09 pglg45tp8ivvqqb xbbzre09uup8nz1 KEEP (yesterday import)
62 2026-09-07 3jhs3ogv7f8ruj6 TLB centre point plant 1604 122 5399 4.88 C26/09 5pcy2uwei818fsf DELETE (orphan)
63 2026-09-07 3jhs3ogv7f8ruj6 TLB centre point plant 1604 122 5399 4.88 C26/09 evzmk4jr6ugi4du xbbzre09uup8nz1 KEEP (yesterday import)
64 2026-09-07 6rsd1ugsd6q9msk Roller ARD Yellow Group plant 1625 35 12874 11.6666666666667 C26/09 orxpy7y0pzj5pvx DELETE (orphan)
65 2026-09-07 6rsd1ugsd6q9msk Roller ARD Yellow Group plant 1625 35 12874 11.6666666666667 C26/09 i71znao8gzlrnv1 xbbzre09uup8nz1 KEEP (yesterday import)
66 2026-09-07 9pdbdmmwtehi6x9 MERC WB02 Mega Plant plant 1091 116 39951 6.44444444444444 C26/09 af05gxh7bsvavbz DELETE (orphan)
67 2026-09-07 9pdbdmmwtehi6x9 MERC WB02 Mega Plant plant 1091 116 39951 6.44444444444444 C26/09 shlizhr6au4hwhr xbbzre09uup8nz1 KEEP (yesterday import)
68 2026-09-07 aau3dz4w8g2zled N1 Plant Excavator CAT plant 1983 49 7067 9.8 C26/09 zwtwuctx6sqbvly DELETE (orphan)
69 2026-09-07 aau3dz4w8g2zled N1 Plant Excavator CAT plant 1983 49 7067 9.8 C26/09 e0lzl3ddqgmzt17 xbbzre09uup8nz1 KEEP (yesterday import)
70 2026-09-07 abkx0zcfst41i8y Bell TLB04 Mega Plant plant 1167 47 15741 5.875 C26/09 5h6zseiwqz6yio5 DELETE (orphan)
71 2026-09-07 abkx0zcfst41i8y Bell TLB04 Mega Plant plant 1167 47 15741 5.875 C26/09 6uiwgnm5m4p6z47 xbbzre09uup8nz1 KEEP (yesterday import)
72 2026-09-07 b6s0ptwj7s6vgky Tipper truck The Big AB plant 1623 166 0 0 C26/09 bvvaxb5t346vu5q DELETE (orphan)
73 2026-09-07 b6s0ptwj7s6vgky Tipper truck The Big AB plant 1623 166 0 0 C26/09 od3e950lh35psyq xbbzre09uup8nz1 KEEP (yesterday import)
74 2026-09-07 b6s0ptwj7s6vgky Tipper truck The Big AB plant 1623 200 32623 0.00681082921845735 C26/09 6u4g1emkg6y1csi DELETE (orphan)
75 2026-09-07 b6s0ptwj7s6vgky Tipper truck The Big AB plant 1623 200 32623 0.00681082921845735 C26/09 wj3iq0u14g61sr2 xbbzre09uup8nz1 KEEP (yesterday import)
76 2026-09-07 bxk0ezqopjpdo7u Roller plant 1007 84 2694 10.5 C26/09 vc8cd44fhtmq7zj DELETE (orphan)
77 2026-09-07 bxk0ezqopjpdo7u Roller plant 1007 84 2694 10.5 C26/09 pezmylawmu5oxw8 xbbzre09uup8nz1 KEEP (yesterday import)
78 2026-09-07 e7yb7w7ug54yacf Tipper truck plant 1547 150 580613 0.973333333333333 C26/09 tb1b9p2wgksyv8u DELETE (orphan)
79 2026-09-07 e7yb7w7ug54yacf Tipper truck plant 1547 150 580613 0.973333333333333 C26/09 alrygnvmbpr8hi3 xbbzre09uup8nz1 KEEP (yesterday import)
80 2026-09-07 jby0yvg41384wtx Loader Jupiter 821C plant 1113 113 8070 14.125 C26/09 9yix9ryf7r1v51y DELETE (orphan)
81 2026-09-07 jby0yvg41384wtx Loader Jupiter 821C plant 1113 113 8070 14.125 C26/09 e41izw0bi7b4zvp xbbzre09uup8nz1 KEEP (yesterday import)
82 2026-09-07 muppqwvwgh5e3m6 Isuzu Johannes 1992 31 31481 10.4838709677419 C26/09 pvn9t2g9frahvz4 DELETE (orphan)
83 2026-09-07 muppqwvwgh5e3m6 Isuzu Johannes 1992 31 31481 10.4838709677419 C26/09 a8cgeictqrx9n8s xbbzre09uup8nz1 KEEP (yesterday import)
84 2026-09-07 n21wwm4ndbfvktw Tipper truck Jupiter plant 1570 118 3829 2.8780487804878 C26/09 rxrr4mdmcs343n7 DELETE (orphan)
85 2026-09-07 n21wwm4ndbfvktw Tipper truck Jupiter plant 1570 118 3829 2.8780487804878 C26/09 padsixufp084cnh xbbzre09uup8nz1 KEEP (yesterday import)
86 2026-09-07 phcy5a8untqbwpm Center Point TLB 473 plant 1516 118 4548 5.1304347826087 C26/09 mft2g80hvzogfl2 DELETE (orphan)
87 2026-09-07 phcy5a8untqbwpm Center Point TLB 473 plant 1516 118 4548 5.1304347826087 C26/09 4dnfys22rbvx3k8 xbbzre09uup8nz1 KEEP (yesterday import)
88 2026-09-07 pkq2cjn4oata4t6 Grader Case Hire plant 1590 89 952 14.8333333333333 C26/09 e1o35zc7vbwyjoh DELETE (orphan)
89 2026-09-07 pkq2cjn4oata4t6 Grader Case Hire plant 1590 89 952 14.8333333333333 C26/09 zjqspco93lajnt0 xbbzre09uup8nz1 KEEP (yesterday import)
90 2026-09-07 rkp6s3b40mvhqfr Pick Up Truck 001 plant 1938 271 300 7.52777777777778 C26/09 infpasex4akd61l DELETE (orphan)
91 2026-09-07 rkp6s3b40mvhqfr Pick Up Truck 001 plant 1938 271 300 7.52777777777778 C26/09 vs5e0zkuggswc0a xbbzre09uup8nz1 KEEP (yesterday import)
92 2026-09-07 shjv24qw7p4sksa Center Point TLB 515 plant 1959 102 4083 4.43478260869565 C26/09 azz2a3t2xwccxhd DELETE (orphan)
93 2026-09-07 shjv24qw7p4sksa Center Point TLB 515 plant 1959 102 4083 4.43478260869565 C26/09 kesbj0zzyc2g6vd xbbzre09uup8nz1 KEEP (yesterday import)
94 2026-09-07 sw75yhfj05asoef Isuzu HY58HVGP 1934 54 16300 11.3888888888889 C26/09 oaykvw612kz1t57 DELETE (orphan)
95 2026-09-07 sw75yhfj05asoef Isuzu HY58HVGP 1934 54 16300 11.3888888888889 C26/09 pw37zyfyjedegvd xbbzre09uup8nz1 KEEP (yesterday import)
96 2026-09-07 un37e6yl59z8ol8 Center Point Excavator CAT plant 1985 124 6080 9.53846153846154 C26/09 wqss7j5vey6bds8 DELETE (orphan)
97 2026-09-07 un37e6yl59z8ol8 Center Point Excavator CAT plant 1985 124 6080 9.53846153846154 C26/09 r5cd5nikfrleucy xbbzre09uup8nz1 KEEP (yesterday import)
98 2026-09-07 vac49hzww505q6t Center Point Grader plant 1626 105 5249 0.0761904761904762 C26/09 3bo6qn2bp4tmij2 DELETE (orphan)
99 2026-09-07 vac49hzww505q6t Center Point Grader plant 1626 105 5249 0.0761904761904762 C26/09 8t1o0ydx7mfo5hn xbbzre09uup8nz1 KEEP (yesterday import)
100 2026-09-07 vq4du1j6kf5jui3 N1 Plant Excavator PC200 plant 1572 319 8219 13.8695652173913 C26/09 w0k3wzxgk818j9c DELETE (orphan)
101 2026-09-07 vq4du1j6kf5jui3 N1 Plant Excavator PC200 plant 1572 319 8219 13.8695652173913 C26/09 zp9zqonrwfw6iwc xbbzre09uup8nz1 KEEP (yesterday import)
102 2026-09-07 z5ta7k16siceztm TLB centre point plant 1586 106 8408 5.57894736842105 C26/09 xyjpd57h9gyhcpn DELETE (orphan)
103 2026-09-07 z5ta7k16siceztm TLB centre point plant 1586 106 8408 5.57894736842105 C26/09 okv117c28fi8eja xbbzre09uup8nz1 KEEP (yesterday import)
104 2026-09-09 03ofzpncx5t82z9 N1 Plant Excavator PC210 plant 1974 112 1006 10.1818181818182 C26/09 lngcy4x8y1txcmd DELETE (orphan)
105 2026-09-09 03ofzpncx5t82z9 N1 Plant Excavator PC210 plant 1974 112 1006 10.1818181818182 C26/09 sdz1n4pt1usjdsp xbbzre09uup8nz1 KEEP (yesterday import)
106 2026-09-09 3jhs3ogv7f8ruj6 TLB centre point plant 1604 59 5411 4.91666666666667 C26/09 g6fpxjttm2qd3g2 DELETE (orphan)
107 2026-09-09 3jhs3ogv7f8ruj6 TLB centre point plant 1604 59 5411 4.91666666666667 C26/09 8sdh9gpgcagzbxl xbbzre09uup8nz1 KEEP (yesterday import)
108 2026-09-09 68n3smofgkrwq93 Can The Hills 1611 42 0 0 C26/09 snle25g7jbx7gly DELETE (orphan)
109 2026-09-09 68n3smofgkrwq93 Can The Hills 1611 42 0 0 C26/09 cyofbtfuzdx89em xbbzre09uup8nz1 KEEP (yesterday import)
110 2026-09-09 6rsd1ugsd6q9msk Roller ARD Yellow Group plant 1625 38 12879 7.6 C26/09 so29f0s9bqps82w DELETE (orphan)
111 2026-09-09 6rsd1ugsd6q9msk Roller ARD Yellow Group plant 1625 38 12879 7.6 C26/09 tpvswbwvmtjqhge xbbzre09uup8nz1 KEEP (yesterday import)
112 2026-09-09 76tm3k0o32jneto Tipper Truck plant 1589 326 290 0.0950920245398773 C26/09 k0l2jl6olrwvfh5 DELETE (orphan)
113 2026-09-09 76tm3k0o32jneto Tipper Truck plant 1589 326 290 0.0950920245398773 C26/09 vxqbj9feakucdcc xbbzre09uup8nz1 KEEP (yesterday import)
114 2026-09-09 9terh30urf4b3r5 Water Truck Go 2Guys plant 1614 164 870912 0.195121951219512 C26/09 crff7d5h2l51xso DELETE (orphan)
115 2026-09-09 9terh30urf4b3r5 Water Truck Go 2Guys plant 1614 164 870912 0.195121951219512 C26/09 ec8dshvhv05u6pr xbbzre09uup8nz1 KEEP (yesterday import)
116 2026-09-09 aau3dz4w8g2zled N1 Plant Excavator CAT plant 1983 138 7075 17.25 C26/09 bomiofuxtb783ui DELETE (orphan)
117 2026-09-09 aau3dz4w8g2zled N1 Plant Excavator CAT plant 1983 138 7075 17.25 C26/09 s9462qzgj6d88j6 xbbzre09uup8nz1 KEEP (yesterday import)
118 2026-09-09 abkx0zcfst41i8y Bell TLB04 Mega Plant plant 1167 73 15755 5.21428571428571 C26/09 wut55nj2oi94hhk DELETE (orphan)
119 2026-09-09 abkx0zcfst41i8y Bell TLB04 Mega Plant plant 1167 73 15755 5.21428571428571 C26/09 686mq8ybdfylby8 xbbzre09uup8nz1 KEEP (yesterday import)
120 2026-09-09 bxk0ezqopjpdo7u Roller plant 1007 74 2702 9.25 C26/09 3mr9cfvvbwcnt8a DELETE (orphan)
121 2026-09-09 bxk0ezqopjpdo7u Roller plant 1007 74 2702 9.25 C26/09 vayf90mfk46ahs2 xbbzre09uup8nz1 KEEP (yesterday import)
122 2026-09-09 dfrv3e65t9q7aem Isuzu MF88YZGP Justice 1999 42 39400 10.0714285714286 C26/09 1dkeu2ni6fmcsv7 DELETE (orphan)
123 2026-09-09 dfrv3e65t9q7aem Isuzu MF88YZGP Justice 1999 42 39400 10.0714285714286 C26/09 fi9k9icty9wtycu xbbzre09uup8nz1 KEEP (yesterday import)
124 2026-09-09 jby0yvg41384wtx Loader Jupiter 821C plant 1113 118 8079 13.1111111111111 C26/09 cq41xzj4pc70e0x DELETE (orphan)
125 2026-09-09 jby0yvg41384wtx Loader Jupiter 821C plant 1113 118 8079 13.1111111111111 C26/09 cts0lo786nd2pqn xbbzre09uup8nz1 KEEP (yesterday import)
126 2026-09-09 muppqwvwgh5e3m6 Isuzu Johannes 1992 17 31657 10.3529411764706 C26/09 py3w6s073384e5g DELETE (orphan)
127 2026-09-09 muppqwvwgh5e3m6 Isuzu Johannes 1992 17 31657 10.3529411764706 C26/09 pep0z111ozg9g7i xbbzre09uup8nz1 KEEP (yesterday import)
128 2026-09-09 phcy5a8untqbwpm Center Point TLB 473 plant 1516 69 4560 5.75 C26/09 rvtmdxz09604m8o DELETE (orphan)
129 2026-09-09 phcy5a8untqbwpm Center Point TLB 473 plant 1516 69 4560 5.75 C26/09 42cz372hr3at7mz xbbzre09uup8nz1 KEEP (yesterday import)
130 2026-09-09 pkq2cjn4oata4t6 Grader Case Hire plant 1590 219 963 19.9090909090909 C26/09 mtitlhdlyq83e3p DELETE (orphan)
131 2026-09-09 pkq2cjn4oata4t6 Grader Case Hire plant 1590 219 963 19.9090909090909 C26/09 9zaht402raqm4rb xbbzre09uup8nz1 KEEP (yesterday import)
132 2026-09-09 qnig4z1earte98c Isuzu MY85HGGP 1936 33 9285 10.1212121212121 C26/09 9hhfz4xcyya9mrq DELETE (orphan)
133 2026-09-09 qnig4z1earte98c Isuzu MY85HGGP 1936 33 9285 10.1212121212121 C26/09 z810mt12qdl4hnl xbbzre09uup8nz1 KEEP (yesterday import)
134 2026-09-09 shjv24qw7p4sksa Center Point TLB 515 plant 1959 26 4091 3.25 C26/09 hja6auvyiam4e8a DELETE (orphan)
135 2026-09-09 shjv24qw7p4sksa Center Point TLB 515 plant 1959 26 4091 3.25 C26/09 m4qr9mphiosb3z2 xbbzre09uup8nz1 KEEP (yesterday import)
136 2026-09-09 sw75yhfj05asoef Isuzu HY58HVGP 1934 24 16595 12.2916666666667 C26/09 cer4dfv3ag6bpve DELETE (orphan)
137 2026-09-09 sw75yhfj05asoef Isuzu HY58HVGP 1934 24 16595 12.2916666666667 C26/09 t122e5655oz2r9y xbbzre09uup8nz1 KEEP (yesterday import)
138 2026-09-09 un37e6yl59z8ol8 Center Point Excavator CAT plant 1985 215 6097 12.6470588235294 C26/09 mc6h5h5vp8e1s6s DELETE (orphan)
139 2026-09-09 un37e6yl59z8ol8 Center Point Excavator CAT plant 1985 215 6097 12.6470588235294 C26/09 64tgdibvqabfv9x xbbzre09uup8nz1 KEEP (yesterday import)
140 2026-09-09 vac49hzww505q6t Center Point Grader plant 1626 130 5259 0.0769230769230769 C26/09 r5ou0332lmc3o7y DELETE (orphan)
141 2026-09-09 vac49hzww505q6t Center Point Grader plant 1626 130 5259 0.0769230769230769 C26/09 bk9i2t1cbnwl1ez xbbzre09uup8nz1 KEEP (yesterday import)
142 2026-09-09 vnyq71ybkgcyeqo Crushing Machine Jupiter plant 1622 170 0 0 C26/09 8c25qnehft0tj16 DELETE (orphan)
143 2026-09-09 vnyq71ybkgcyeqo Crushing Machine Jupiter plant 1622 170 0 0 C26/09 8u1kdvcx5c554ck xbbzre09uup8nz1 KEEP (yesterday import)
144 2026-09-09 vq4du1j6kf5jui3 N1 Plant Excavator PC200 plant 1572 118 8229 11.8 C26/09 mddwgitouz6g5ob DELETE (orphan)
145 2026-09-09 vq4du1j6kf5jui3 N1 Plant Excavator PC200 plant 1572 118 8229 11.8 C26/09 tpvf5ckja07mlvt xbbzre09uup8nz1 KEEP (yesterday import)
146 2026-09-09 z5ta7k16siceztm TLB centre point plant 1586 87 8425 5.11764705882353 C26/09 tws6zsmny9gwurz DELETE (orphan)
147 2026-09-09 z5ta7k16siceztm TLB centre point plant 1586 87 8425 5.11764705882353 C26/09 g5nqf70j9lrvrwh xbbzre09uup8nz1 KEEP (yesterday import)

View file

@ -0,0 +1,182 @@
#!/usr/bin/env python3
"""
Rename two collections as part of the ingestion restructure.
PB_URL=... PB_ADMIN_EMAIL=... PB_ADMIN_PASSWORD=... \\
python3 scripts/migrations/2026-09-12-rename-collections.py [--apply]
DRY RUN BY DEFAULT. Pass --apply to rename.
RECEIVED_ITEMS -> DELIVERY_NOTE_ITEMS
They are the lines on a delivery note. The old name describes the
event, not the thing.
TIMESHEETS -> TIMESHEET_ENTRIES
This collection is the time log (employee, date, hours, site), not
a timesheet. The name is freed for the uploaded-document
collection created in Task 6.
WHY THIS IS SAFE
----------------
PocketBase relations store collectionId, not name, so every existing
relation survives a rename untouched. Collection names are
case-insensitive, so lowercase call sites in `src/` keep resolving until
the code is updated - the rename and the code change do not have to be
simultaneous.
THE SAFETY PROPERTY
-------------------
A rename must move a name and nothing else. So each rename asserts, on
the collection id it just patched, that the new name stuck AND that the
row count is byte-identical to the count read immediately before. A
count that moves means something other than a rename happened, and the
run stops there rather than carrying on to the second collection with
an unexplained delta behind it.
Refuses to rename onto a name that is already taken by a different
collection. Idempotent: a collection already carrying the new name is
reported and skipped.
"""
import json
import os
import sys
import urllib.error
import urllib.request
APPLY = "--apply" in sys.argv
RENAMES = [
("received_items", "DELIVERY_NOTE_ITEMS"),
("timesheets", "TIMESHEET_ENTRIES"),
]
def admin_auth(base_url):
body = json.dumps(
{
"identity": os.environ["PB_ADMIN_EMAIL"],
"password": os.environ["PB_ADMIN_PASSWORD"],
}
).encode()
req = urllib.request.Request(
f"{base_url}/api/collections/_superusers/auth-with-password",
data=body,
headers={"Content-Type": "application/json"},
method="POST",
)
with urllib.request.urlopen(req) as resp:
return json.loads(resp.read())["token"]
def api(base_url, token, method, path, body=None):
"""
A 404 is only soft for GET - "this collection is absent" is a
legitimate answer to a read, and is how we detect an already-renamed
collection. On a write it is not: a PATCH against a since-renamed
collection returning None would be counted as a successful rename.
Mutations raise.
"""
data = json.dumps(body).encode() if body is not None else None
req = urllib.request.Request(
f"{base_url}{path}",
data=data,
method=method,
headers={"Authorization": token, "Content-Type": "application/json"},
)
try:
with urllib.request.urlopen(req) as resp:
txt = resp.read().decode()
return json.loads(txt) if txt else None
except urllib.error.HTTPError as e:
if e.code == 404 and method == "GET":
return None
raise RuntimeError(
f"{method} {path}: {e.code} {e.read().decode() if e.fp else ''}"
) from e
def row_count(base_url, token, coll_ref):
"""Total rows, read by collection id so it is stable across a rename."""
return api(
base_url,
token,
"GET",
f"/api/collections/{coll_ref}/records?perPage=1&fields=id",
)["totalItems"]
def main():
base_url = os.environ.get("PB_URL", "http://127.0.0.1:8090").rstrip("/")
token = admin_auth(base_url)
# Say where we are writing. This script mutates production by default
# target, and a run whose output names no host is a run you cannot
# audit afterwards.
print(f"target: {base_url} mode: {'APPLY' if APPLY else 'DRY RUN'}")
all_colls = api(base_url, token, "GET", "/api/collections?perPage=200")
names_lower = {c["name"].lower(): c["name"] for c in all_colls["items"]}
renamed, skipped = 0, 0
for old, new in RENAMES:
cur = api(base_url, token, "GET", f"/api/collections/{old}")
if cur is None:
print(f"\nSKIP {old}: not found (already renamed?)")
skipped += 1
continue
if cur["name"].lower() == new.lower():
print(f"\nSKIP {old}: already named {cur['name']}")
skipped += 1
continue
# A name collision is not a skip. Renaming onto a live collection
# is not something this script can do safely, and continuing to
# the next rename would leave the restructure half-applied.
taken = names_lower.get(new.lower())
if taken is not None and taken.lower() != cur["name"].lower():
print(f"\nABORT {old} -> {new}: target name already taken")
return 1
count = row_count(base_url, token, old)
print(f"\n{cur['name']} -> {new} (id={cur['id']}, {count} rows)")
if not APPLY:
continue
api(base_url, token, "PATCH", f"/api/collections/{cur['id']}", {"name": new})
# Re-read by id, not by either name: reading by the new name
# would prove only that *a* collection has that name, not that
# this one does.
after = api(base_url, token, "GET", f"/api/collections/{cur['id']}")
if after is None:
print(f" FAILED: collection id={cur['id']} vanished after rename")
return 1
if after["name"] != new:
print(f" FAILED: rename did not stick: {after['name']!r} != {new!r}")
return 1
after_count = row_count(base_url, token, cur["id"])
if after_count != count:
print(
f" FAILED: row count changed during rename: "
f"{count} -> {after_count}. Stopping before the next rename."
)
return 1
print(f" OK, {after_count} rows intact")
renamed += 1
if not APPLY:
print("\nDRY RUN. Re-run with --apply to rename.")
return 0
print(f"\nrenamed {renamed} skipped {skipped} of {len(RENAMES)}")
return 0
if __name__ == "__main__":
try:
sys.exit(main())
except KeyError as e:
print(f"ERROR: missing environment variable {e}", file=sys.stderr)
sys.exit(2)

View file

@ -40,15 +40,15 @@ import { validateMatchedPoItems } from "@/lib/validate-matched-po-items";
* } * }
* *
* Behaviour (see resolveOcrTier for the authoritative rules): * Behaviour (see resolveOcrTier for the authoritative rules):
* - Overall confidence >= 0.8 AND PO resolved: creates received_items, * - Overall confidence >= 0.8 AND PO resolved: creates delivery_note_items,
* sets processing_status="auto-verified" and is_verified=true. * sets processing_status="auto-verified" and is_verified=true.
* - Overall confidence >= 0.8 BUT PO did NOT resolve (OCR was * - Overall confidence >= 0.8 BUT PO did NOT resolve (OCR was
* confident in the slip but the PO number didn't fuzzy-match * confident in the slip but the PO number didn't fuzzy-match
* any PO we have on file): DOWNGRADES to draft — we never * any PO we have on file): DOWNGRADES to draft — we never
* auto-verify an orphaned DN. * auto-verify an orphaned DN.
* - 0.5..0.79: creates received_items as a draft, sets * - 0.5..0.79: creates delivery_note_items as a draft, sets
* processing_status="needs-review" and is_verified=false. * processing_status="needs-review" and is_verified=false.
* - < 0.5: doesn't create received_items, sets * - < 0.5: doesn't create delivery_note_items, sets
* processing_status="needs-review" and is_verified=false. * processing_status="needs-review" and is_verified=false.
* *
* PO matching (in priority order): exact → normalised * PO matching (in priority order): exact → normalised
@ -57,7 +57,7 @@ import { validateMatchedPoItems } from "@/lib/validate-matched-po-items";
* purchasing exception inbox can show "matched by Levenshtein, 0.9" * purchasing exception inbox can show "matched by Levenshtein, 0.9"
* instead of a silent "no match". * instead of a silent "no match".
* *
* Idempotency: if the webhook is replayed, received_items already * Idempotency: if the webhook is replayed, delivery_note_items already
* linked to this DN are updated rather than duplicated. * linked to this DN are updated rather than duplicated.
*/ */
export async function POST( export async function POST(
@ -198,8 +198,8 @@ export async function POST(
// >= 0.8 BUT items unverifiable (empty local PO items but // >= 0.8 BUT items unverifiable (empty local PO items but
// n8n supplied ids) → draft (don't claim auto when we // n8n supplied ids) → draft (don't claim auto when we
// couldn't cross-check the links) // couldn't cross-check the links)
// 0.5..0.79 → draft, received_items created for review // 0.5..0.79 → draft, delivery_note_items created for review
// < 0.5 → manual, no received_items (user captures manually) // < 0.5 → manual, no delivery_note_items (user captures manually)
const poId = matchedPoId ?? dn.purchase_order ?? null; const poId = matchedPoId ?? dn.purchase_order ?? null;
let poItems: PurchaseOrderItemRecord[] = []; let poItems: PurchaseOrderItemRecord[] = [];
if (poId) { if (poId) {
@ -239,7 +239,7 @@ export async function POST(
const isVerified = tier === "auto"; const isVerified = tier === "auto";
// 5. Update the DN with the OCR fields regardless of tier. // 5. Update the DN with the OCR fields regardless of tier.
// We do this BEFORE creating received_items so the audit trail shows // We do this BEFORE creating delivery_note_items so the audit trail shows
// the OCR happened even if item creation fails. // the OCR happened even if item creation fails.
try { try {
await pb.collection("delivery_notes").update(dnId, { await pb.collection("delivery_notes").update(dnId, {
@ -298,7 +298,7 @@ export async function POST(
); );
} }
// 6. Build received_items only for the auto / draft tiers. // 6. Build delivery_note_items only for the auto / draft tiers.
// The manual tier gets no items — the user will fill them in via the // The manual tier gets no items — the user will fill them in via the
// exception inbox. // exception inbox.
if (tier === "manual") { if (tier === "manual") {
@ -318,21 +318,21 @@ export async function POST(
}); });
} }
// 7. Idempotently upsert received_items keyed by (delivery_note, po_item). // 7. Idempotently upsert delivery_note_items keyed by (delivery_note, po_item).
// The PO items + matched-id validation already happened above (so it // The PO items + matched-id validation already happened above (so it
// could feed the tier decision). Here we just consume the result. // could feed the tier decision). Here we just consume the result.
// We delete the existing set first (within this DN) and recreate — atomic // We delete the existing set first (within this DN) and recreate — atomic
// from the caller's perspective and avoids stale matches if the OCR // from the caller's perspective and avoids stale matches if the OCR
// rerun finds different items. // rerun finds different items.
const existing = await pb.collection("received_items").getFullList({ const existing = await pb.collection("delivery_note_items").getFullList({
filter: `delivery_note='${dnId}'`, filter: `delivery_note='${dnId}'`,
fields: "id,purchase_order_item", fields: "id,purchase_order_item",
}); });
for (const r of existing) { for (const r of existing) {
try { try {
await pb.collection("received_items").delete(r.id); await pb.collection("delivery_note_items").delete(r.id);
} catch (err) { } catch (err) {
console.warn(`[dn-ocr-result] delete received_item ${r.id} failed:`, err); console.warn(`[dn-ocr-result] delete delivery_note_item ${r.id} failed:`, err);
} }
} }
@ -359,7 +359,7 @@ export async function POST(
.join(" · "); .join(" · ");
try { try {
const created = await pb.collection("received_items").create({ const created = await pb.collection("delivery_note_items").create({
delivery_note: dnId, delivery_note: dnId,
// Only link to a PO item if we got a verified match. Otherwise // Only link to a PO item if we got a verified match. Otherwise
// we still create the row (so the user sees what OCR found) but // we still create the row (so the user sees what OCR found) but
@ -385,11 +385,11 @@ export async function POST(
const isFkError = Boolean(validPoItemId) && status === 400; const isFkError = Boolean(validPoItemId) && status === 400;
if (isFkError) { if (isFkError) {
console.warn( console.warn(
`[dn-ocr-result] received_item create failed for matched_po_item_id=${validPoItemId} (id no longer exists in PB) — retrying without link:`, `[dn-ocr-result] delivery_note_item create failed for matched_po_item_id=${validPoItemId} (id no longer exists in PB) — retrying without link:`,
message, message,
); );
try { try {
const created = await pb.collection("received_items").create({ const created = await pb.collection("delivery_note_items").create({
delivery_note: dnId, delivery_note: dnId,
purchase_order_item: null, purchase_order_item: null,
qty_received: qty, qty_received: qty,
@ -402,12 +402,12 @@ export async function POST(
}); });
} catch (err2) { } catch (err2) {
console.warn( console.warn(
"[dn-ocr-result] received_item create (no-link retry) failed:", "[dn-ocr-result] delivery_note_item create (no-link retry) failed:",
err2, err2,
); );
} }
} else { } else {
console.warn("[dn-ocr-result] received_item create failed:", err); console.warn("[dn-ocr-result] delivery_note_item create failed:", err);
} }
} }
} }

View file

@ -143,7 +143,7 @@ export async function POST(request: Request) {
} }
try { try {
await pb.collection("timesheets").create({ await pb.collection("timesheet_entries").create({
employee: employeeId, employee: employeeId,
batch_reference: batch.id, batch_reference: batch.id,
date_logged: new Date(row.date).toISOString(), date_logged: new Date(row.date).toISOString(),

View file

@ -101,7 +101,7 @@ export default async function EmployeesPage() {
const [employees, timesheets, sites] = await Promise.all([ const [employees, timesheets, sites] = await Promise.all([
pb.collection("employees").getFullList({ sort: "name", expand: "site" }), pb.collection("employees").getFullList({ sort: "name", expand: "site" }),
pb.collection("timesheets").getFullList(), pb.collection("timesheet_entries").getFullList(),
pb.collection("sites").getFullList({ sort: "name" }), pb.collection("sites").getFullList({ sort: "name" }),
]); ]);

View file

@ -35,7 +35,7 @@ export default async function PurchaseOrderDetailPage({
pb.collection("delivery_notes").getFullList({ pb.collection("delivery_notes").getFullList({
filter: `purchase_order='${poId}'`, filter: `purchase_order='${poId}'`,
}), }),
pb.collection("received_items").getFullList({ pb.collection("delivery_note_items").getFullList({
fields: "id,delivery_note,purchase_order_item,qty_received,condition_notes", fields: "id,delivery_note,purchase_order_item,qty_received,condition_notes",
}), }),
]); ]);

View file

@ -25,10 +25,10 @@ export default async function PurchasingPage() {
}), }),
pb.collection("sites").getFullList({ sort: "name" }), pb.collection("sites").getFullList({ sort: "name" }),
// Authoritative source for received quantities. Use getFullList so // Authoritative source for received quantities. Use getFullList so
// there is no silent truncation if `received_items` ever exceeds // there is no silent truncation if `delivery_note_items` ever exceeds
// 500 rows — earlier this used `getList(1, 500, ...)` which capped // 500 rows — earlier this used `getList(1, 500, ...)` which capped
// and produced 0% fulfillment whenever low-id POs were dropped. // and produced 0% fulfillment whenever low-id POs were dropped.
pb.collection("received_items").getFullList({ pb.collection("delivery_note_items").getFullList({
fields: "id,purchase_order_item,qty_received", fields: "id,purchase_order_item,qty_received",
}), }),
]); ]);
@ -46,7 +46,7 @@ export default async function PurchasingPage() {
dnsByPo.set(dn.purchase_order, list); dnsByPo.set(dn.purchase_order, list);
} }
// Sum received_items.qty_received per PO item so we can compute // Sum delivery_note_items.qty_received per PO item so we can compute
// per-PO fulfilment % from authoritative data instead of the stale // per-PO fulfilment % from authoritative data instead of the stale
// denormalized field on purchase_order_items. Rows without a // denormalized field on purchase_order_items. Rows without a
// purchase_order_item are collected as orphans (they can't roll up to // purchase_order_item are collected as orphans (they can't roll up to
@ -67,7 +67,7 @@ export default async function PurchasingPage() {
} }
if (orphanIds.length > 0) { if (orphanIds.length > 0) {
console.warn( console.warn(
`[purchasing] ${orphanIds.length} received_items row(s) have empty purchase_order_item and are excluded from fulfilment. ids=${orphanIds.join(",")}`, `[purchasing] ${orphanIds.length} delivery_note_items row(s) have empty purchase_order_item and are excluded from fulfilment. ids=${orphanIds.join(",")}`,
); );
} }

View file

@ -57,7 +57,7 @@ export default async function SiteDetailPage({
fuelPrices, fuelPrices,
] = await Promise.all([ ] = await Promise.all([
pb.collection("fixed_costs").getFullList({ filter: `site='${id}'` }), pb.collection("fixed_costs").getFullList({ filter: `site='${id}'` }),
pb.collection("timesheets").getFullList(), pb.collection("timesheet_entries").getFullList(),
pb.collection("employees").getFullList({ fields: "id,rate_per_hour,site,name" }), pb.collection("employees").getFullList({ fields: "id,rate_per_hour,site,name" }),
pb.collection("purchase_orders").getFullList({ filter: `site='${id}'` }), pb.collection("purchase_orders").getFullList({ filter: `site='${id}'` }),
pb.collection("fuel_logs").getFullList({ filter: `site='${id}'` }), pb.collection("fuel_logs").getFullList({ filter: `site='${id}'` }),

View file

@ -34,7 +34,7 @@ export default async function SitesPage() {
] = await Promise.all([ ] = await Promise.all([
pb.collection("sites").getFullList(), pb.collection("sites").getFullList(),
pb.collection("fixed_costs").getFullList(), pb.collection("fixed_costs").getFullList(),
pb.collection("timesheets").getFullList(), pb.collection("timesheet_entries").getFullList(),
pb.collection("employees").getFullList({ pb.collection("employees").getFullList({
fields: "id,rate_per_hour,site,name", fields: "id,rate_per_hour,site,name",
}), }),

View file

@ -39,7 +39,7 @@ export async function loadSiteBundle(siteId: string) {
] = await Promise.all([ ] = await Promise.all([
pb.collection("sites").getOne(siteId), pb.collection("sites").getOne(siteId),
pb.collection("fixed_costs").getFullList({ filter: `site='${siteId}'` }), pb.collection("fixed_costs").getFullList({ filter: `site='${siteId}'` }),
pb.collection("timesheets").getFullList(), pb.collection("timesheet_entries").getFullList(),
pb.collection("employees").getFullList({ pb.collection("employees").getFullList({
fields: "id,rate_per_hour,site,name", fields: "id,rate_per_hour,site,name",
}), }),
@ -75,7 +75,7 @@ export async function loadAllSitesBundle() {
] = await Promise.all([ ] = await Promise.all([
pb.collection("sites").getFullList({ sort: "name" }), pb.collection("sites").getFullList({ sort: "name" }),
pb.collection("fixed_costs").getFullList(), pb.collection("fixed_costs").getFullList(),
pb.collection("timesheets").getFullList(), pb.collection("timesheet_entries").getFullList(),
pb.collection("employees").getFullList({ pb.collection("employees").getFullList({
fields: "id,rate_per_hour,site,name", fields: "id,rate_per_hour,site,name",
}), }),
@ -191,7 +191,7 @@ export async function loadDeliveryNoteByNumber(dnNumber: string) {
if (!dn) return null; if (!dn) return null;
// Expand the PO item so each received line has a description. // Expand the PO item so each received line has a description.
const items = await pb.collection("received_items").getFullList({ const items = await pb.collection("delivery_note_items").getFullList({
filter: `delivery_note='${dn.id}'`, filter: `delivery_note='${dn.id}'`,
expand: "purchase_order_item", expand: "purchase_order_item",
}); });
@ -219,7 +219,7 @@ export async function loadWorkforce() {
pb.collection("employees").getFullList({ pb.collection("employees").getFullList({
fields: "id,name,rate_per_hour,site,position,worker_type", fields: "id,name,rate_per_hour,site,position,worker_type",
}), }),
pb.collection("timesheets").getFullList(), pb.collection("timesheet_entries").getFullList(),
pb.collection("sites").getFullList({ fields: "id,name,project_code" }), pb.collection("sites").getFullList({ fields: "id,name,project_code" }),
]); ]);
return { employees, timesheets, sites }; return { employees, timesheets, sites };
@ -241,7 +241,7 @@ export async function loadDeliveryNotes(args: { siteId?: string; verified?: bool
}); });
// One query for all received items, then bucket — avoids N round-trips. // One query for all received items, then bucket — avoids N round-trips.
const received = await pb.collection("received_items").getFullList({ const received = await pb.collection("delivery_note_items").getFullList({
expand: "purchase_order_item", expand: "purchase_order_item",
}); });
const itemsByNote = new Map<string, typeof received>(); const itemsByNote = new Map<string, typeof received>();

View file

@ -7,7 +7,7 @@
* *
* Why the PO-resolved downgrade matters: * Why the PO-resolved downgrade matters:
* Before this, a slip with confidence 0.92 but a garbled PO * Before this, a slip with confidence 0.92 but a garbled PO
* number would be marked auto-verified with every received_item * number would be marked auto-verified with every delivery_note_item
* linked to nothing. The user only noticed when reconciling the * linked to nothing. The user only noticed when reconciling the
* exception inbox — by which point the audit trail had already * exception inbox — by which point the audit trail had already
* been stamped as "verified". Now the tier falls back to "draft" * been stamped as "verified". Now the tier falls back to "draft"
@ -34,7 +34,7 @@ export type OcrMatchMethod = "exact" | "normalised" | "levenshtein" | "none";
* didn't bother to cross-check the matched ids). Pass `false` when * didn't bother to cross-check the matched ids). Pass `false` when
* the local PO-items fetch was empty but n8n supplied ids we had to * the local PO-items fetch was empty but n8n supplied ids we had to
* trust anyway — in that case we don't have contradicting local * trust anyway — in that case we don't have contradicting local
* evidence, but we also can't claim the received_items were * evidence, but we also can't claim the delivery_note_items were
* correctly linked. Force the user to review. * correctly linked. Force the user to review.
* *
* Confidence is clamped to [0, 1]; values > 1 are treated as percentages * Confidence is clamped to [0, 1]; values > 1 are treated as percentages

View file

@ -187,13 +187,19 @@ export interface PurchaseOrderItemRecord extends RecordModel {
expand?: { purchase_order?: PurchaseOrderRecord }; expand?: { purchase_order?: PurchaseOrderRecord };
} }
export interface TimesheetRecord extends RecordModel { /**
collectionName: "timesheets"; * One logged shift: this employee worked these hours on this date. The
* collection was called `timesheets` until the 2026-09-12 rename; that
* name now belongs to the uploaded timesheet document.
*/
export interface TimesheetEntryRecord extends RecordModel {
collectionName: "timesheet_entries";
employee: string; employee: string;
batch_reference: string; /** Stamped from the employee's site at import time. Never joined at read time. */
site: string;
date_logged: string; date_logged: string;
hours_worked: number; hours_worked: number;
expand?: { employee?: EmployeeRecord; batch_reference?: DataImportBatchRecord }; expand?: { employee?: EmployeeRecord; site?: SiteRecord };
} }
export interface FuelLogRecord extends RecordModel { export interface FuelLogRecord extends RecordModel {
@ -275,9 +281,15 @@ export type DeliveryNoteProcessingStatus =
| "needs-review" | "needs-review"
| "manual-verified" | "manual-verified"
| "failed"; | "failed";
export interface ReceivedItemRecord extends RecordModel { /**
collectionName: "received_items"; * One line on a delivery note. The collection was called
* `received_items` until the 2026-09-12 rename — the old name described
* the receiving event rather than the thing received.
*/
export interface DeliveryNoteItemRecord extends RecordModel {
collectionName: "delivery_note_items";
delivery_note: string; delivery_note: string;
/** Optional — empty when OCR could not match the line to a PO item. */
purchase_order_item: string; purchase_order_item: string;
qty_received: number; qty_received: number;
condition_notes: string; condition_notes: string;