From 095dd4cb8b34545114fb75094e94eb4aaaec43f8 Mon Sep 17 00:00:00 2001 From: Rafhan Mazaya Fathurrahman Date: Fri, 3 Jul 2026 16:43:24 +0700 Subject: [PATCH] feat: implement db layout caching for parsed ocr & reprocess batch test with corrected parser alignment --- .../pfm-web-app/src/app/api/parse/route.ts | 143 +++-- backend/sources/ai_results.json | 193 +++--- backend/sources/ai_results.md | 566 +++++++++++++++--- backend/sources/comparison_report.xlsx | Bin 16984 -> 17066 bytes backend/sources/comparison_side_by_side.md | 341 +++++++++++ backend/sources/generate_side_by_side.py | 160 +++++ 6 files changed, 1140 insertions(+), 263 deletions(-) create mode 100644 backend/sources/comparison_side_by_side.md create mode 100644 backend/sources/generate_side_by_side.py diff --git a/backend/pfm-web-app/src/app/api/parse/route.ts b/backend/pfm-web-app/src/app/api/parse/route.ts index 726aa7d..1070d4d 100644 --- a/backend/pfm-web-app/src/app/api/parse/route.ts +++ b/backend/pfm-web-app/src/app/api/parse/route.ts @@ -68,75 +68,98 @@ export async function POST(req: NextRequest) { const b64 = fileBuffer.toString("base64"); - // Form payload - const payload = { - file: b64, - matchHistoryJob: false, - useLayoutDetection: true, - fileType: 1, - useDocUnwarping: false, - useDocOrientationClassify: true - }; + // Check if we already have a parsed document in the database with the exact filename (and has valid layout_parsing_result) + const cachedDoc = await query( + "SELECT layout_parsing_result, processing_logs FROM documents WHERE filename = $1 AND parsed = true", + [safeFile] + ); - // Post to Pipeline API - const pipelineUrl = process.env.PIPELINE_URL || "http://localhost:7871/layout-parsing"; - - console.log(`Forwarding request to pipeline API: ${pipelineUrl}`); - const response = await fetch(pipelineUrl, { - method: "POST", - headers: { - "Content-Type": "application/json" - }, - body: JSON.stringify(payload) - }); - - if (!response.ok) { - const errText = await response.text(); - console.warn(`Pipeline API error for ${safeFile}: ${errText}. Marking document as parsed with default metadata.`); - try { - await query( - "UPDATE documents SET parsed = true, metadata = $1 WHERE filename = $2", - [JSON.stringify({ - tanggal: "Not Found", - noPO: "Not Found", - noSO: "Not Found", - noDO: "Not Found", - vendorInfo: "Not Found", - customerInfo: "Not Found", - items: [] - }), safeFile] - ); - } catch (dbErr) { - console.error("Failed to mark document as parsed on pipeline error:", dbErr); - } - return NextResponse.json({ error: `Pipeline API error: ${errText}` }, { status: response.status }); - } - - let data = await response.json(); - - // Check if the image is not straight (tilt > 1.0 degree) - const tilt = calculateAverageTilt(data); + let data: any = null; + let tilt = 0; let unwarped = false; - if (tilt > 1.0) { - console.log(`Parsed document ${safeFile} is not straight (average tilt: ${tilt.toFixed(2)} deg). Re-running with unwarping and orientation classification enabled...`); - const unwarpPayload = { - ...payload, - useDocUnwarping: true, + + if (cachedDoc.rows.length > 0 && cachedDoc.rows[0].layout_parsing_result) { + console.log(`[Cache Hit] Found cached layout result for ${safeFile}. Skipping Pipeline API.`); + const rawData = cachedDoc.rows[0].layout_parsing_result; + const parsedData = typeof rawData === "string" ? JSON.parse(rawData) : rawData; + data = parsedData.result || parsedData; + + const procLogs = cachedDoc.rows[0].processing_logs; + if (procLogs) { + const parsedLogs = typeof procLogs === "string" ? JSON.parse(procLogs) : procLogs; + tilt = parsedLogs?.pipeline_info?.tilt !== undefined ? Number(parsedLogs.pipeline_info.tilt) : 0; + unwarped = parsedLogs?.pipeline_info?.unwarped ?? false; + } + } else { + // Form payload + const payload = { + file: b64, + matchHistoryJob: false, + useLayoutDetection: true, + fileType: 1, + useDocUnwarping: false, useDocOrientationClassify: true }; - const unwarpResponse = await fetch(pipelineUrl, { + + // Post to Pipeline API + const pipelineUrl = process.env.PIPELINE_URL || "http://localhost:7871/layout-parsing"; + + console.log(`Forwarding request to pipeline API: ${pipelineUrl}`); + const response = await fetch(pipelineUrl, { method: "POST", headers: { "Content-Type": "application/json" }, - body: JSON.stringify(unwarpPayload) + body: JSON.stringify(payload) }); - if (unwarpResponse.ok) { - data = await unwarpResponse.json(); - console.log(`Document unwarped successfully.`); - unwarped = true; - } else { - console.error(`Unwarping failed with status ${unwarpResponse.status}`); + + if (!response.ok) { + const errText = await response.text(); + console.warn(`Pipeline API error for ${safeFile}: ${errText}. Marking document as parsed with default metadata.`); + try { + await query( + "UPDATE documents SET parsed = true, metadata = $1 WHERE filename = $2", + [JSON.stringify({ + tanggal: "Not Found", + noPO: "Not Found", + noSO: "Not Found", + noDO: "Not Found", + vendorInfo: "Not Found", + customerInfo: "Not Found", + items: [] + }), safeFile] + ); + } catch (dbErr) { + console.error("Failed to mark document as parsed on pipeline error:", dbErr); + } + return NextResponse.json({ error: `Pipeline API error: ${errText}` }, { status: response.status }); + } + + data = await response.json(); + + // Check if the image is not straight (tilt > 1.0 degree) + tilt = calculateAverageTilt(data); + if (tilt > 1.0) { + console.log(`Parsed document ${safeFile} is not straight (average tilt: ${tilt.toFixed(2)} deg). Re-running with unwarping and orientation classification enabled...`); + const unwarpPayload = { + ...payload, + useDocUnwarping: true, + useDocOrientationClassify: true + }; + const unwarpResponse = await fetch(pipelineUrl, { + method: "POST", + headers: { + "Content-Type": "application/json" + }, + body: JSON.stringify(unwarpPayload) + }); + if (unwarpResponse.ok) { + data = await unwarpResponse.json(); + console.log(`Document unwarped successfully.`); + unwarped = true; + } else { + console.error(`Unwarping failed with status ${unwarpResponse.status}`); + } } } diff --git a/backend/sources/ai_results.json b/backend/sources/ai_results.json index 0cf38f2..ba4b72a 100644 --- a/backend/sources/ai_results.json +++ b/backend/sources/ai_results.json @@ -151,8 +151,8 @@ } ], "platTruk": "B 9427 UXT", - "orderUntuk": "", - "alamat": "" + "orderUntuk": "PX HEAD OFFICE ANCOL", + "alamat": "JL. ANCOL BARAT VIII/1 KEL. ANCOL, KEC. PADEMANGAN JAKARTA UTARA, DKI JAKARTA" }, "items": [ { @@ -252,8 +252,8 @@ } ], "platTruk": "B 9723 CXS", - "orderUntuk": "", - "alamat": "" + "orderUntuk": "AYAM HITZ HO ANCOL", + "alamat": "JL. ANCOL BARAT VIII/1 KEL. ANCOL, KEC. PADEMANGAN JAKARTA UTARA, DKI JAKARTA" }, "items": [ { @@ -338,8 +338,8 @@ } ], "platTruk": "B 9257 JXR", - "orderUntuk": "", - "alamat": "" + "orderUntuk": "PX HEAD OFFICE ANCOL", + "alamat": "JL. ANCOL BARAT VIII/1 KEL. ANCOL, KEC. PADEMANGAN JAKARTA UTARA, DKI JAKARTA" }, "items": [ { @@ -450,8 +450,8 @@ } ], "platTruk": "B 9257 JXR", - "orderUntuk": "", - "alamat": "" + "orderUntuk": "PX HEAD OFFICE ANCOL", + "alamat": "JL. ANCOL BARAT VIII/1 KEL. ANCOL, KEC. PADEMANGAN JAKARTA UTARA, DKI JAKARTA" }, "items": [ { @@ -649,8 +649,8 @@ } ], "platTruk": "B 9715 UXU", - "orderUntuk": "", - "alamat": "" + "orderUntuk": "PX HEAD OFFICE ANCOL", + "alamat": "JL. ANCOL BARAT VIII/1 KEL. ANCOL, KEC. PADEMANGAN JAKARTA UTARA, DKI JAKARTA" }, "items": [ { @@ -704,7 +704,7 @@ "status": "success", "tilt": 17.41, "unwarped": true, - "rawMarkdown": "\n
CHARDEN POKPHAND INDONESIA TBK06:28:48 / 1otTanggal :30 June 2026
AWASAM INDUSTRI MODERN.No. SO :1691972284
BANTENNo. DO :1659990583
No. PO :PO/26/0000241302
\n\n
\"Image\"
\n\n\n00088615\n\nKepada : Kepala Gudang\n\n## DELIVERY ORDER\n\nKepada Yth : PT.PRIMAFOOD INTERNATIONAL\n\nOrder Untuk : DKI AREA\n\nAlamat : JL. ANCOL BARAT VIII/1. ANCOL. PADEMANGAN.\n\nJAKARTA UTARA. 14430\n\n\n\n\n
Kode BarangNama BarangBanyakJumlah
12010509829 Champ Crunchy Nugget 450 G1 BOX10 PAC
12010512888 Champ Naget Avam Kombinasi 900 G1 BOX6 PAC
12010519894 CHAMP NAGET KOMBINASI BENTUK STIK 901 BOX6 PAC
12012501600 Akumo Chicken Naget 250 Gr1 BOX20 PAC
12012503602 Akumo Chicken Naget 1 Ka1 BOX5 PAC
13010116692 Fiesta Original Sausage 300 GR1 BOX20 PAC
13010514299 Champ Chicken Sausage 1 Ka FR1 BOX10 PAC
13030502298 Champ Chicken Ball 500 GR Fr1 BOX10 PAC
Barang dikirim dalam keadaan baikJumlah
\"Image\"\"56 JXRWH 01 / 01
HEAD OFFICE ANCOL ! JL. ANCOL BARAT VIII NO. 1 JAKARTA UTARA IDN \"Image\"\"
Bag. Pengeluaran Barang Bagian Peniualan
\n\nLembar3 : Customer\n\n3 : Customer", + "rawMarkdown": "\n
CHARDEN POKPHAND INDONESIA TBK06:28:48 / 1otTanggal :30 June 2026
AWASAM INDUSTRI MODERN.No. SO :1691972284
BANTENNo. DO :1659990583
No. PO :PO/26/0000241302
\n\n
\"Image\"
\n\n\n00088615\n\nKepada : Kepala Gudang\n\n## DELIVERY ORDER\n\nKepada Yth : PT.PRIMAFOOD INTERNATIONAL\n\nOrder Untuk : DKI AREA\n\nAlamat : JL. ANCOL BARAT VIII/1. ANCOL. PADEMANGAN.\n\nJAKARTA UTARA. 14430\n\n\n\n\n
Kode BarangNama BarangBanyakJumlah
12010509\n12010512\n12010519\n12012501\n12012503\n13010116\n13010514\n13030502829 Champ Crunchy Nugget 450 G\n888 Champ Naget Avam Kombinasi 900 G\n894 CHAMP NAGET KOMBINASI BENTUK STIK 90\n600 AKumo Chicken Naget 250 Gr\n602 AKumo Chicken Naget 1 Ka\n692 Fiesta Original Sausage 300 GR\n299 Champ Chicken Sausage 1 Ka FR\n298 Champ Chicken Ball 500 GR Fr1 BOX\n1 BOX\n1 BOX\n1 BOX\n1 BOX\n1 BOX\n1 BOX10 PAC\n6 PAC\n6 PAC\n20 PAC\n5 PAC\n20 PAC\n10 PAC\n10 PAC
Barang dikirim dalam keadaan baikJumlah
\"Image\"\"\"Image\"\"WH 01 / 01\nHEAD OFFICE ANCOL ! JL. ANCOL BARAT VIII NO. 1 JAKARTA UTARA IDN
\n\nLembar3 : Customer\n\n3 : Customer", "layer1RawRegex": { "vendorInfo": "PT.PRIMAFOOD INTERNATIONAL", "customerInfo": "PT.PRIMAFOOD INTERNATIONAL", @@ -768,27 +768,6 @@ "banyak": "1 BOX", "jumlah": "10 PAC", "kodeBarangOriginal": "13030502" - }, - { - "kodeBarang": "", - "namaBarang": "56 JXR", - "banyak": "WH 01 / 01", - "jumlah": "WH 01 / 01", - "kodeBarangOriginal": "" - }, - { - "kodeBarang": "HEAD OFFICE ANCOL ! JL. ANCOL BARAT VIII NO. 1 JAKARTA UTARA IDN", - "namaBarang": "HEAD OFFICE ANCOL ! JL. ANCOL BARAT VIII NO. 1 JAKARTA UTARA IDN", - "banyak": "HEAD OFFICE ANCOL ! JL. ANCOL BARAT VIII NO. 1 JAKARTA UTARA IDN", - "jumlah": "", - "kodeBarangOriginal": "HEAD OFFICE ANCOL ! JL. ANCOL BARAT VIII NO. 1 JAKARTA UTARA IDN" - }, - { - "kodeBarang": "Bag. Pengeluaran Barang Bagian Peniualan", - "namaBarang": "Bag. Pengeluaran Barang Bagian Peniualan", - "banyak": "Bag. Pengeluaran Barang Bagian Peniualan", - "jumlah": "", - "kodeBarangOriginal": "Bag. Pengeluaran Barang Bagian Peniualan" } ], "platTruk": "" @@ -821,13 +800,13 @@ }, { "kodeBarang": "12012501", - "namaBarang": "600 Akumo Chicken Naget 250 Gr", + "namaBarang": "600 AKumo Chicken Naget 250 Gr", "banyak": "1 BOX", "jumlah": "20 PAC" }, { "kodeBarang": "12012503", - "namaBarang": "602 Akumo Chicken Naget 1 Ka", + "namaBarang": "602 AKumo Chicken Naget 1 Ka", "banyak": "1 BOX", "jumlah": "5 PAC" }, @@ -848,24 +827,6 @@ "namaBarang": "298 Champ Chicken Ball 500 GR Fr", "banyak": "1 BOX", "jumlah": "10 PAC" - }, - { - "kodeBarang": "", - "namaBarang": "56 JXR", - "banyak": "WH 01 / 01", - "jumlah": "WH 01 / 01" - }, - { - "kodeBarang": "HEAD OFFICE ANCOL ! JL. ANCOL BARAT VIII NO. 1 JAKARTA UTARA IDN", - "namaBarang": "HEAD OFFICE ANCOL ! JL. ANCOL BARAT VIII NO. 1 JAKARTA UTARA IDN", - "banyak": "HEAD OFFICE ANCOL ! JL. ANCOL BARAT VIII NO. 1 JAKARTA UTARA IDN", - "jumlah": "" - }, - { - "kodeBarang": "Bag. Pengeluaran Barang Bagian Peniualan", - "namaBarang": "Bag. Pengeluaran Barang Bagian Peniualan", - "banyak": "Bag. Pengeluaran Barang Bagian Peniualan", - "jumlah": "" } ], "platTruk": "" @@ -936,8 +897,8 @@ } ], "platTruk": "", - "orderUntuk": "", - "alamat": "" + "orderUntuk": "PX HEAD OFFICE ANCOL", + "alamat": "JL. ANCOL BARAT VIII/1 KEL. ANCOL, KEC. PADEMANGAN JAKARTA UTARA, DKI JAKARTA" }, "items": [ { @@ -1110,8 +1071,8 @@ } ], "platTruk": "B 9256 JXR", - "orderUntuk": "", - "alamat": "" + "orderUntuk": "PX HEAD OFFICE ANCOL", + "alamat": "JL. ANCOL BARAT VIII/1 KEL. ANCOL, KEC. PADEMANGAN JAKARTA UTARA, DKI JAKARTA" }, "items": [ { @@ -1183,8 +1144,8 @@ } ], "platTruk": "", - "orderUntuk": "", - "alamat": "" + "orderUntuk": "PX HEAD OFFICE ANCOL", + "alamat": "JL. ANCOL BARAT VIII/1 KEL. ANCOL, KEC. PADEMANGAN JAKARTA UTARA, DKI JAKARTA" }, "items": [ { @@ -1282,8 +1243,8 @@ } ], "platTruk": "B 9257 JXR", - "orderUntuk": "", - "alamat": "" + "orderUntuk": "PX HEAD OFFICE ANCOL", + "alamat": "JL. ANCOL BARAT VIII/1 KEL. ANCOL, KEC. PADEMANGAN JAKARTA UTARA, DKI JAKARTA" }, "items": [ { @@ -1381,8 +1342,8 @@ } ], "platTruk": "", - "orderUntuk": "", - "alamat": "" + "orderUntuk": "PRIMA XPRESS - TOWN HALL ANCOL", + "alamat": "JL. ANCOL BARAT VIII/1 KEL. ANCOL, KEC. PADEMANGAN, JAKARTA UTARA, DKI JAKARTA (KANTIN CPI)" }, "items": [ { @@ -1480,8 +1441,8 @@ } ], "platTruk": "", - "orderUntuk": "", - "alamat": "" + "orderUntuk": "PX HEAD OFFICE ANCOL", + "alamat": "JL. ANCOL BARAT VIII/1 KEL. ANCOL, KEC. PADEMANGAN JAKARTA UTARA, DKI JAKARTA" }, "items": [ { @@ -1579,8 +1540,8 @@ } ], "platTruk": "", - "orderUntuk": "", - "alamat": "" + "orderUntuk": "PX HEAD OFFICE ANCOL", + "alamat": "JL. ANCOL BARAT VIII/1 KEL. ANCOL, KEC. PADEMANGAN JAKARTA UTARA, DKI JAKARTA" }, "items": [ { @@ -1599,7 +1560,7 @@ "status": "success", "tilt": 0.57, "unwarped": false, - "rawMarkdown": "## Purchase Order\n\n\n
Nomor P.O: PO/26/0000230199
: 22/06/2026
KAWASAKI INDUSTRI MODERN. BANTEN02:56:41Tanggal :
No. SO : 23 June 2026
No. DO : 1691960321
DELIVERY ORDERNo. PO : 1659980277
\n\nKepala Gudang\n\n00169133\n\nKepada Yth :\n\nOrder Untuk : PT.PRIMAFOOD INTERNATIONAL\n\nAlamat : DKI AREA\n\nJL.ANCOL BARAT VIII/1.ANCOL.PADEMANGAN.\n\n\n
Kode BarangNama BarangJAKARTA UTARA, 14430\\nJAKARTA UTA RABanyakJumlah
11310014\\n11310024\\n11620056\\n11690053\\n11720055✓ Griller Size 2 ( 20 Ekor ) Frozen\\n✓ Griller Size A Frozen (900-1000 G) PC\\n✓ SBL Mitra 10 Kg\\n✓ SBB Mitra 10 Kg\\n✓ Full Wing Frozen Pack2KRG40 PC
2KRG40 PC
1BOX10 KG
1BOX10 KG
1BOX10 KG
Barang dikirim dalam keadaan baikJumlah
Truck No. B 9427 UXT\\nPX, HEAD OFFICE ANCOL ; JL. ANCOL BARAT VIII NO. 1 JAKARTA UTARA IDN
Penerima Barang Tanda Tangan Supir\\nBag. Pengeluaran Barang
3 : Customer Jika D.O. ini telah ditanda tangan oleh Penerima barang tanpa sanggahan, segala CLAIM atas kekurangan barang tidak dapat kami layani
\n\n\n
COPY P.O SELALUPPN254,000.00
Total
Menyetujui
", + "rawMarkdown": "## Purchase Order\n\n\n
Nomor P.O: PO/26/0000230199
: 22/06/2026
KAWASAKI INDUSTRI MODERN.02:56:41Tanggal :
BANTENNo. SO :23 June 2026
No. DO :1691960321
No. PO :1659980277
DELIVERY ORDERPO/26/0000230828
\n\nKepala Gudang\n\n00169133\n\nKepada Yth :\n\nOrder Untuk : PT.PRIMAFOOD INTERNATIONAL\n\nAlamat : DKI AREA\n\nJL.ANCOL BARAT VIII/1.ANCOL.PADEMANGAN.\n\n\n
Kode BarangNama BarangJAKARTA UTARA, 14430\\nJAKARTA UTA RABanyakJumlah
11310014\\n11310024\\n11620056\\n11690053\\n11720055✓ Griller Size 2 ( 20 Ekor ) Frozen\\n✓ Griller Size A Frozen (900-1000 G) PC\\n✓ SBL Mitra 10 Kg\\n✓ SBB Mitra 10 Kg\\n✓ Full Wing Frozen Pack2KRG40 PC
2KRG40 PC
1BOX10 KG
1BOX10 KG
1BOX10 KG
Barang dikirim dalam keadaan baikJumlah
Truck No. B 9427 UXT\\nPX, HEAD OFFICE ANCOL ; JL. ANCOL BARAT VIII NO. 1 JAKARTA UTARA IDN
Penerima Barang Tanda Tangan Supir\\nBag. Pengeluaran Barang
3 : Customer Jika D.O. ini telah ditanda tangan oleh Penerima barang tanpa sanggahan, segala CLAIM atas kekurangan barang tidak dapat kami layani
\n\n\n
COPY P.O SELALUPPN254,000.00
Total
Menyetujui
", "layer1RawRegex": { "vendorInfo": "PT.PRIMAFOOD INTERNATIONAL", "customerInfo": "PT.PRIMAFOOD INTERNATIONAL", @@ -1797,8 +1758,8 @@ } ], "platTruk": "B 9427 UXT", - "orderUntuk": "", - "alamat": "" + "orderUntuk": "PX HEAD OFFICE ANCOL", + "alamat": "JL. ANCOL BARAT VIII/1 KEL. ANCOL, KEC. PADEMANGAN JAKARTA UTARA, DKI JAKARTA" }, "items": [ { @@ -2145,8 +2106,8 @@ } ], "platTruk": "B 9948 VCC", - "orderUntuk": "", - "alamat": "" + "orderUntuk": "PX HEAD OFFICE ANCOL", + "alamat": "JL. ANCOL BARAT VIII/1 KEL. ANCOL, KEC. PADEMANGAN JAKARTA UTARA, DKI JAKARTA" }, "items": [ { @@ -2277,8 +2238,8 @@ } ], "platTruk": "B 9599 CXS", - "orderUntuk": "", - "alamat": "" + "orderUntuk": "PX HEAD OFFICE ANCOL", + "alamat": "JL. ANCOL BARAT VIII/1 KEL. ANCOL, KEC. PADEMANGAN JAKARTA UTARA, DKI JAKARTA" }, "items": [ { @@ -2403,8 +2364,8 @@ } ], "platTruk": "B 9254 SCG", - "orderUntuk": "", - "alamat": "" + "orderUntuk": "PX HEAD OFFICE ANCOL", + "alamat": "JL. ANCOL BARAT VIII/1 KEL. ANCOL, KEC. PADEMANGAN JAKARTA UTARA, DKI JAKARTA" }, "items": [ { @@ -2562,8 +2523,8 @@ } ], "platTruk": "B 9053 VCF", - "orderUntuk": "", - "alamat": "" + "orderUntuk": "PX HEAD OFFICE ANCOL", + "alamat": "JL. ANCOL BARAT VIII/1 KEL. ANCOL, KEC. PADEMANGAN JAKARTA UTARA, DKI JAKARTA" }, "items": [ { @@ -2802,8 +2763,8 @@ } ], "platTruk": "B 9260 BXT", - "orderUntuk": "", - "alamat": "" + "orderUntuk": "PX HEAD OFFICE ANCOL", + "alamat": "JL. ANCOL BARAT VIII/1 KEL. ANCOL, KEC. PADEMANGAN JAKARTA UTARA, DKI JAKARTA" }, "items": [ { @@ -3023,8 +2984,8 @@ } ], "platTruk": "B 9365 AI", - "orderUntuk": "", - "alamat": "" + "orderUntuk": "PX HEAD OFFICE ANCOL", + "alamat": "JL. ANCOL BARAT VIII/1 KEL. ANCOL, KEC. PADEMANGAN JAKARTA UTARA, DKI JAKARTA" }, "items": [ { @@ -3296,8 +3257,8 @@ } ], "platTruk": "", - "orderUntuk": "", - "alamat": "" + "orderUntuk": "PX HEAD OFFICE ANCOL", + "alamat": "JL. ANCOL BARAT VIII/1 KEL. ANCOL, KEC. PADEMANGAN JAKARTA UTARA, DKI JAKARTA" }, "items": [ { @@ -3484,8 +3445,8 @@ } ], "platTruk": "B 9683 VCF", - "orderUntuk": "", - "alamat": "" + "orderUntuk": "PX HEAD OFFICE ANCOL", + "alamat": "JL. ANCOL BARAT VIII/1 KEL. ANCOL, KEC. PADEMANGAN JAKARTA UTARA, DKI JAKARTA" }, "items": [ { @@ -3729,8 +3690,8 @@ } ], "platTruk": "B 9042 VCC", - "orderUntuk": "", - "alamat": "" + "orderUntuk": "PX HEAD OFFICE ANCOL", + "alamat": "JL. ANCOL BARAT VIII/1 KEL. ANCOL, KEC. PADEMANGAN JAKARTA UTARA, DKI JAKARTA" }, "items": [ { @@ -3929,8 +3890,8 @@ } ], "platTruk": "B 9260 VCF", - "orderUntuk": "", - "alamat": "" + "orderUntuk": "PX HEAD OFFICE ANCOL", + "alamat": "JL. ANCOL BARAT VIII/1 KEL. ANCOL, KEC. PADEMANGAN JAKARTA UTARA, DKI JAKARTA" }, "items": [ { @@ -3970,7 +3931,7 @@ "status": "success", "tilt": 15.19, "unwarped": true, - "rawMarkdown": "KAWASAN INDUSTRI MODERN.\n\nKepada : Kepala Gudang\n\n00202207\n\n## DELIVERY ORDER\n\nTanggal : 3.2019.007731\n\nNo. SO : 1691896671\n\nNo. DO : 1659921089\n\nNo. PO : PO/26/0000166510\n\nKepada Yth : PT.PRIMAFOOD INTERNATIONAL\n\nOrder Untuk : PFM-KU\n\nAlamat : JL. ANCOL BARAT VIII/1, ANCOL, PADEMANGAN, JAKARTA UTARA, 14430\n\nJAKARTA UTADA\n\n\n
Kode BarangNama BarangBanyakJumlah
11310014✓ Griller Size 2 ( 20 Ekor ) Frozen5 KRG100 PC
11310018✓ Griller (PR) Size 1 Friz1 KRG30 PC
11310024✓ Griller Size A Frozen (900-1000 G) PC5 KRG100 PC
11640053✓ Bone In Leg ASLI1 80X10 KG
11660050✓ Drumstick Frozen Pack1 80X10 KG
11710051✓ Bone In Breast Frozen Pack1 80X10 KG
11750050✓ fillet Mitra 10 Kg1 80X10 KG
Barang dikirim dalam keadaan baikJumlah234270
\"Image\"\" ENTRA \"Image\"\" \"Image\"\" WH 01 / 01 IL DANAU KELAPA DUA ( Bagian Penjualan
\n\nembar 1: Customer\n\nJika D.O. ini telah ditanda tangan oleh Penerima barang tanpa sanggahan, segala CLAIM atas kekurangan barang tidak dapat kami layani\n\nDinindoi dengan", + "rawMarkdown": "KAWASAN INDUSTRI MODERN.\n\nKepada : Kepala Gudang\n\n00202207\n\n## DELIVERY ORDER\n\nTanggal : 3.2019.007731\n\nNo. SO : 1691896671\n\nNo. DO : 1659921089\n\nNo. PO : PO/26/0000166510\n\nKepada Yth : PT.PRIMAFOOD INTERNATIONAL\n\nOrder Untuk : PFM-KU\n\nAlamat : JL. ANCOL BARAT VIII/1, ANCOL, PADEMANGAN, JAKARTA UTARA, 14430\n\nJAKARTA ITARA\n\n\n
Kode BarangNama BarangBanyakJumlah
11310014✓ Griller Size 2 ( 20 Ekor ) Frozen5 KRG100 PC
11310018✓ Griller (PR) Size 1 Friz1 KRG30 PC
11310024✓ Griller Size A Frozen (900-1000 G) PC5 KRG100 PC
11640053✓ Bone In Leg ASLI1 80X10 KG
11660050✓ Drumstick Frozen Pack1 80X10 KG
11710051✓ Bone In Breast Frozen Pack1 80X10 KG
11750050✓ fillet Mitra 10 Kg1 80X10 KG
Barang dikirim dalam keadaan baikJumlah234270
\"Image\"\" ENTRA \"Image\"\" \"Image\"\" WH 01 / 01 IL DANAU KELAPA DUA ( Bagian Penjualan
\n\nembar 1: Customer\n\nJika D.O. ini telah ditanda tangan oleh Penerima barang tanpa sanggahan, segala CLAIM atas kekurangan barang tidak dapat kami layani\n\nDinindoi dengan", "layer1RawRegex": { "vendorInfo": "PT.PRIMAFOOD INTERNATIONAL", "customerInfo": "PT.PRIMAFOOD INTERNATIONAL", @@ -4156,8 +4117,8 @@ } ], "platTruk": "", - "orderUntuk": "", - "alamat": "" + "orderUntuk": "PX HEAD OFFICE ANCOL", + "alamat": "JL. ANCOL BARAT VIII/1 KEL. ANCOL, KEC. PADEMANGAN JAKARTA UTARA, DKI JAKARTA" }, "items": [ { @@ -4357,8 +4318,8 @@ } ], "platTruk": "B 9417 VOC", - "orderUntuk": "", - "alamat": "" + "orderUntuk": "PM PANORAMA BALI RESIDENCE BGR", + "alamat": "PANORAMA BALI RESIDENCE B NO 16, KEL. PUTAT NUTUG, KEC. CISEENG, KAB. BOGOR 16120" }, "items": [ { @@ -4630,8 +4591,8 @@ } ], "platTruk": "B 9259 BCU", - "orderUntuk": "", - "alamat": "" + "orderUntuk": "PX HEAD OFFICE ANCOL", + "alamat": "JL. ANCOL BARAT VIII/1 KEL. ANCOL, KEC. PADEMANGAN JAKARTA UTARA, DKI JAKARTA" }, "items": [ { @@ -4838,8 +4799,8 @@ } ], "platTruk": "", - "orderUntuk": "", - "alamat": "" + "orderUntuk": "PX HEAD OFFICE ANCOL", + "alamat": "JL. ANCOL BARAT VIII/1 KEL. ANCOL, KEC. PADEMANGAN JAKARTA UTARA, DKI JAKARTA" }, "items": [ { @@ -5024,8 +4985,8 @@ } ], "platTruk": "B 9260 BXT", - "orderUntuk": "", - "alamat": "" + "orderUntuk": "PX HEAD OFFICE ANCOL", + "alamat": "JL. ANCOL BARAT VIII/1 KEL. ANCOL, KEC. PADEMANGAN JAKARTA UTARA, DKI JAKARTA" }, "items": [ { @@ -5157,8 +5118,8 @@ } ], "platTruk": "B 9308 BXT", - "orderUntuk": "", - "alamat": "" + "orderUntuk": "PM KAMPUNG TENGAH", + "alamat": "JL. RAYA TENGAH RT. 004, RW. 009, KEL. TENGAH, KEC. KRAMAT JATI, JAKARTA TIMUR 13540" }, "items": [ { @@ -5270,8 +5231,8 @@ } ], "platTruk": "B 9767 NCD", - "orderUntuk": "", - "alamat": "" + "orderUntuk": "PX HEAD OFFICE ANCOL", + "alamat": "JL. ANCOL BARAT VIII/1 KEL. ANCOL, KEC. PADEMANGAN JAKARTA UTARA, DKI JAKARTA" }, "items": [ { @@ -5469,8 +5430,8 @@ } ], "platTruk": "", - "orderUntuk": "", - "alamat": "" + "orderUntuk": "PX HEAD OFFICE ANCOL", + "alamat": "JL. ANCOL BARAT VIII/1 KEL. ANCOL, KEC. PADEMANGAN JAKARTA UTARA, DKI JAKARTA" }, "items": [ { @@ -5682,8 +5643,8 @@ } ], "platTruk": "B 9402 SCH", - "orderUntuk": "", - "alamat": "" + "orderUntuk": "PX HEAD OFFICE ANCOL", + "alamat": "JL. ANCOL BARAT VIII/1 KEL. ANCOL, KEC. PADEMANGAN JAKARTA UTARA, DKI JAKARTA" }, "items": [ { @@ -5789,8 +5750,8 @@ } ], "platTruk": "", - "orderUntuk": "", - "alamat": "" + "orderUntuk": "PX HEAD OFFICE ANCOL", + "alamat": "JL. ANCOL BARAT VIII/1 KEL. ANCOL, KEC. PADEMANGAN JAKARTA UTARA, DKI JAKARTA" }, "items": [ { @@ -5928,8 +5889,8 @@ } ], "platTruk": "B 9726 UCT", - "orderUntuk": "", - "alamat": "" + "orderUntuk": "PX HEAD OFFICE ANCOL", + "alamat": "JL. ANCOL BARAT VIII/1 KEL. ANCOL, KEC. PADEMANGAN JAKARTA UTARA, DKI JAKARTA" }, "items": [ { @@ -6094,8 +6055,8 @@ } ], "platTruk": "", - "orderUntuk": "", - "alamat": "" + "orderUntuk": "PX HEAD OFFICE ANCOL", + "alamat": "JL. ANCOL BARAT VIII/1 KEL. ANCOL, KEC. PADEMANGAN JAKARTA UTARA, DKI JAKARTA" }, "items": [ { @@ -6207,8 +6168,8 @@ } ], "platTruk": "B 9259 BCU", - "orderUntuk": "", - "alamat": "" + "orderUntuk": "PX HEAD OFFICE ANCOL", + "alamat": "JL. ANCOL BARAT VIII/1 KEL. ANCOL, KEC. PADEMANGAN JAKARTA UTARA, DKI JAKARTA" }, "items": [ { diff --git a/backend/sources/ai_results.md b/backend/sources/ai_results.md index 4c0aacc..5a5e6db 100644 --- a/backend/sources/ai_results.md +++ b/backend/sources/ai_results.md @@ -1,7 +1,7 @@ # OCR Batch Test Report -> Generated: 2026-07-03T08:59:19.013Z -> API: `reparsed-via-new-algorithm` +> Generated: 2026-07-03T09:42:29.584Z +> API: `http://localhost:8000/api/parse` > Images: **37** files from `backend/sources/test-images/` --- @@ -63,6 +63,8 @@ #### 📄 Stage 1 — Raw OCR Markdown +*This is the raw text extracted by PaddleOCR layout parser before any post-processing.* + ```markdown
Image
@@ -109,6 +111,8 @@ Jika D.O. ini telah ditanda tangan oleh Penerima barang tanpa sanggahan, segala #### 🔍 Stage 2 — Layer 1: Regex Extraction (`parseDOMetadata`) +*Regex patterns are applied to raw markdown to extract header fields and item rows.* + **Header fields (raw regex output):** - **noDO**: `1659980277` @@ -134,6 +138,8 @@ Jika D.O. ini telah ditanda tangan oleh Penerima barang tanpa sanggahan, segala #### 🧹 Stage 3 — Layer 2: Sanitized (`sanitizeParsedMetadata`) +*Strict format enforcement: corrects date formats, trims whitespace, enforces field constraints.* + **Header fields (after sanitization):** - **noDO**: `1659980277` @@ -159,6 +165,8 @@ Jika D.O. ini telah ditanda tangan oleh Penerima barang tanpa sanggahan, segala #### ✅ Stage 4 — Layer 3: Final (`SKU triple-check + store resolution`) +*SKU validated against master list (score ≥ 0.6 threshold). Items with noise SKU codes are filtered out. Store resolved from DB.* + **Final metadata:** - **noDO**: `1659980277` @@ -167,8 +175,8 @@ Jika D.O. ini telah ditanda tangan oleh Penerima barang tanpa sanggahan, segala - **tanggal**: `23 June 2026` - **vendorInfo**: `PT.PRIMAFOOD INTERNATIONAL` - **customerInfo**: `PT.PRIMAFOOD INTERNATIONAL` -- **alamat**: *empty* -- **orderUntuk**: *empty* +- **alamat**: `JL. ANCOL BARAT VIII/1 KEL. ANCOL, KEC. PADEMANGAN JAKARTA UTARA, DKI JAKARTA` +- **orderUntuk**: `PX HEAD OFFICE ANCOL` - **platTruk**: `B 9427 UXT` **Final items after SKU validation (5 row(s)):** @@ -183,6 +191,8 @@ Jika D.O. ini telah ditanda tangan oleh Penerima barang tanpa sanggahan, segala #### 🗃️ Stage 5 — Submitted Items (ready-to-use JSON) +*These are the items actually returned to the caller and saved to the database.* + | kodeBarangOriginal | kodeBarang | namaBarang | banyak | jumlah | | --- | --- | --- | --- | --- | | 11310014 | 11310014 | AYAM SIZE 2 FROZEN (0.8-0.9)KG(*) | 2 KRG | 40 PC | @@ -204,6 +214,8 @@ Jika D.O. ini telah ditanda tangan oleh Penerima barang tanpa sanggahan, segala #### 📄 Stage 1 — Raw OCR Markdown +*This is the raw text extracted by PaddleOCR layout parser before any post-processing.* + ```markdown Agnes 'Telco 23 Telkom fineshyt telco kmrn ngechat gue tp ga jwb Ig @@ -281,6 +293,8 @@ Tanda Tangan Supir #### 🔍 Stage 2 — Layer 1: Regex Extraction (`parseDOMetadata`) +*Regex patterns are applied to raw markdown to extract header fields and item rows.* + **Header fields (raw regex output):** - **noDO**: `1659932080` @@ -301,6 +315,8 @@ Tanda Tangan Supir #### 🧹 Stage 3 — Layer 2: Sanitized (`sanitizeParsedMetadata`) +*Strict format enforcement: corrects date formats, trims whitespace, enforces field constraints.* + **Header fields (after sanitization):** - **noDO**: `1659932080` @@ -321,6 +337,8 @@ Tanda Tangan Supir #### ✅ Stage 4 — Layer 3: Final (`SKU triple-check + store resolution`) +*SKU validated against master list (score ≥ 0.6 threshold). Items with noise SKU codes are filtered out. Store resolved from DB.* + **Final metadata:** - **noDO**: `1659932080` @@ -329,8 +347,8 @@ Tanda Tangan Supir - **tanggal**: `15 May 2026` - **vendorInfo**: `PT.PRIMAFOOD INTERNATIONAL` - **customerInfo**: `PT.PRIMAFOOD INTERNATIONAL` -- **alamat**: *empty* -- **orderUntuk**: *empty* +- **alamat**: `JL. ANCOL BARAT VIII/1 KEL. ANCOL, KEC. PADEMANGAN JAKARTA UTARA, DKI JAKARTA` +- **orderUntuk**: `AYAM HITZ HO ANCOL` - **platTruk**: `B 9723 CXS` **Final items after SKU validation (1 row(s)):** @@ -341,6 +359,8 @@ Tanda Tangan Supir #### 🗃️ Stage 5 — Submitted Items (ready-to-use JSON) +*These are the items actually returned to the caller and saved to the database.* + | kodeBarangOriginal | kodeBarang | namaBarang | banyak | jumlah | | --- | --- | --- | --- | --- | | 13012205 | 13012205 | ASIMO SOSIS AYAM KOMBINASI 375 GR (PAC) | 1 BOX | 15 PAC | @@ -358,6 +378,8 @@ Tanda Tangan Supir #### 📄 Stage 1 — Raw OCR Markdown +*This is the raw text extracted by PaddleOCR layout parser before any post-processing.* + ```markdown
Image
@@ -406,6 +428,8 @@ Jika D.D. ini telah ditanda tangan oleh Penerima barang tanpa sanggahan, segala #### 🔍 Stage 2 — Layer 1: Regex Extraction (`parseDOMetadata`) +*Regex patterns are applied to raw markdown to extract header fields and item rows.* + **Header fields (raw regex output):** - **noDO**: `1659990561` @@ -427,6 +451,8 @@ Jika D.D. ini telah ditanda tangan oleh Penerima barang tanpa sanggahan, segala #### 🧹 Stage 3 — Layer 2: Sanitized (`sanitizeParsedMetadata`) +*Strict format enforcement: corrects date formats, trims whitespace, enforces field constraints.* + **Header fields (after sanitization):** - **noDO**: `1659990561` @@ -448,6 +474,8 @@ Jika D.D. ini telah ditanda tangan oleh Penerima barang tanpa sanggahan, segala #### ✅ Stage 4 — Layer 3: Final (`SKU triple-check + store resolution`) +*SKU validated against master list (score ≥ 0.6 threshold). Items with noise SKU codes are filtered out. Store resolved from DB.* + **Final metadata:** - **noDO**: `1659990561` @@ -456,8 +484,8 @@ Jika D.D. ini telah ditanda tangan oleh Penerima barang tanpa sanggahan, segala - **tanggal**: `30 June 2026` - **vendorInfo**: `PT.PRIMAFOOD INTERNATIONAL` - **customerInfo**: `PT.PRIMAFOOD INTERNATIONAL` -- **alamat**: *empty* -- **orderUntuk**: *empty* +- **alamat**: `JL. ANCOL BARAT VIII/1 KEL. ANCOL, KEC. PADEMANGAN JAKARTA UTARA, DKI JAKARTA` +- **orderUntuk**: `PX HEAD OFFICE ANCOL` - **platTruk**: `B 9257 JXR` **Final items after SKU validation (1 row(s)):** @@ -468,6 +496,8 @@ Jika D.D. ini telah ditanda tangan oleh Penerima barang tanpa sanggahan, segala #### 🗃️ Stage 5 — Submitted Items (ready-to-use JSON) +*These are the items actually returned to the caller and saved to the database.* + | kodeBarangOriginal | kodeBarang | namaBarang | banyak | jumlah | | --- | --- | --- | --- | --- | | 21002601 | 21002601 | Prima Nasi Spicy Chick Sambal Geprek COPY | 1 BOX | 6 PAC | @@ -485,6 +515,8 @@ Jika D.D. ini telah ditanda tangan oleh Penerima barang tanpa sanggahan, segala #### 📄 Stage 1 — Raw OCR Markdown +*This is the raw text extracted by PaddleOCR layout parser before any post-processing.* + ```markdown
000006 MA TELUR OMEGA (PC)(*)900PCH/PCS1.950.00Amount
Qty:9001.755.000.00
DEN POKPHAND INDONESIA Tbk00:21:27Tanggal :
IN INDUSTRI MODERN.No. SO : 30 June 2026
ENNo. DO : 1691972227
No. PO : 1659990561PO/26/0000241938
@@ -513,6 +545,8 @@ SA UDANG #### 🔍 Stage 2 — Layer 1: Regex Extraction (`parseDOMetadata`) +*Regex patterns are applied to raw markdown to extract header fields and item rows.* + **Header fields (raw regex output):** - **noDO**: `1659990561` @@ -536,6 +570,8 @@ SA UDANG #### 🧹 Stage 3 — Layer 2: Sanitized (`sanitizeParsedMetadata`) +*Strict format enforcement: corrects date formats, trims whitespace, enforces field constraints.* + **Header fields (after sanitization):** - **noDO**: `1659990561` @@ -559,6 +595,8 @@ SA UDANG #### ✅ Stage 4 — Layer 3: Final (`SKU triple-check + store resolution`) +*SKU validated against master list (score ≥ 0.6 threshold). Items with noise SKU codes are filtered out. Store resolved from DB.* + **Final metadata:** - **noDO**: `1659990561` @@ -567,8 +605,8 @@ SA UDANG - **tanggal**: `30 June 2026` - **vendorInfo**: `Not Found` - **customerInfo**: `PT.PRIMAFOOD INTERNATIONAL` -- **alamat**: *empty* -- **orderUntuk**: *empty* +- **alamat**: `JL. ANCOL BARAT VIII/1 KEL. ANCOL, KEC. PADEMANGAN JAKARTA UTARA, DKI JAKARTA` +- **orderUntuk**: `PX HEAD OFFICE ANCOL` - **platTruk**: `B 9257 JXR` **Final items after SKU validation (1 row(s)):** @@ -579,6 +617,8 @@ SA UDANG #### 🗃️ Stage 5 — Submitted Items (ready-to-use JSON) +*These are the items actually returned to the caller and saved to the database.* + | kodeBarangOriginal | kodeBarang | namaBarang | banyak | jumlah | | --- | --- | --- | --- | --- | | 21002601 | 21002601 | Prima Nasi Spicy Chick Sambal Geprek COPY | 1 BOX | 6 PAC | @@ -596,6 +636,8 @@ SA UDANG #### 📄 Stage 1 — Raw OCR Markdown +*This is the raw text extracted by PaddleOCR layout parser before any post-processing.* + ```markdown
Image
@@ -633,6 +675,8 @@ Jika D.O. ini telah ditanda tangan oleh Penerima barang tanpa sanggahan, segala #### 🔍 Stage 2 — Layer 1: Regex Extraction (`parseDOMetadata`) +*Regex patterns are applied to raw markdown to extract header fields and item rows.* + **Header fields (raw regex output):** - **noDO**: `Not Found` @@ -660,6 +704,8 @@ Jika D.O. ini telah ditanda tangan oleh Penerima barang tanpa sanggahan, segala #### 🧹 Stage 3 — Layer 2: Sanitized (`sanitizeParsedMetadata`) +*Strict format enforcement: corrects date formats, trims whitespace, enforces field constraints.* + **Header fields (after sanitization):** - **noDO**: `Not Found` @@ -687,6 +733,8 @@ Jika D.O. ini telah ditanda tangan oleh Penerima barang tanpa sanggahan, segala #### ✅ Stage 4 — Layer 3: Final (`SKU triple-check + store resolution`) +*SKU validated against master list (score ≥ 0.6 threshold). Items with noise SKU codes are filtered out. Store resolved from DB.* + **Final metadata:** - **noDO**: `Not Found` @@ -695,8 +743,8 @@ Jika D.O. ini telah ditanda tangan oleh Penerima barang tanpa sanggahan, segala - **tanggal**: `Not Found` - **vendorInfo**: `PT.PRIMAFOOD INTERNATIONAL` - **customerInfo**: `PT.PRIMAFOOD INTERNATIONAL` -- **alamat**: *empty* -- **orderUntuk**: *empty* +- **alamat**: `JL. ANCOL BARAT VIII/1 KEL. ANCOL, KEC. PADEMANGAN JAKARTA UTARA, DKI JAKARTA` +- **orderUntuk**: `PX HEAD OFFICE ANCOL` - **platTruk**: `B 9715 UXU` **Final items after SKU validation (6 row(s)):** @@ -712,6 +760,8 @@ Jika D.O. ini telah ditanda tangan oleh Penerima barang tanpa sanggahan, segala #### 🗃️ Stage 5 — Submitted Items (ready-to-use JSON) +*These are the items actually returned to the caller and saved to the database.* + | kodeBarangOriginal | kodeBarang | namaBarang | banyak | jumlah | | --- | --- | --- | --- | --- | | 11310014 | 11310014 | AYAM SIZE 2 FROZEN (0.8-0.9)KG(*) | 3 KRG | 60 PC | @@ -734,6 +784,8 @@ Jika D.O. ini telah ditanda tangan oleh Penerima barang tanpa sanggahan, segala #### 📄 Stage 1 — Raw OCR Markdown +*This is the raw text extracted by PaddleOCR layout parser before any post-processing.* + ```markdown
CHARDEN POKPHAND INDONESIA TBK06:28:48 / 1otTanggal :30 June 2026
AWASAM INDUSTRI MODERN.No. SO :1691972284
BANTENNo. DO :1659990583
No. PO :PO/26/0000241302
@@ -758,7 +810,35 @@ JAKARTA UTARA. 14430 -
Kode BarangNama BarangBanyakJumlah
12010509829 Champ Crunchy Nugget 450 G1 BOX10 PAC
12010512888 Champ Naget Avam Kombinasi 900 G1 BOX6 PAC
12010519894 CHAMP NAGET KOMBINASI BENTUK STIK 901 BOX6 PAC
12012501600 Akumo Chicken Naget 250 Gr1 BOX20 PAC
12012503602 Akumo Chicken Naget 1 Ka1 BOX5 PAC
13010116692 Fiesta Original Sausage 300 GR1 BOX20 PAC
13010514299 Champ Chicken Sausage 1 Ka FR1 BOX10 PAC
13030502298 Champ Chicken Ball 500 GR Fr1 BOX10 PAC
Barang dikirim dalam keadaan baikJumlah
Image56 JXRWH 01 / 01
HEAD OFFICE ANCOL ! JL. ANCOL BARAT VIII NO. 1 JAKARTA UTARA IDN Image
Bag. Pengeluaran Barang Bagian Peniualan
+
Kode BarangNama BarangBanyakJumlah
12010509 +12010512 +12010519 +12012501 +12012503 +13010116 +13010514 +13030502829 Champ Crunchy Nugget 450 G +888 Champ Naget Avam Kombinasi 900 G +894 CHAMP NAGET KOMBINASI BENTUK STIK 90 +600 AKumo Chicken Naget 250 Gr +602 AKumo Chicken Naget 1 Ka +692 Fiesta Original Sausage 300 GR +299 Champ Chicken Sausage 1 Ka FR +298 Champ Chicken Ball 500 GR Fr1 BOX +1 BOX +1 BOX +1 BOX +1 BOX +1 BOX +1 BOX10 PAC +6 PAC +6 PAC +20 PAC +5 PAC +20 PAC +10 PAC +10 PAC
Barang dikirim dalam keadaan baikJumlah
ImageImageWH 01 / 01 +HEAD OFFICE ANCOL ! JL. ANCOL BARAT VIII NO. 1 JAKARTA UTARA IDN
Lembar3 : Customer @@ -767,6 +847,8 @@ Lembar3 : Customer #### 🔍 Stage 2 — Layer 1: Regex Extraction (`parseDOMetadata`) +*Regex patterns are applied to raw markdown to extract header fields and item rows.* + **Header fields (raw regex output):** - **noDO**: `1659990583` @@ -779,7 +861,7 @@ Lembar3 : Customer - **orderUntuk**: *empty* - **platTruk**: *empty* -**Raw items (11 row(s)):** +**Raw items (8 row(s)):** | kodeBarang | namaBarang | banyak | jumlah | | --- | --- | --- | --- | @@ -791,12 +873,11 @@ Lembar3 : Customer | 13010116 | FIESTA SSG ORIGINAL 300 GR | 1 BOX | 20 PAC | | 13010514 | CHAMP CHICK SSG 1000 GR | 1 BOX | 10 PAC | | 13030502 | CHAMP CHICK MEATBALL 500 GR | 1 BOX | 10 PAC | -| | 56 JXR | WH 01 / 01 | WH 01 / 01 | -| HEAD OFFICE ANCOL ! JL. ANCOL BARAT VIII NO. 1 JAKARTA UTARA IDN | HEAD OFFICE ANCOL ! JL. ANCOL BARAT VIII NO. 1 JAKARTA UTARA IDN | HEAD OFFICE ANCOL ! JL. ANCOL BARAT VIII NO. 1 JAKARTA UTARA IDN | | -| Bag. Pengeluaran Barang Bagian Peniualan | Bag. Pengeluaran Barang Bagian Peniualan | Bag. Pengeluaran Barang Bagian Peniualan | | #### 🧹 Stage 3 — Layer 2: Sanitized (`sanitizeParsedMetadata`) +*Strict format enforcement: corrects date formats, trims whitespace, enforces field constraints.* + **Header fields (after sanitization):** - **noDO**: `1659990583` @@ -809,24 +890,23 @@ Lembar3 : Customer - **orderUntuk**: *empty* - **platTruk**: *empty* -**Sanitized items (11 row(s)):** +**Sanitized items (8 row(s)):** | kodeBarang | namaBarang | banyak | jumlah | | --- | --- | --- | --- | | 12010509 | 829 Champ Crunchy Nugget 450 G | 1 BOX | 10 PAC | | 12010512 | 888 Champ Naget Avam Kombinasi 900 G | 1 BOX | 6 PAC | | 12010519 | 894 CHAMP NAGET KOMBINASI BENTUK STIK 90 | 1 BOX | 6 PAC | -| 12012501 | 600 Akumo Chicken Naget 250 Gr | 1 BOX | 20 PAC | -| 12012503 | 602 Akumo Chicken Naget 1 Ka | 1 BOX | 5 PAC | +| 12012501 | 600 AKumo Chicken Naget 250 Gr | 1 BOX | 20 PAC | +| 12012503 | 602 AKumo Chicken Naget 1 Ka | 1 BOX | 5 PAC | | 13010116 | 692 Fiesta Original Sausage 300 GR | 1 BOX | 20 PAC | | 13010514 | 299 Champ Chicken Sausage 1 Ka FR | 1 BOX | 10 PAC | | 13030502 | 298 Champ Chicken Ball 500 GR Fr | 1 BOX | 10 PAC | -| | 56 JXR | WH 01 / 01 | WH 01 / 01 | -| HEAD OFFICE ANCOL ! JL. ANCOL BARAT VIII NO. 1 JAKARTA UTARA IDN | HEAD OFFICE ANCOL ! JL. ANCOL BARAT VIII NO. 1 JAKARTA UTARA IDN | HEAD OFFICE ANCOL ! JL. ANCOL BARAT VIII NO. 1 JAKARTA UTARA IDN | | -| Bag. Pengeluaran Barang Bagian Peniualan | Bag. Pengeluaran Barang Bagian Peniualan | Bag. Pengeluaran Barang Bagian Peniualan | | #### ✅ Stage 4 — Layer 3: Final (`SKU triple-check + store resolution`) +*SKU validated against master list (score ≥ 0.6 threshold). Items with noise SKU codes are filtered out. Store resolved from DB.* + **Final metadata:** - **noDO**: `1659990583` @@ -835,8 +915,8 @@ Lembar3 : Customer - **tanggal**: `30 June 2026` - **vendorInfo**: `PT.PRIMAFOOD INTERNATIONAL` - **customerInfo**: `PT.PRIMAFOOD INTERNATIONAL` -- **alamat**: *empty* -- **orderUntuk**: *empty* +- **alamat**: `JL. ANCOL BARAT VIII/1 KEL. ANCOL, KEC. PADEMANGAN JAKARTA UTARA, DKI JAKARTA` +- **orderUntuk**: `PX HEAD OFFICE ANCOL` - **platTruk**: *empty* **Final items after SKU validation (8 row(s)):** @@ -854,6 +934,8 @@ Lembar3 : Customer #### 🗃️ Stage 5 — Submitted Items (ready-to-use JSON) +*These are the items actually returned to the caller and saved to the database.* + | kodeBarangOriginal | kodeBarang | namaBarang | banyak | jumlah | | --- | --- | --- | --- | --- | | 12010509 | 12010509 | CHAMP CRUNCHY NUGGET 450 GR/PAC | 1 BOX | 10 PAC | @@ -878,6 +960,8 @@ Lembar3 : Customer #### 📄 Stage 1 — Raw OCR Markdown +*This is the raw text extracted by PaddleOCR layout parser before any post-processing.* + ```markdown PT. CHAROEN POKPHAND INDONESIA TBK @@ -930,6 +1014,8 @@ Jika D.O. ini telah ditanau #### 🔍 Stage 2 — Layer 1: Regex Extraction (`parseDOMetadata`) +*Regex patterns are applied to raw markdown to extract header fields and item rows.* + **Header fields (raw regex output):** - **noDO**: `1659990583` @@ -956,6 +1042,8 @@ BANTEN` #### 🧹 Stage 3 — Layer 2: Sanitized (`sanitizeParsedMetadata`) +*Strict format enforcement: corrects date formats, trims whitespace, enforces field constraints.* + **Header fields (after sanitization):** - **noDO**: `1659990583` @@ -982,6 +1070,8 @@ BANTEN` #### ✅ Stage 4 — Layer 3: Final (`SKU triple-check + store resolution`) +*SKU validated against master list (score ≥ 0.6 threshold). Items with noise SKU codes are filtered out. Store resolved from DB.* + **Final metadata:** - **noDO**: `1659990583` @@ -992,8 +1082,8 @@ BANTEN` KAWASAN INDUSTRI MODERN. BANTEN` - **customerInfo**: `PT.PRIMAFOOD INTERNATIONAL` -- **alamat**: *empty* -- **orderUntuk**: *empty* +- **alamat**: `JL. ANCOL BARAT VIII/1 KEL. ANCOL, KEC. PADEMANGAN JAKARTA UTARA, DKI JAKARTA` +- **orderUntuk**: `PX HEAD OFFICE ANCOL` - **platTruk**: `B 9256 JXR` **Final items after SKU validation (1 row(s)):** @@ -1004,6 +1094,8 @@ BANTEN` #### 🗃️ Stage 5 — Submitted Items (ready-to-use JSON) +*These are the items actually returned to the caller and saved to the database.* + | kodeBarangOriginal | kodeBarang | namaBarang | banyak | jumlah | | --- | --- | --- | --- | --- | | 15040101 | 15040101 | FIESTA BATTER COATED 500 GR | 1 BOX | 12 PAC | @@ -1021,6 +1113,8 @@ BANTEN` #### 📄 Stage 1 — Raw OCR Markdown +*This is the raw text extracted by PaddleOCR layout parser before any post-processing.* + ```markdown ☐ ☑ ☐ ☑ @@ -1077,6 +1171,8 @@ in #### 🔍 Stage 2 — Layer 1: Regex Extraction (`parseDOMetadata`) +*Regex patterns are applied to raw markdown to extract header fields and item rows.* + **Header fields (raw regex output):** - **noDO**: `1057745004` @@ -1097,6 +1193,8 @@ in #### 🧹 Stage 3 — Layer 2: Sanitized (`sanitizeParsedMetadata`) +*Strict format enforcement: corrects date formats, trims whitespace, enforces field constraints.* + **Header fields (after sanitization):** - **noDO**: `1057745004` @@ -1117,6 +1215,8 @@ in #### ✅ Stage 4 — Layer 3: Final (`SKU triple-check + store resolution`) +*SKU validated against master list (score ≥ 0.6 threshold). Items with noise SKU codes are filtered out. Store resolved from DB.* + **Final metadata:** - **noDO**: `1057745004` @@ -1125,8 +1225,8 @@ in - **tanggal**: `25 May 2026` - **vendorInfo**: `PT.PRINHFOVO INTERNATIONAL` - **customerInfo**: `PT.PRIMAFOOD INTERNATIONAL` -- **alamat**: *empty* -- **orderUntuk**: *empty* +- **alamat**: `JL. ANCOL BARAT VIII/1 KEL. ANCOL, KEC. PADEMANGAN JAKARTA UTARA, DKI JAKARTA` +- **orderUntuk**: `PX HEAD OFFICE ANCOL` - **platTruk**: *empty* **Final items after SKU validation (1 row(s)):** @@ -1137,6 +1237,8 @@ in #### 🗃️ Stage 5 — Submitted Items (ready-to-use JSON) +*These are the items actually returned to the caller and saved to the database.* + | kodeBarangOriginal | kodeBarang | namaBarang | banyak | jumlah | | --- | --- | --- | --- | --- | | 13030502 | 13030502 | CHAMP CHICK MEATBALL 500 GR | 1 BOX | 10 PAC | @@ -1154,6 +1256,8 @@ in #### 📄 Stage 1 — Raw OCR Markdown +*This is the raw text extracted by PaddleOCR layout parser before any post-processing.* + ```markdown
Kode BarangNama Barang1.950.00Amount @@ -1165,6 +1269,8 @@ in #### 🔍 Stage 2 — Layer 1: Regex Extraction (`parseDOMetadata`) +*Regex patterns are applied to raw markdown to extract header fields and item rows.* + **Header fields (raw regex output):** - **noDO**: `Not Found` @@ -1187,6 +1293,8 @@ in #### 🧹 Stage 3 — Layer 2: Sanitized (`sanitizeParsedMetadata`) +*Strict format enforcement: corrects date formats, trims whitespace, enforces field constraints.* + **Header fields (after sanitization):** - **noDO**: `Not Found` @@ -1209,6 +1317,8 @@ in #### ✅ Stage 4 — Layer 3: Final (`SKU triple-check + store resolution`) +*SKU validated against master list (score ≥ 0.6 threshold). Items with noise SKU codes are filtered out. Store resolved from DB.* + **Final metadata:** - **noDO**: `Not Found` @@ -1217,8 +1327,8 @@ in - **tanggal**: `Not Found` - **vendorInfo**: `Not Found` - **customerInfo**: `PT.PRIMAFOOD INTERNATIONAL` -- **alamat**: *empty* -- **orderUntuk**: *empty* +- **alamat**: `JL. ANCOL BARAT VIII/1 KEL. ANCOL, KEC. PADEMANGAN JAKARTA UTARA, DKI JAKARTA` +- **orderUntuk**: `PX HEAD OFFICE ANCOL` - **platTruk**: `B 9257 JXR` **Final items after SKU validation (1 row(s)):** @@ -1229,6 +1339,8 @@ in #### 🗃️ Stage 5 — Submitted Items (ready-to-use JSON) +*These are the items actually returned to the caller and saved to the database.* + | kodeBarangOriginal | kodeBarang | namaBarang | banyak | jumlah | | --- | --- | --- | --- | --- | | 21002601 | 21002601 | Prima Nasi Spicy Chick Sambal Beprek COPY | 1 BOX | 6 PAC | @@ -1246,6 +1358,8 @@ in #### 📄 Stage 1 — Raw OCR Markdown +*This is the raw text extracted by PaddleOCR layout parser before any post-processing.* + ```markdown
70000006 PRIMA TELUR OMEGA (PC)(*) qty unitH/PCS1.950.001.755.000.00
Total qty :90006:28:57Tanggal : 30 June 2026\nNo. SO : 1691972285\nNo. DO : 1659990584\nNo. PO : 07/26/0000241303
INDONESIA TbKRN.
@@ -1272,6 +1386,8 @@ Jika D.O. ini telah ditanda tangan oleh Penerima barang tanpa sanggahan, segala #### 🔍 Stage 2 — Layer 1: Regex Extraction (`parseDOMetadata`) +*Regex patterns are applied to raw markdown to extract header fields and item rows.* + **Header fields (raw regex output):** - **noDO**: `1659990584` @@ -1294,6 +1410,8 @@ Jika D.O. ini telah ditanda tangan oleh Penerima barang tanpa sanggahan, segala #### 🧹 Stage 3 — Layer 2: Sanitized (`sanitizeParsedMetadata`) +*Strict format enforcement: corrects date formats, trims whitespace, enforces field constraints.* + **Header fields (after sanitization):** - **noDO**: `1659990584` @@ -1316,6 +1434,8 @@ Jika D.O. ini telah ditanda tangan oleh Penerima barang tanpa sanggahan, segala #### ✅ Stage 4 — Layer 3: Final (`SKU triple-check + store resolution`) +*SKU validated against master list (score ≥ 0.6 threshold). Items with noise SKU codes are filtered out. Store resolved from DB.* + **Final metadata:** - **noDO**: `1659990584` @@ -1324,8 +1444,8 @@ Jika D.O. ini telah ditanda tangan oleh Penerima barang tanpa sanggahan, segala - **tanggal**: `30 June 2026` - **vendorInfo**: `PT.PRIMAFOOD INTERNATIONAL` - **customerInfo**: `PT.PRIMAFOOD INTERNATIONAL` -- **alamat**: *empty* -- **orderUntuk**: *empty* +- **alamat**: `JL. ANCOL BARAT VIII/1 KEL. ANCOL, KEC. PADEMANGAN, JAKARTA UTARA, DKI JAKARTA (KANTIN CPI)` +- **orderUntuk**: `PRIMA XPRESS - TOWN HALL ANCOL` - **platTruk**: *empty* **Final items after SKU validation (1 row(s)):** @@ -1336,6 +1456,8 @@ Jika D.O. ini telah ditanda tangan oleh Penerima barang tanpa sanggahan, segala #### 🗃️ Stage 5 — Submitted Items (ready-to-use JSON) +*These are the items actually returned to the caller and saved to the database.* + | kodeBarangOriginal | kodeBarang | namaBarang | banyak | jumlah | | --- | --- | --- | --- | --- | | 21010104 | 21010104 | NEW FIESTA BEEF RENDANG W RICE 320GR (PAC) | 1 BOX | 6 PAC | @@ -1353,6 +1475,8 @@ Jika D.O. ini telah ditanda tangan oleh Penerima barang tanpa sanggahan, segala #### 📄 Stage 1 — Raw OCR Markdown +*This is the raw text extracted by PaddleOCR layout parser before any post-processing.* + ```markdown IDONESIA IDK @@ -1389,6 +1513,8 @@ JL.ANCOL BARAT VIII/1.ANCOL.PADEMANGAN. #### 🔍 Stage 2 — Layer 1: Regex Extraction (`parseDOMetadata`) +*Regex patterns are applied to raw markdown to extract header fields and item rows.* + **Header fields (raw regex output):** - **noDO**: `2272290022` @@ -1411,6 +1537,8 @@ JL.ANCOL BARAT VIII/1.ANCOL.PADEMANGAN. #### 🧹 Stage 3 — Layer 2: Sanitized (`sanitizeParsedMetadata`) +*Strict format enforcement: corrects date formats, trims whitespace, enforces field constraints.* + **Header fields (after sanitization):** - **noDO**: `2272290022` @@ -1433,6 +1561,8 @@ JL.ANCOL BARAT VIII/1.ANCOL.PADEMANGAN. #### ✅ Stage 4 — Layer 3: Final (`SKU triple-check + store resolution`) +*SKU validated against master list (score ≥ 0.6 threshold). Items with noise SKU codes are filtered out. Store resolved from DB.* + **Final metadata:** - **noDO**: `2272290022` @@ -1441,8 +1571,8 @@ JL.ANCOL BARAT VIII/1.ANCOL.PADEMANGAN. - **tanggal**: `30 June 2026` - **vendorInfo**: `PT.PRIMAFOOD INTERNATIONAL` - **customerInfo**: `PT.PRIMAFOOD INTERNATIONAL` -- **alamat**: *empty* -- **orderUntuk**: *empty* +- **alamat**: `JL. ANCOL BARAT VIII/1 KEL. ANCOL, KEC. PADEMANGAN JAKARTA UTARA, DKI JAKARTA` +- **orderUntuk**: `PX HEAD OFFICE ANCOL` - **platTruk**: *empty* **Final items after SKU validation (1 row(s)):** @@ -1453,6 +1583,8 @@ JL.ANCOL BARAT VIII/1.ANCOL.PADEMANGAN. #### 🗃️ Stage 5 — Submitted Items (ready-to-use JSON) +*These are the items actually returned to the caller and saved to the database.* + | kodeBarangOriginal | kodeBarang | namaBarang | banyak | jumlah | | --- | --- | --- | --- | --- | | 11048006 | 11048006 | BEBEK PARTING-NEW(*) | 2 BOX | 30 PAC | @@ -1470,6 +1602,8 @@ JL.ANCOL BARAT VIII/1.ANCOL.PADEMANGAN. #### 📄 Stage 1 — Raw OCR Markdown +*This is the raw text extracted by PaddleOCR layout parser before any post-processing.* + ```markdown IDONESIA IDK @@ -1506,6 +1640,8 @@ JL.ANCOL BARAT VIII/1.ANCOL.PADEMANGAN. #### 🔍 Stage 2 — Layer 1: Regex Extraction (`parseDOMetadata`) +*Regex patterns are applied to raw markdown to extract header fields and item rows.* + **Header fields (raw regex output):** - **noDO**: `2272290022` @@ -1528,6 +1664,8 @@ JL.ANCOL BARAT VIII/1.ANCOL.PADEMANGAN. #### 🧹 Stage 3 — Layer 2: Sanitized (`sanitizeParsedMetadata`) +*Strict format enforcement: corrects date formats, trims whitespace, enforces field constraints.* + **Header fields (after sanitization):** - **noDO**: `2272290022` @@ -1550,6 +1688,8 @@ JL.ANCOL BARAT VIII/1.ANCOL.PADEMANGAN. #### ✅ Stage 4 — Layer 3: Final (`SKU triple-check + store resolution`) +*SKU validated against master list (score ≥ 0.6 threshold). Items with noise SKU codes are filtered out. Store resolved from DB.* + **Final metadata:** - **noDO**: `2272290022` @@ -1558,8 +1698,8 @@ JL.ANCOL BARAT VIII/1.ANCOL.PADEMANGAN. - **tanggal**: `30 June 2026` - **vendorInfo**: `PT.PRIMAFOOD INTERNATIONAL` - **customerInfo**: `PT.PRIMAFOOD INTERNATIONAL` -- **alamat**: *empty* -- **orderUntuk**: *empty* +- **alamat**: `JL. ANCOL BARAT VIII/1 KEL. ANCOL, KEC. PADEMANGAN JAKARTA UTARA, DKI JAKARTA` +- **orderUntuk**: `PX HEAD OFFICE ANCOL` - **platTruk**: *empty* **Final items after SKU validation (1 row(s)):** @@ -1570,6 +1710,8 @@ JL.ANCOL BARAT VIII/1.ANCOL.PADEMANGAN. #### 🗃️ Stage 5 — Submitted Items (ready-to-use JSON) +*These are the items actually returned to the caller and saved to the database.* + | kodeBarangOriginal | kodeBarang | namaBarang | banyak | jumlah | | --- | --- | --- | --- | --- | | 11048000 | 11048000 | PARTING 150 - 160 GR FRZ PACK | 2 BOX | 30 PAC | @@ -1587,11 +1729,13 @@ JL.ANCOL BARAT VIII/1.ANCOL.PADEMANGAN. #### 📄 Stage 1 — Raw OCR Markdown +*This is the raw text extracted by PaddleOCR layout parser before any post-processing.* + ```markdown ## Purchase Order -
Nomor P.O: PO/26/0000230199
: 22/06/2026
KAWASAKI INDUSTRI MODERN. BANTEN02:56:41Tanggal :
No. SO : 23 June 2026
No. DO : 1691960321
DELIVERY ORDERNo. PO : 1659980277
+
Nomor P.O: PO/26/0000230199
: 22/06/2026
KAWASAKI INDUSTRI MODERN.02:56:41Tanggal :
BANTENNo. SO :23 June 2026
No. DO :1691960321
No. PO :1659980277
DELIVERY ORDERPO/26/0000230828
Kepala Gudang @@ -1614,6 +1758,8 @@ JL.ANCOL BARAT VIII/1.ANCOL.PADEMANGAN. #### 🔍 Stage 2 — Layer 1: Regex Extraction (`parseDOMetadata`) +*Regex patterns are applied to raw markdown to extract header fields and item rows.* + **Header fields (raw regex output):** - **noDO**: `1659980277` @@ -1643,6 +1789,8 @@ JL.ANCOL BARAT VIII/1.ANCOL.PADEMANGAN. #### 🧹 Stage 3 — Layer 2: Sanitized (`sanitizeParsedMetadata`) +*Strict format enforcement: corrects date formats, trims whitespace, enforces field constraints.* + **Header fields (after sanitization):** - **noDO**: `1659980277` @@ -1672,6 +1820,8 @@ JL.ANCOL BARAT VIII/1.ANCOL.PADEMANGAN. #### ✅ Stage 4 — Layer 3: Final (`SKU triple-check + store resolution`) +*SKU validated against master list (score ≥ 0.6 threshold). Items with noise SKU codes are filtered out. Store resolved from DB.* + **Final metadata:** - **noDO**: `1659980277` @@ -1680,8 +1830,8 @@ JL.ANCOL BARAT VIII/1.ANCOL.PADEMANGAN. - **tanggal**: `23 June 2026` - **vendorInfo**: `PT.PRIMAFOOD INTERNATIONAL` - **customerInfo**: `PT.PRIMAFOOD INTERNATIONAL` -- **alamat**: *empty* -- **orderUntuk**: *empty* +- **alamat**: `JL. ANCOL BARAT VIII/1 KEL. ANCOL, KEC. PADEMANGAN JAKARTA UTARA, DKI JAKARTA` +- **orderUntuk**: `PX HEAD OFFICE ANCOL` - **platTruk**: `B 9427 UXT` **Final items after SKU validation (5 row(s)):** @@ -1696,6 +1846,8 @@ JL.ANCOL BARAT VIII/1.ANCOL.PADEMANGAN. #### 🗃️ Stage 5 — Submitted Items (ready-to-use JSON) +*These are the items actually returned to the caller and saved to the database.* + | kodeBarangOriginal | kodeBarang | namaBarang | banyak | jumlah | | --- | --- | --- | --- | --- | | 11310014 | 11310014 | AYAM SIZE 2 FROZEN (0.8-0.9)KG(*) | 2 KRG | 40 PC | @@ -1717,6 +1869,8 @@ JL.ANCOL BARAT VIII/1.ANCOL.PADEMANGAN. #### 📄 Stage 1 — Raw OCR Markdown +*This is the raw text extracted by PaddleOCR layout parser before any post-processing.* + ```markdown - @@ -1726,6 +1880,8 @@ JL.ANCOL BARAT VIII/1.ANCOL.PADEMANGAN. #### 🔍 Stage 2 — Layer 1: Regex Extraction (`parseDOMetadata`) +*Regex patterns are applied to raw markdown to extract header fields and item rows.* + **Header fields (raw regex output):** - **noDO**: `Not Found` @@ -1752,6 +1908,8 @@ JL.ANCOL BARAT VIII/1.ANCOL.PADEMANGAN. #### 🧹 Stage 3 — Layer 2: Sanitized (`sanitizeParsedMetadata`) +*Strict format enforcement: corrects date formats, trims whitespace, enforces field constraints.* + **Header fields (after sanitization):** - **noDO**: `Not Found` @@ -1778,6 +1936,8 @@ JL.ANCOL BARAT VIII/1.ANCOL.PADEMANGAN. #### ✅ Stage 4 — Layer 3: Final (`SKU triple-check + store resolution`) +*SKU validated against master list (score ≥ 0.6 threshold). Items with noise SKU codes are filtered out. Store resolved from DB.* + **Final metadata:** - **noDO**: `Not Found` @@ -1803,6 +1963,8 @@ JL.ANCOL BARAT VIII/1.ANCOL.PADEMANGAN. #### 🗃️ Stage 5 — Submitted Items (ready-to-use JSON) +*These are the items actually returned to the caller and saved to the database.* + | kodeBarangOriginal | kodeBarang | namaBarang | banyak | jumlah | | --- | --- | --- | --- | --- | | 11140062 | 11140062 | AMPELA 1 KG FROZEN (20 PAC/KARUNG)(*) | 1 KRG | 20 KG | @@ -1825,6 +1987,8 @@ JL.ANCOL BARAT VIII/1.ANCOL.PADEMANGAN. #### 📄 Stage 1 — Raw OCR Markdown +*This is the raw text extracted by PaddleOCR layout parser before any post-processing.* + ```markdown PT. CHAROEN ROKPHAND INDONESIA TBK @@ -1875,6 +2039,8 @@ Jika D.O. ini telah ditanda tangan oleh Penerima barang tanpa sanggahan, segala #### 🔍 Stage 2 — Layer 1: Regex Extraction (`parseDOMetadata`) +*Regex patterns are applied to raw markdown to extract header fields and item rows.* + **Header fields (raw regex output):** - **noDO**: `1659905109` @@ -1899,6 +2065,8 @@ BANTEN` #### 🧹 Stage 3 — Layer 2: Sanitized (`sanitizeParsedMetadata`) +*Strict format enforcement: corrects date formats, trims whitespace, enforces field constraints.* + **Header fields (after sanitization):** - **noDO**: `1659905109` @@ -1923,6 +2091,8 @@ BANTEN` #### ✅ Stage 4 — Layer 3: Final (`SKU triple-check + store resolution`) +*SKU validated against master list (score ≥ 0.6 threshold). Items with noise SKU codes are filtered out. Store resolved from DB.* + **Final metadata:** - **noDO**: `1659905109` @@ -1933,8 +2103,8 @@ BANTEN` KAWASAN INDUSTRI MODERN, BANTEN` - **customerInfo**: `PT.PRIMAFOOD INTERNATIONAL` -- **alamat**: *empty* -- **orderUntuk**: *empty* +- **alamat**: `JL. ANCOL BARAT VIII/1 KEL. ANCOL, KEC. PADEMANGAN JAKARTA UTARA, DKI JAKARTA` +- **orderUntuk**: `PX HEAD OFFICE ANCOL` - **platTruk**: `B 9948 VCC` **Final items after SKU validation (1 row(s)):** @@ -1945,6 +2115,8 @@ BANTEN` #### 🗃️ Stage 5 — Submitted Items (ready-to-use JSON) +*These are the items actually returned to the caller and saved to the database.* + | kodeBarangOriginal | kodeBarang | namaBarang | banyak | jumlah | | --- | --- | --- | --- | --- | | 17210109 | 17210109 | FIESTA RTS B/BULGOGI 300GR/PAC | 1 BOX | 8 PAC | @@ -1962,6 +2134,8 @@ BANTEN` #### 📄 Stage 1 — Raw OCR Markdown +*This is the raw text extracted by PaddleOCR layout parser before any post-processing.* + ```markdown PT. CHAROEN POKPHAND INDONESIA TBK @@ -2007,6 +2181,8 @@ Jika D.O. ini telah ditanda tangan oleh Penerima barang tanpa sanggahan, segala #### 🔍 Stage 2 — Layer 1: Regex Extraction (`parseDOMetadata`) +*Regex patterns are applied to raw markdown to extract header fields and item rows.* + **Header fields (raw regex output):** - **noDO**: `1659897809` @@ -2033,6 +2209,8 @@ BANTEN` #### 🧹 Stage 3 — Layer 2: Sanitized (`sanitizeParsedMetadata`) +*Strict format enforcement: corrects date formats, trims whitespace, enforces field constraints.* + **Header fields (after sanitization):** - **noDO**: `1659897809` @@ -2059,6 +2237,8 @@ BANTEN` #### ✅ Stage 4 — Layer 3: Final (`SKU triple-check + store resolution`) +*SKU validated against master list (score ≥ 0.6 threshold). Items with noise SKU codes are filtered out. Store resolved from DB.* + **Final metadata:** - **noDO**: `1659897809` @@ -2069,8 +2249,8 @@ BANTEN` KAWASAN INDUSTRI MODERN, BANTEN` - **customerInfo**: `PT.PRIMAFOOD INTERNATIONAL` -- **alamat**: *empty* -- **orderUntuk**: *empty* +- **alamat**: `JL. ANCOL BARAT VIII/1 KEL. ANCOL, KEC. PADEMANGAN JAKARTA UTARA, DKI JAKARTA` +- **orderUntuk**: `PX HEAD OFFICE ANCOL` - **platTruk**: `B 9599 CXS` **Final items after SKU validation (2 row(s)):** @@ -2082,6 +2262,8 @@ BANTEN` #### 🗃️ Stage 5 — Submitted Items (ready-to-use JSON) +*These are the items actually returned to the caller and saved to the database.* + | kodeBarangOriginal | kodeBarang | namaBarang | banyak | jumlah | | --- | --- | --- | --- | --- | | 11110074 | 11110074 | CEKER 1 KG FROZEN (20 PAC/KARUNG)(*) | 1 KRG | 20 KG | @@ -2100,6 +2282,8 @@ BANTEN` #### 📄 Stage 1 — Raw OCR Markdown +*This is the raw text extracted by PaddleOCR layout parser before any post-processing.* + ```markdown PI KAWASAN INDUSTRI MODERN, INDONESIA TBK @@ -2142,6 +2326,8 @@ Jika D.O. ini telah ditanda tangan oleh Penerima barang tanpa sanggahan, segala #### 🔍 Stage 2 — Layer 1: Regex Extraction (`parseDOMetadata`) +*Regex patterns are applied to raw markdown to extract header fields and item rows.* + **Header fields (raw regex output):** - **noDO**: `1659897396` @@ -2165,6 +2351,8 @@ Jika D.O. ini telah ditanda tangan oleh Penerima barang tanpa sanggahan, segala #### 🧹 Stage 3 — Layer 2: Sanitized (`sanitizeParsedMetadata`) +*Strict format enforcement: corrects date formats, trims whitespace, enforces field constraints.* + **Header fields (after sanitization):** - **noDO**: `1659897396` @@ -2188,6 +2376,8 @@ Jika D.O. ini telah ditanda tangan oleh Penerima barang tanpa sanggahan, segala #### ✅ Stage 4 — Layer 3: Final (`SKU triple-check + store resolution`) +*SKU validated against master list (score ≥ 0.6 threshold). Items with noise SKU codes are filtered out. Store resolved from DB.* + **Final metadata:** - **noDO**: `1659897396` @@ -2196,8 +2386,8 @@ Jika D.O. ini telah ditanda tangan oleh Penerima barang tanpa sanggahan, segala - **tanggal**: `Not Found` - **vendorInfo**: `PT.PRIMAFOOD INTERNATIONAL` - **customerInfo**: `PT.PRIMAFOOD INTERNATIONAL` -- **alamat**: *empty* -- **orderUntuk**: *empty* +- **alamat**: `JL. ANCOL BARAT VIII/1 KEL. ANCOL, KEC. PADEMANGAN JAKARTA UTARA, DKI JAKARTA` +- **orderUntuk**: `PX HEAD OFFICE ANCOL` - **platTruk**: `B 9254 SCG` **Final items after SKU validation (2 row(s)):** @@ -2209,6 +2399,8 @@ Jika D.O. ini telah ditanda tangan oleh Penerima barang tanpa sanggahan, segala #### 🗃️ Stage 5 — Submitted Items (ready-to-use JSON) +*These are the items actually returned to the caller and saved to the database.* + | kodeBarangOriginal | kodeBarang | namaBarang | banyak | jumlah | | --- | --- | --- | --- | --- | | 11310024 | 11310024 | AYAM SIZE A FROZEN (0.9-1)KG/PC(*) | 2 KRG | 40 PC | @@ -2227,6 +2419,8 @@ Jika D.O. ini telah ditanda tangan oleh Penerima barang tanpa sanggahan, segala #### 📄 Stage 1 — Raw OCR Markdown +*This is the raw text extracted by PaddleOCR layout parser before any post-processing.* + ```markdown
Image
@@ -2276,6 +2470,8 @@ Jika D.O. ini telah ditanda tangan oleh Penerima barang tanpa senggahan, segala #### 🔍 Stage 2 — Layer 1: Regex Extraction (`parseDOMetadata`) +*Regex patterns are applied to raw markdown to extract header fields and item rows.* + **Header fields (raw regex output):** - **noDO**: `1659892421` @@ -2303,6 +2499,8 @@ BANTEN` #### 🧹 Stage 3 — Layer 2: Sanitized (`sanitizeParsedMetadata`) +*Strict format enforcement: corrects date formats, trims whitespace, enforces field constraints.* + **Header fields (after sanitization):** - **noDO**: `1659892421` @@ -2330,6 +2528,8 @@ BANTEN` #### ✅ Stage 4 — Layer 3: Final (`SKU triple-check + store resolution`) +*SKU validated against master list (score ≥ 0.6 threshold). Items with noise SKU codes are filtered out. Store resolved from DB.* + **Final metadata:** - **noDO**: `1659892421` @@ -2340,8 +2540,8 @@ BANTEN` KAWASAN INDUSTRI MOOERN, BANTEN` - **customerInfo**: `PT.PRIMAFOOD INTERNATIONAL` -- **alamat**: *empty* -- **orderUntuk**: *empty* +- **alamat**: `JL. ANCOL BARAT VIII/1 KEL. ANCOL, KEC. PADEMANGAN JAKARTA UTARA, DKI JAKARTA` +- **orderUntuk**: `PX HEAD OFFICE ANCOL` - **platTruk**: `B 9053 VCF` **Final items after SKU validation (3 row(s)):** @@ -2354,6 +2554,8 @@ BANTEN` #### 🗃️ Stage 5 — Submitted Items (ready-to-use JSON) +*These are the items actually returned to the caller and saved to the database.* + | kodeBarangOriginal | kodeBarang | namaBarang | banyak | jumlah | | --- | --- | --- | --- | --- | | 11310014 | 11310014 | AYAM SIZE 2 FROZEN (0.8-0.9)KG(*) | 3 KRG | 60 PC | @@ -2373,6 +2575,8 @@ BANTEN` #### 📄 Stage 1 — Raw OCR Markdown +*This is the raw text extracted by PaddleOCR layout parser before any post-processing.* + ```markdown PT. CHAROEN POKPHAND INDONESIA @@ -2420,6 +2624,8 @@ Jika D.O. ini telah ditanda tangan oleh Penerima barang tanpa sanggahan, segala #### 🔍 Stage 2 — Layer 1: Regex Extraction (`parseDOMetadata`) +*Regex patterns are applied to raw markdown to extract header fields and item rows.* + **Header fields (raw regex output):** - **noDO**: `1659886692` @@ -2450,6 +2656,8 @@ BANTEN` #### 🧹 Stage 3 — Layer 2: Sanitized (`sanitizeParsedMetadata`) +*Strict format enforcement: corrects date formats, trims whitespace, enforces field constraints.* + **Header fields (after sanitization):** - **noDO**: `1659886692` @@ -2480,6 +2688,8 @@ BANTEN` #### ✅ Stage 4 — Layer 3: Final (`SKU triple-check + store resolution`) +*SKU validated against master list (score ≥ 0.6 threshold). Items with noise SKU codes are filtered out. Store resolved from DB.* + **Final metadata:** - **noDO**: `1659886692` @@ -2490,8 +2700,8 @@ BANTEN` KAWASAN INDUSTRI MODERN, BANTEN` - **customerInfo**: `PT.PRIMAFOOD INTERNATIONAL` -- **alamat**: *empty* -- **orderUntuk**: *empty* +- **alamat**: `JL. ANCOL BARAT VIII/1 KEL. ANCOL, KEC. PADEMANGAN JAKARTA UTARA, DKI JAKARTA` +- **orderUntuk**: `PX HEAD OFFICE ANCOL` - **platTruk**: `B 9260 BXT` **Final items after SKU validation (8 row(s)):** @@ -2509,6 +2719,8 @@ BANTEN` #### 🗃️ Stage 5 — Submitted Items (ready-to-use JSON) +*These are the items actually returned to the caller and saved to the database.* + | kodeBarangOriginal | kodeBarang | namaBarang | banyak | jumlah | | --- | --- | --- | --- | --- | | 12010112 | 12010112 | FIESTA CHICKEN NUGGET 400 GR/PAC | 1 BOX | 12 PAC | @@ -2533,6 +2745,8 @@ BANTEN` #### 📄 Stage 1 — Raw OCR Markdown +*This is the raw text extracted by PaddleOCR layout parser before any post-processing.* + ```markdown PT. CHAROEN POKPHAND INDONESIA TBK 6 @@ -2581,6 +2795,8 @@ Dipindai dengan #### 🔍 Stage 2 — Layer 1: Regex Extraction (`parseDOMetadata`) +*Regex patterns are applied to raw markdown to extract header fields and item rows.* + **Header fields (raw regex output):** - **noDO**: `1659895333` @@ -2609,6 +2825,8 @@ BANTEN` #### 🧹 Stage 3 — Layer 2: Sanitized (`sanitizeParsedMetadata`) +*Strict format enforcement: corrects date formats, trims whitespace, enforces field constraints.* + **Header fields (after sanitization):** - **noDO**: `1659895333` @@ -2637,6 +2855,8 @@ BANTEN` #### ✅ Stage 4 — Layer 3: Final (`SKU triple-check + store resolution`) +*SKU validated against master list (score ≥ 0.6 threshold). Items with noise SKU codes are filtered out. Store resolved from DB.* + **Final metadata:** - **noDO**: `1659895333` @@ -2647,8 +2867,8 @@ BANTEN` KAWASAN INDUSTRI MODERN, BANTEN` - **customerInfo**: `PT.PRIMAFOOD INTERNATIONAL` -- **alamat**: *empty* -- **orderUntuk**: *empty* +- **alamat**: `JL. ANCOL BARAT VIII/1 KEL. ANCOL, KEC. PADEMANGAN JAKARTA UTARA, DKI JAKARTA` +- **orderUntuk**: `PX HEAD OFFICE ANCOL` - **platTruk**: `B 9365 AI` **Final items after SKU validation (4 row(s)):** @@ -2662,6 +2882,8 @@ BANTEN` #### 🗃️ Stage 5 — Submitted Items (ready-to-use JSON) +*These are the items actually returned to the caller and saved to the database.* + | kodeBarangOriginal | kodeBarang | namaBarang | banyak | jumlah | | --- | --- | --- | --- | --- | | 11140062 | 11140062 | AMPELA 1 KG FROZEN (20 PAC/KARUNG)(*) | 20 KRG | 20 KG | @@ -2682,6 +2904,8 @@ BANTEN` #### 📄 Stage 1 — Raw OCR Markdown +*This is the raw text extracted by PaddleOCR layout parser before any post-processing.* + ```markdown PT. CHAROEN POKPHAND INDONESIA TBK KAWASAN INDUSTRI MODERN. BANTEN @@ -2715,6 +2939,8 @@ Jika D.O. ini telah ditanda tangan oleh Penerima barang tanpa sanggahan, segala #### 🔍 Stage 2 — Layer 1: Regex Extraction (`parseDOMetadata`) +*Regex patterns are applied to raw markdown to extract header fields and item rows.* + **Header fields (raw regex output):** - **noDO**: `1659896184` @@ -2745,6 +2971,8 @@ Jika D.O. ini telah ditanda tangan oleh Penerima barang tanpa sanggahan, segala #### 🧹 Stage 3 — Layer 2: Sanitized (`sanitizeParsedMetadata`) +*Strict format enforcement: corrects date formats, trims whitespace, enforces field constraints.* + **Header fields (after sanitization):** - **noDO**: `1659896184` @@ -2775,6 +3003,8 @@ Jika D.O. ini telah ditanda tangan oleh Penerima barang tanpa sanggahan, segala #### ✅ Stage 4 — Layer 3: Final (`SKU triple-check + store resolution`) +*SKU validated against master list (score ≥ 0.6 threshold). Items with noise SKU codes are filtered out. Store resolved from DB.* + **Final metadata:** - **noDO**: `1659896184` @@ -2783,8 +3013,8 @@ Jika D.O. ini telah ditanda tangan oleh Penerima barang tanpa sanggahan, segala - **tanggal**: `16 April 2026` - **vendorInfo**: `PT. CHAROEN POKPHAND INDONESIA TBK KAWASAN INDUSTRI MODERN. BANTEN` - **customerInfo**: `PT.PRIMAFOOD INTERNATIONAL` -- **alamat**: *empty* -- **orderUntuk**: *empty* +- **alamat**: `JL. ANCOL BARAT VIII/1 KEL. ANCOL, KEC. PADEMANGAN JAKARTA UTARA, DKI JAKARTA` +- **orderUntuk**: `PX HEAD OFFICE ANCOL` - **platTruk**: *empty* **Final items after SKU validation (8 row(s)):** @@ -2802,6 +3032,8 @@ Jika D.O. ini telah ditanda tangan oleh Penerima barang tanpa sanggahan, segala #### 🗃️ Stage 5 — Submitted Items (ready-to-use JSON) +*These are the items actually returned to the caller and saved to the database.* + | kodeBarangOriginal | kodeBarang | namaBarang | banyak | jumlah | | --- | --- | --- | --- | --- | | 12010111 | 12010111 | FIESTA CRISPY BUBBLE 400 GR/PAC | 1 BOX | 12 PAC | @@ -2826,6 +3058,8 @@ Jika D.O. ini telah ditanda tangan oleh Penerima barang tanpa sanggahan, segala #### 📄 Stage 1 — Raw OCR Markdown +*This is the raw text extracted by PaddleOCR layout parser before any post-processing.* + ```markdown PT. CHAROEN POKPHAND INDONESIA TBK KAWASAN INDUSTRI MODERN, BANTEN @@ -2868,6 +3102,8 @@ Jika D.O. ini telah ditanda tangan oleh Penerima barang tanpa sanggahan, segala #### 🔍 Stage 2 — Layer 1: Regex Extraction (`parseDOMetadata`) +*Regex patterns are applied to raw markdown to extract header fields and item rows.* + **Header fields (raw regex output):** - **noDO**: `1659927197` @@ -2892,6 +3128,8 @@ Jika D.O. ini telah ditanda tangan oleh Penerima barang tanpa sanggahan, segala #### 🧹 Stage 3 — Layer 2: Sanitized (`sanitizeParsedMetadata`) +*Strict format enforcement: corrects date formats, trims whitespace, enforces field constraints.* + **Header fields (after sanitization):** - **noDO**: `1659927197` @@ -2916,6 +3154,8 @@ Jika D.O. ini telah ditanda tangan oleh Penerima barang tanpa sanggahan, segala #### ✅ Stage 4 — Layer 3: Final (`SKU triple-check + store resolution`) +*SKU validated against master list (score ≥ 0.6 threshold). Items with noise SKU codes are filtered out. Store resolved from DB.* + **Final metadata:** - **noDO**: `1659927197` @@ -2924,8 +3164,8 @@ Jika D.O. ini telah ditanda tangan oleh Penerima barang tanpa sanggahan, segala - **tanggal**: `11 May 2026` - **vendorInfo**: `PT. CHAROEN POKPHAND INDONESIA TBK KAWASAN INDUSTRI MODERN, BANTEN` - **customerInfo**: `PT.PRIMAFOOD INTERNATIONAL` -- **alamat**: *empty* -- **orderUntuk**: *empty* +- **alamat**: `JL. ANCOL BARAT VIII/1 KEL. ANCOL, KEC. PADEMANGAN JAKARTA UTARA, DKI JAKARTA` +- **orderUntuk**: `PX HEAD OFFICE ANCOL` - **platTruk**: `B 9683 VCF` **Final items after SKU validation (3 row(s)):** @@ -2938,6 +3178,8 @@ Jika D.O. ini telah ditanda tangan oleh Penerima barang tanpa sanggahan, segala #### 🗃️ Stage 5 — Submitted Items (ready-to-use JSON) +*These are the items actually returned to the caller and saved to the database.* + | kodeBarangOriginal | kodeBarang | namaBarang | banyak | jumlah | | --- | --- | --- | --- | --- | | 12012501 | 12012501 | AKUMO CHICKEN NAGET 250 GR | 1 BOX | 20 PAC | @@ -2957,6 +3199,8 @@ Jika D.O. ini telah ditanda tangan oleh Penerima barang tanpa sanggahan, segala #### 📄 Stage 1 — Raw OCR Markdown +*This is the raw text extracted by PaddleOCR layout parser before any post-processing.* + ```markdown PT. CHAROEN POKPHAND INDONESIA @@ -3000,6 +3244,8 @@ Jika D.O. ini telah ditanda tangan oleh Penerima barang tanpa sanggahan, segala #### 🔍 Stage 2 — Layer 1: Regex Extraction (`parseDOMetadata`) +*Regex patterns are applied to raw markdown to extract header fields and item rows.* + **Header fields (raw regex output):** - **noDO**: `1659919748` @@ -3031,6 +3277,8 @@ KAWASAN INDUSTRI KODERN, BANTEN` #### 🧹 Stage 3 — Layer 2: Sanitized (`sanitizeParsedMetadata`) +*Strict format enforcement: corrects date formats, trims whitespace, enforces field constraints.* + **Header fields (after sanitization):** - **noDO**: `1659919748` @@ -3062,6 +3310,8 @@ KAWASAN INDUSTRI KODERN, BANTEN` #### ✅ Stage 4 — Layer 3: Final (`SKU triple-check + store resolution`) +*SKU validated against master list (score ≥ 0.6 threshold). Items with noise SKU codes are filtered out. Store resolved from DB.* + **Final metadata:** - **noDO**: `1659919748` @@ -3071,8 +3321,8 @@ KAWASAN INDUSTRI KODERN, BANTEN` - **vendorInfo**: `PT. CHAROEN POKPHAND INDONESIA KAWASAN INDUSTRI KODERN, BANTEN` - **customerInfo**: `PT.PRIMAFOOD INTERNATIONAL` -- **alamat**: *empty* -- **orderUntuk**: *empty* +- **alamat**: `JL. ANCOL BARAT VIII/1 KEL. ANCOL, KEC. PADEMANGAN JAKARTA UTARA, DKI JAKARTA` +- **orderUntuk**: `PX HEAD OFFICE ANCOL` - **platTruk**: `B 9042 VCC` **Final items after SKU validation (5 row(s)):** @@ -3087,6 +3337,8 @@ KAWASAN INDUSTRI KODERN, BANTEN` #### 🗃️ Stage 5 — Submitted Items (ready-to-use JSON) +*These are the items actually returned to the caller and saved to the database.* + | kodeBarangOriginal | kodeBarang | namaBarang | banyak | jumlah | | --- | --- | --- | --- | --- | | 12010111 | 12010111 | FIESTA CRISPY BUBBLE 400 GR/PAC | 1 BOX | 12 PAC | @@ -3108,6 +3360,8 @@ KAWASAN INDUSTRI KODERN, BANTEN` #### 📄 Stage 1 — Raw OCR Markdown +*This is the raw text extracted by PaddleOCR layout parser before any post-processing.* + ```markdown PT. CHARQEN WOKPHAND INDONESIA TBK @@ -3155,6 +3409,8 @@ Jika D.O. ini telah ditanda tangan oleh Penerima barang tanpa sanggahan, segala #### 🔍 Stage 2 — Layer 1: Regex Extraction (`parseDOMetadata`) +*Regex patterns are applied to raw markdown to extract header fields and item rows.* + **Header fields (raw regex output):** - **noDO**: `1659920402` @@ -3183,6 +3439,8 @@ BANTEN` #### 🧹 Stage 3 — Layer 2: Sanitized (`sanitizeParsedMetadata`) +*Strict format enforcement: corrects date formats, trims whitespace, enforces field constraints.* + **Header fields (after sanitization):** - **noDO**: `1659920402` @@ -3211,6 +3469,8 @@ BANTEN` #### ✅ Stage 4 — Layer 3: Final (`SKU triple-check + store resolution`) +*SKU validated against master list (score ≥ 0.6 threshold). Items with noise SKU codes are filtered out. Store resolved from DB.* + **Final metadata:** - **noDO**: `1659920402` @@ -3221,8 +3481,8 @@ BANTEN` KAWASAN INDUSTRI MODERN, BANTEN` - **customerInfo**: `PT.PRIMAFOOD INTERNATIONAL` -- **alamat**: *empty* -- **orderUntuk**: *empty* +- **alamat**: `JL. ANCOL BARAT VIII/1 KEL. ANCOL, KEC. PADEMANGAN JAKARTA UTARA, DKI JAKARTA` +- **orderUntuk**: `PX HEAD OFFICE ANCOL` - **platTruk**: `B 9260 VCF` **Final items after SKU validation (4 row(s)):** @@ -3236,6 +3496,8 @@ BANTEN` #### 🗃️ Stage 5 — Submitted Items (ready-to-use JSON) +*These are the items actually returned to the caller and saved to the database.* + | kodeBarangOriginal | kodeBarang | namaBarang | banyak | jumlah | | --- | --- | --- | --- | --- | | 11310013 | 11310013 | AYAM SIZE1 FROZEN (0.75-0.8) KG(*) | 3 KRG | 90 PC | @@ -3256,6 +3518,8 @@ BANTEN` #### 📄 Stage 1 — Raw OCR Markdown +*This is the raw text extracted by PaddleOCR layout parser before any post-processing.* + ```markdown KAWASAN INDUSTRI MODERN. @@ -3279,7 +3543,7 @@ Order Untuk : PFM-KU Alamat : JL. ANCOL BARAT VIII/1, ANCOL, PADEMANGAN, JAKARTA UTARA, 14430 -JAKARTA UTADA +JAKARTA ITARA
Kode BarangNama BarangBanyakJumlah
11310014✓ Griller Size 2 ( 20 Ekor ) Frozen5 KRG100 PC
11310018✓ Griller (PR) Size 1 Friz1 KRG30 PC
11310024✓ Griller Size A Frozen (900-1000 G) PC5 KRG100 PC
11640053✓ Bone In Leg ASLI1 80X10 KG
11660050✓ Drumstick Frozen Pack1 80X10 KG
11710051✓ Bone In Breast Frozen Pack1 80X10 KG
11750050✓ fillet Mitra 10 Kg1 80X10 KG
Barang dikirim dalam keadaan baikJumlah234270
Image ENTRA Image Image WH 01 / 01 IL DANAU KELAPA DUA ( Bagian Penjualan
@@ -3293,6 +3557,8 @@ Dinindoi dengan #### 🔍 Stage 2 — Layer 1: Regex Extraction (`parseDOMetadata`) +*Regex patterns are applied to raw markdown to extract header fields and item rows.* + **Header fields (raw regex output):** - **noDO**: `1659921089` @@ -3320,6 +3586,8 @@ Dinindoi dengan #### 🧹 Stage 3 — Layer 2: Sanitized (`sanitizeParsedMetadata`) +*Strict format enforcement: corrects date formats, trims whitespace, enforces field constraints.* + **Header fields (after sanitization):** - **noDO**: `1659921089` @@ -3347,6 +3615,8 @@ Dinindoi dengan #### ✅ Stage 4 — Layer 3: Final (`SKU triple-check + store resolution`) +*SKU validated against master list (score ≥ 0.6 threshold). Items with noise SKU codes are filtered out. Store resolved from DB.* + **Final metadata:** - **noDO**: `1659921089` @@ -3355,8 +3625,8 @@ Dinindoi dengan - **tanggal**: `Not Found` - **vendorInfo**: `PT.PRIMAFOOD INTERNATIONAL` - **customerInfo**: `PT.PRIMAFOOD INTERNATIONAL` -- **alamat**: *empty* -- **orderUntuk**: *empty* +- **alamat**: `JL. ANCOL BARAT VIII/1 KEL. ANCOL, KEC. PADEMANGAN JAKARTA UTARA, DKI JAKARTA` +- **orderUntuk**: `PX HEAD OFFICE ANCOL` - **platTruk**: *empty* **Final items after SKU validation (7 row(s)):** @@ -3373,6 +3643,8 @@ Dinindoi dengan #### 🗃️ Stage 5 — Submitted Items (ready-to-use JSON) +*These are the items actually returned to the caller and saved to the database.* + | kodeBarangOriginal | kodeBarang | namaBarang | banyak | jumlah | | --- | --- | --- | --- | --- | | 11310014 | 11310014 | AYAM SIZE 2 FROZEN (0.8-0.9)KG(*) | 5 KRG | 100 PC | @@ -3396,6 +3668,8 @@ Dinindoi dengan #### 📄 Stage 1 — Raw OCR Markdown +*This is the raw text extracted by PaddleOCR layout parser before any post-processing.* + ```markdown DI CHARGEN IDKCHANO INDONESIA TBK KAMASIN INDUSTRI AODERN BANTEN @@ -3439,6 +3713,8 @@ Jika D.O. ini telah ditanda tangan oleh Penerima barang tanpa sanggahan, segala #### 🔍 Stage 2 — Layer 1: Regex Extraction (`parseDOMetadata`) +*Regex patterns are applied to raw markdown to extract header fields and item rows.* + **Header fields (raw regex output):** - **noDO**: `1659920441` @@ -3464,6 +3740,8 @@ Jika D.O. ini telah ditanda tangan oleh Penerima barang tanpa sanggahan, segala #### 🧹 Stage 3 — Layer 2: Sanitized (`sanitizeParsedMetadata`) +*Strict format enforcement: corrects date formats, trims whitespace, enforces field constraints.* + **Header fields (after sanitization):** - **noDO**: `1659920441` @@ -3489,6 +3767,8 @@ Jika D.O. ini telah ditanda tangan oleh Penerima barang tanpa sanggahan, segala #### ✅ Stage 4 — Layer 3: Final (`SKU triple-check + store resolution`) +*SKU validated against master list (score ≥ 0.6 threshold). Items with noise SKU codes are filtered out. Store resolved from DB.* + **Final metadata:** - **noDO**: `1659920441` @@ -3497,8 +3777,8 @@ Jika D.O. ini telah ditanda tangan oleh Penerima barang tanpa sanggahan, segala - **tanggal**: `Not Found` - **vendorInfo**: `PT.PRIMAFOOD INTERNATIONAL` - **customerInfo**: `PT.PRIMAFOOD INTERNATIONAL` -- **alamat**: *empty* -- **orderUntuk**: *empty* +- **alamat**: `PANORAMA BALI RESIDENCE B NO 16, KEL. PUTAT NUTUG, KEC. CISEENG, KAB. BOGOR 16120` +- **orderUntuk**: `PM PANORAMA BALI RESIDENCE BGR` - **platTruk**: `B 9417 VOC` **Final items after SKU validation (4 row(s)):** @@ -3512,6 +3792,8 @@ Jika D.O. ini telah ditanda tangan oleh Penerima barang tanpa sanggahan, segala #### 🗃️ Stage 5 — Submitted Items (ready-to-use JSON) +*These are the items actually returned to the caller and saved to the database.* + | kodeBarangOriginal | kodeBarang | namaBarang | banyak | jumlah | | --- | --- | --- | --- | --- | | 11140062 | 11140062 | AMPELA 1 KG FROZEN (20 PAC/KARUNG)(*) | 1 KRG | 20 KG | @@ -3532,6 +3814,8 @@ Jika D.O. ini telah ditanda tangan oleh Penerima barang tanpa sanggahan, segala #### 📄 Stage 1 — Raw OCR Markdown +*This is the raw text extracted by PaddleOCR layout parser before any post-processing.* + ```markdown PT. CHAROEN POKPHAND INDONESIA TBK KAWASAN INDUSTRI MODERN. BANTEN @@ -3568,6 +3852,8 @@ Jika D.O. ini telah ditanda tangan oleh Penerima barang tanpa sanggahan, segala #### 🔍 Stage 2 — Layer 1: Regex Extraction (`parseDOMetadata`) +*Regex patterns are applied to raw markdown to extract header fields and item rows.* + **Header fields (raw regex output):** - **noDO**: `1659922449` @@ -3598,6 +3884,8 @@ Jika D.O. ini telah ditanda tangan oleh Penerima barang tanpa sanggahan, segala #### 🧹 Stage 3 — Layer 2: Sanitized (`sanitizeParsedMetadata`) +*Strict format enforcement: corrects date formats, trims whitespace, enforces field constraints.* + **Header fields (after sanitization):** - **noDO**: `1659922449` @@ -3628,6 +3916,8 @@ Jika D.O. ini telah ditanda tangan oleh Penerima barang tanpa sanggahan, segala #### ✅ Stage 4 — Layer 3: Final (`SKU triple-check + store resolution`) +*SKU validated against master list (score ≥ 0.6 threshold). Items with noise SKU codes are filtered out. Store resolved from DB.* + **Final metadata:** - **noDO**: `1659922449` @@ -3636,8 +3926,8 @@ Jika D.O. ini telah ditanda tangan oleh Penerima barang tanpa sanggahan, segala - **tanggal**: `07 May 2026` - **vendorInfo**: `PT. CHAROEN POKPHAND INDONESIA TBK KAWASAN INDUSTRI MODERN. BANTEN` - **customerInfo**: `PT.PRIMAFOOD INTERNATIONAL` -- **alamat**: *empty* -- **orderUntuk**: *empty* +- **alamat**: `JL. ANCOL BARAT VIII/1 KEL. ANCOL, KEC. PADEMANGAN JAKARTA UTARA, DKI JAKARTA` +- **orderUntuk**: `PX HEAD OFFICE ANCOL` - **platTruk**: `B 9259 BCU` **Final items after SKU validation (8 row(s)):** @@ -3655,6 +3945,8 @@ Jika D.O. ini telah ditanda tangan oleh Penerima barang tanpa sanggahan, segala #### 🗃️ Stage 5 — Submitted Items (ready-to-use JSON) +*These are the items actually returned to the caller and saved to the database.* + | kodeBarangOriginal | kodeBarang | namaBarang | banyak | jumlah | | --- | --- | --- | --- | --- | | 11310013 | 11310013 | AYAM SIZE1 FROZEN (0.75-0.8) KG(*) | 1 KRG | 30 PC | @@ -3679,6 +3971,8 @@ Jika D.O. ini telah ditanda tangan oleh Penerima barang tanpa sanggahan, segala #### 📄 Stage 1 — Raw OCR Markdown +*This is the raw text extracted by PaddleOCR layout parser before any post-processing.* + ```markdown PT. CHAROEN POKPHAND INDONESIA TBK @@ -3726,6 +4020,8 @@ Jika D.O. ini telah ditanda tangan oleh Penerima barang tanpa sanggahan, segala #### 🔍 Stage 2 — Layer 1: Regex Extraction (`parseDOMetadata`) +*Regex patterns are applied to raw markdown to extract header fields and item rows.* + **Header fields (raw regex output):** - **noDO**: `1659881372` @@ -3753,6 +4049,8 @@ BANTEN` #### 🧹 Stage 3 — Layer 2: Sanitized (`sanitizeParsedMetadata`) +*Strict format enforcement: corrects date formats, trims whitespace, enforces field constraints.* + **Header fields (after sanitization):** - **noDO**: `1659881372` @@ -3780,6 +4078,8 @@ BANTEN` #### ✅ Stage 4 — Layer 3: Final (`SKU triple-check + store resolution`) +*SKU validated against master list (score ≥ 0.6 threshold). Items with noise SKU codes are filtered out. Store resolved from DB.* + **Final metadata:** - **noDO**: `1659881372` @@ -3790,8 +4090,8 @@ BANTEN` KAWASAN INDUSTRI MODERN, BANTEN` - **customerInfo**: `PT.PRIMAFOOD INTERNATIONAL` -- **alamat**: *empty* -- **orderUntuk**: *empty* +- **alamat**: `JL. ANCOL BARAT VIII/1 KEL. ANCOL, KEC. PADEMANGAN JAKARTA UTARA, DKI JAKARTA` +- **orderUntuk**: `PX HEAD OFFICE ANCOL` - **platTruk**: *empty* **Final items after SKU validation (4 row(s)):** @@ -3805,6 +4105,8 @@ BANTEN` #### 🗃️ Stage 5 — Submitted Items (ready-to-use JSON) +*These are the items actually returned to the caller and saved to the database.* + | kodeBarangOriginal | kodeBarang | namaBarang | banyak | jumlah | | --- | --- | --- | --- | --- | | 12010515 | 12010515 | CHAMP KOIN KOMBINASI 450 GR/PAC | 1 BOX | 12 PAC | @@ -3825,6 +4127,8 @@ BANTEN` #### 📄 Stage 1 — Raw OCR Markdown +*This is the raw text extracted by PaddleOCR layout parser before any post-processing.* + ```markdown PT. CHAROEN POKPHAND INDONESIA TBK KAWASAN INDUSTRI MODERN, BANTEN @@ -3866,6 +4170,8 @@ Jika D.O. ini telah ditanda tangan oleh Penerima barang tanpa sanggahan, segala #### 🔍 Stage 2 — Layer 1: Regex Extraction (`parseDOMetadata`) +*Regex patterns are applied to raw markdown to extract header fields and item rows.* + **Header fields (raw regex output):** - **noDO**: `1659876922` @@ -3892,6 +4198,8 @@ Jika D.O. ini telah ditanda tangan oleh Penerima barang tanpa sanggahan, segala #### 🧹 Stage 3 — Layer 2: Sanitized (`sanitizeParsedMetadata`) +*Strict format enforcement: corrects date formats, trims whitespace, enforces field constraints.* + **Header fields (after sanitization):** - **noDO**: `1659876922` @@ -3918,6 +4226,8 @@ Jika D.O. ini telah ditanda tangan oleh Penerima barang tanpa sanggahan, segala #### ✅ Stage 4 — Layer 3: Final (`SKU triple-check + store resolution`) +*SKU validated against master list (score ≥ 0.6 threshold). Items with noise SKU codes are filtered out. Store resolved from DB.* + **Final metadata:** - **noDO**: `1659876922` @@ -3926,8 +4236,8 @@ Jika D.O. ini telah ditanda tangan oleh Penerima barang tanpa sanggahan, segala - **tanggal**: `02 April 2026` - **vendorInfo**: `PT. CHAROEN POKPHAND INDONESIA TBK KAWASAN INDUSTRI MODERN, BANTEN` - **customerInfo**: `PT.PRIMAFOOD INTERNATIONAL` -- **alamat**: *empty* -- **orderUntuk**: *empty* +- **alamat**: `JL. ANCOL BARAT VIII/1 KEL. ANCOL, KEC. PADEMANGAN JAKARTA UTARA, DKI JAKARTA` +- **orderUntuk**: `PX HEAD OFFICE ANCOL` - **platTruk**: `B 9260 BXT` **Final items after SKU validation (3 row(s)):** @@ -3940,6 +4250,8 @@ Jika D.O. ini telah ditanda tangan oleh Penerima barang tanpa sanggahan, segala #### 🗃️ Stage 5 — Submitted Items (ready-to-use JSON) +*These are the items actually returned to the caller and saved to the database.* + | kodeBarangOriginal | kodeBarang | namaBarang | banyak | jumlah | | --- | --- | --- | --- | --- | | 11110074 | 11110074 | CEKER 1 KG FROZEN (20 PAC/KARUNG)(*) | 1 KRG | 20 KG | @@ -3959,6 +4271,8 @@ Jika D.O. ini telah ditanda tangan oleh Penerima barang tanpa sanggahan, segala #### 📄 Stage 1 — Raw OCR Markdown +*This is the raw text extracted by PaddleOCR layout parser before any post-processing.* + ```markdown PT. CHAROEN POKPHAND INDONESIA TBK @@ -4004,6 +4318,8 @@ Lembera: Customer Jika D.O. ini telah ditanda tangan oleh Penerima barang tanpa #### 🔍 Stage 2 — Layer 1: Regex Extraction (`parseDOMetadata`) +*Regex patterns are applied to raw markdown to extract header fields and item rows.* + **Header fields (raw regex output):** - **noDO**: `1659878594` @@ -4029,6 +4345,8 @@ BANTEN` #### 🧹 Stage 3 — Layer 2: Sanitized (`sanitizeParsedMetadata`) +*Strict format enforcement: corrects date formats, trims whitespace, enforces field constraints.* + **Header fields (after sanitization):** - **noDO**: `1659878594` @@ -4054,6 +4372,8 @@ BANTEN` #### ✅ Stage 4 — Layer 3: Final (`SKU triple-check + store resolution`) +*SKU validated against master list (score ≥ 0.6 threshold). Items with noise SKU codes are filtered out. Store resolved from DB.* + **Final metadata:** - **noDO**: `1659878594` @@ -4064,8 +4384,8 @@ BANTEN` KAWASAN INDUSTRI MODERN, BANTEN` - **customerInfo**: `PT.PRIMAFOOD INTERNATIONAL` -- **alamat**: *empty* -- **orderUntuk**: *empty* +- **alamat**: `JL. RAYA TENGAH RT. 004, RW. 009, KEL. TENGAH, KEC. KRAMAT JATI, JAKARTA TIMUR 13540` +- **orderUntuk**: `PM KAMPUNG TENGAH` - **platTruk**: `B 9308 BXT` **Final items after SKU validation (2 row(s)):** @@ -4077,6 +4397,8 @@ BANTEN` #### 🗃️ Stage 5 — Submitted Items (ready-to-use JSON) +*These are the items actually returned to the caller and saved to the database.* + | kodeBarangOriginal | kodeBarang | namaBarang | banyak | jumlah | | --- | --- | --- | --- | --- | | 17210106 | 17210106 | FIESTA RTS B/YAKINIKU 300GR/PAC | 1 BOX | BOX | @@ -4095,6 +4417,8 @@ BANTEN` #### 📄 Stage 1 — Raw OCR Markdown +*This is the raw text extracted by PaddleOCR layout parser before any post-processing.* + ```markdown PT. CHARGEN POKPIAND INDONESIA T KAWASAN, INDUSTRI MODERN, BANTEN @@ -4138,6 +4462,8 @@ Jika D.O. ini telah ditanda tangan oleh Penerima barang tanpa sanggahan, segala #### 🔍 Stage 2 — Layer 1: Regex Extraction (`parseDOMetadata`) +*Regex patterns are applied to raw markdown to extract header fields and item rows.* + **Header fields (raw regex output):** - **noDO**: `1659877509` @@ -4160,6 +4486,8 @@ Jika D.O. ini telah ditanda tangan oleh Penerima barang tanpa sanggahan, segala #### 🧹 Stage 3 — Layer 2: Sanitized (`sanitizeParsedMetadata`) +*Strict format enforcement: corrects date formats, trims whitespace, enforces field constraints.* + **Header fields (after sanitization):** - **noDO**: `1659877509` @@ -4182,6 +4510,8 @@ Jika D.O. ini telah ditanda tangan oleh Penerima barang tanpa sanggahan, segala #### ✅ Stage 4 — Layer 3: Final (`SKU triple-check + store resolution`) +*SKU validated against master list (score ≥ 0.6 threshold). Items with noise SKU codes are filtered out. Store resolved from DB.* + **Final metadata:** - **noDO**: `1659877509` @@ -4190,8 +4520,8 @@ Jika D.O. ini telah ditanda tangan oleh Penerima barang tanpa sanggahan, segala - **tanggal**: `02 April 2026` - **vendorInfo**: `PT. CHARGEN POKPIAND INDONESIA T KAWASAN, INDUSTRI MODERN, BANTEN` - **customerInfo**: `PT.PRIMAFOOD INTERNATIONAL` -- **alamat**: *empty* -- **orderUntuk**: *empty* +- **alamat**: `JL. ANCOL BARAT VIII/1 KEL. ANCOL, KEC. PADEMANGAN JAKARTA UTARA, DKI JAKARTA` +- **orderUntuk**: `PX HEAD OFFICE ANCOL` - **platTruk**: `B 9767 NCD` **Final items after SKU validation (2 row(s)):** @@ -4203,6 +4533,8 @@ Jika D.O. ini telah ditanda tangan oleh Penerima barang tanpa sanggahan, segala #### 🗃️ Stage 5 — Submitted Items (ready-to-use JSON) +*These are the items actually returned to the caller and saved to the database.* + | kodeBarangOriginal | kodeBarang | namaBarang | banyak | jumlah | | --- | --- | --- | --- | --- | | 11310013 | 11310013 | AYAM SIZE1 FROZEN (0.75-0.8) KG(*) | 4 KRG | 120 PC | @@ -4221,6 +4553,8 @@ Jika D.O. ini telah ditanda tangan oleh Penerima barang tanpa sanggahan, segala #### 📄 Stage 1 — Raw OCR Markdown +*This is the raw text extracted by PaddleOCR layout parser before any post-processing.* + ```markdown PT. CHAROEN POKPUAND INDONESIA T5K 03:28:00 @@ -4263,6 +4597,8 @@ Dipindai dengan #### 🔍 Stage 2 — Layer 1: Regex Extraction (`parseDOMetadata`) +*Regex patterns are applied to raw markdown to extract header fields and item rows.* + **Header fields (raw regex output):** - **noDO**: `1659898844` @@ -4291,6 +4627,8 @@ KAWASAN, INDUSTRI MODERN, BANTEN` #### 🧹 Stage 3 — Layer 2: Sanitized (`sanitizeParsedMetadata`) +*Strict format enforcement: corrects date formats, trims whitespace, enforces field constraints.* + **Header fields (after sanitization):** - **noDO**: `1659898844` @@ -4319,6 +4657,8 @@ KAWASAN, INDUSTRI MODERN, BANTEN` #### ✅ Stage 4 — Layer 3: Final (`SKU triple-check + store resolution`) +*SKU validated against master list (score ≥ 0.6 threshold). Items with noise SKU codes are filtered out. Store resolved from DB.* + **Final metadata:** - **noDO**: `1659898844` @@ -4328,8 +4668,8 @@ KAWASAN, INDUSTRI MODERN, BANTEN` - **vendorInfo**: `PT. CHAROEN POKPUAND INDONESIA T5K 03:28:00 KAWASAN, INDUSTRI MODERN, BANTEN` - **customerInfo**: `PT.PRIMAFOOD INTERNATIONAL` -- **alamat**: *empty* -- **orderUntuk**: *empty* +- **alamat**: `JL. ANCOL BARAT VIII/1 KEL. ANCOL, KEC. PADEMANGAN JAKARTA UTARA, DKI JAKARTA` +- **orderUntuk**: `PX HEAD OFFICE ANCOL` - **platTruk**: *empty* **Final items after SKU validation (5 row(s)):** @@ -4344,6 +4684,8 @@ KAWASAN, INDUSTRI MODERN, BANTEN` #### 🗃️ Stage 5 — Submitted Items (ready-to-use JSON) +*These are the items actually returned to the caller and saved to the database.* + | kodeBarangOriginal | kodeBarang | namaBarang | banyak | jumlah | | --- | --- | --- | --- | --- | | 11150064 | 11150064 | HATI 1 KG FROZEN (20 PAC/KARUNG)(*) | 1 KRG | 30 PC | @@ -4365,6 +4707,8 @@ KAWASAN, INDUSTRI MODERN, BANTEN` #### 📄 Stage 1 — Raw OCR Markdown +*This is the raw text extracted by PaddleOCR layout parser before any post-processing.* + ```markdown PT. CHAROEN POKPHAND INDONESIA TBK @@ -4420,6 +4764,8 @@ Osto dei donno #### 🔍 Stage 2 — Layer 1: Regex Extraction (`parseDOMetadata`) +*Regex patterns are applied to raw markdown to extract header fields and item rows.* + **Header fields (raw regex output):** - **noDO**: `1659880471` @@ -4449,6 +4795,8 @@ NTEN` #### 🧹 Stage 3 — Layer 2: Sanitized (`sanitizeParsedMetadata`) +*Strict format enforcement: corrects date formats, trims whitespace, enforces field constraints.* + **Header fields (after sanitization):** - **noDO**: `1659880471` @@ -4478,6 +4826,8 @@ NTEN` #### ✅ Stage 4 — Layer 3: Final (`SKU triple-check + store resolution`) +*SKU validated against master list (score ≥ 0.6 threshold). Items with noise SKU codes are filtered out. Store resolved from DB.* + **Final metadata:** - **noDO**: `1659880471` @@ -4488,8 +4838,8 @@ NTEN` KAWASAN INDUSTPI MODER NTEN` - **customerInfo**: `PT.PRIMAFOOD INTERNATIONAL` -- **alamat**: *empty* -- **orderUntuk**: *empty* +- **alamat**: `JL. ANCOL BARAT VIII/1 KEL. ANCOL, KEC. PADEMANGAN JAKARTA UTARA, DKI JAKARTA` +- **orderUntuk**: `PX HEAD OFFICE ANCOL` - **platTruk**: `B 9402 SCH` **Final items after SKU validation (4 row(s)):** @@ -4503,6 +4853,8 @@ NTEN` #### 🗃️ Stage 5 — Submitted Items (ready-to-use JSON) +*These are the items actually returned to the caller and saved to the database.* + | kodeBarangOriginal | kodeBarang | namaBarang | banyak | jumlah | | --- | --- | --- | --- | --- | | 11140062 | 11140062 | AMPELA 1 KG FROZEN (20 PAC/KARUNG)(*) | 20 KRG | 20 KG | @@ -4523,6 +4875,8 @@ NTEN` #### 📄 Stage 1 — Raw OCR Markdown +*This is the raw text extracted by PaddleOCR layout parser before any post-processing.* + ```markdown PT. CHAROEN POKPHAND INDONESIA TBK @@ -4583,6 +4937,8 @@ Jika D.O. ini telah ditanda tangan oleh Penerima barang tanpa sanggahan, segala #### 🔍 Stage 2 — Layer 1: Regex Extraction (`parseDOMetadata`) +*Regex patterns are applied to raw markdown to extract header fields and item rows.* + **Header fields (raw regex output):** - **noDO**: `1659889989` @@ -4607,6 +4963,8 @@ BANTEN #### 🧹 Stage 3 — Layer 2: Sanitized (`sanitizeParsedMetadata`) +*Strict format enforcement: corrects date formats, trims whitespace, enforces field constraints.* + **Header fields (after sanitization):** - **noDO**: `1659889989` @@ -4631,6 +4989,8 @@ BANTEN #### ✅ Stage 4 — Layer 3: Final (`SKU triple-check + store resolution`) +*SKU validated against master list (score ≥ 0.6 threshold). Items with noise SKU codes are filtered out. Store resolved from DB.* + **Final metadata:** - **noDO**: `1659889989` @@ -4642,8 +5002,8 @@ KAWASAN INDUSTRI MODERN, BANTEN 300000000000` - **customerInfo**: `PT.PRIMAFOOD INTERNATIONAL` -- **alamat**: *empty* -- **orderUntuk**: *empty* +- **alamat**: `JL. ANCOL BARAT VIII/1 KEL. ANCOL, KEC. PADEMANGAN JAKARTA UTARA, DKI JAKARTA` +- **orderUntuk**: `PX HEAD OFFICE ANCOL` - **platTruk**: *empty* **Final items after SKU validation (1 row(s)):** @@ -4654,6 +5014,8 @@ BANTEN #### 🗃️ Stage 5 — Submitted Items (ready-to-use JSON) +*These are the items actually returned to the caller and saved to the database.* + | kodeBarangOriginal | kodeBarang | namaBarang | banyak | jumlah | | --- | --- | --- | --- | --- | | 11310013 | 11310013 | AYAM SIZE1 FROZEN (0.75-0.8) KG(*) | 2 KRG | 60 PC | @@ -4671,6 +5033,8 @@ BANTEN #### 📄 Stage 1 — Raw OCR Markdown +*This is the raw text extracted by PaddleOCR layout parser before any post-processing.* + ```markdown PT., CHAROEN POKPHAND INDONESIA TDK @@ -4719,6 +5083,8 @@ Jika D.O. ini telah ditanda tangan oleh Penerima barang tanpa sanggahan, segala #### 🔍 Stage 2 — Layer 1: Regex Extraction (`parseDOMetadata`) +*Regex patterns are applied to raw markdown to extract header fields and item rows.* + **Header fields (raw regex output):** - **noDO**: `1659877015` @@ -4745,6 +5111,8 @@ BANTEN` #### 🧹 Stage 3 — Layer 2: Sanitized (`sanitizeParsedMetadata`) +*Strict format enforcement: corrects date formats, trims whitespace, enforces field constraints.* + **Header fields (after sanitization):** - **noDO**: `1659877015` @@ -4771,6 +5139,8 @@ BANTEN` #### ✅ Stage 4 — Layer 3: Final (`SKU triple-check + store resolution`) +*SKU validated against master list (score ≥ 0.6 threshold). Items with noise SKU codes are filtered out. Store resolved from DB.* + **Final metadata:** - **noDO**: `1659877015` @@ -4781,8 +5151,8 @@ BANTEN` KAWASAN INDUSTRI MODERN, BANTEN` - **customerInfo**: `PT.PRIMAFOOD INTERNATIONAL` -- **alamat**: *empty* -- **orderUntuk**: *empty* +- **alamat**: `JL. ANCOL BARAT VIII/1 KEL. ANCOL, KEC. PADEMANGAN JAKARTA UTARA, DKI JAKARTA` +- **orderUntuk**: `PX HEAD OFFICE ANCOL` - **platTruk**: `B 9726 UCT` **Final items after SKU validation (3 row(s)):** @@ -4795,6 +5165,8 @@ BANTEN` #### 🗃️ Stage 5 — Submitted Items (ready-to-use JSON) +*These are the items actually returned to the caller and saved to the database.* + | kodeBarangOriginal | kodeBarang | namaBarang | banyak | jumlah | | --- | --- | --- | --- | --- | | 11110074 | 11110074 | CEKER 1 KG FROZEN (20 PAC/KARUNG)(*) | 1 KRG | 20 KG | @@ -4814,6 +5186,8 @@ BANTEN` #### 📄 Stage 1 — Raw OCR Markdown +*This is the raw text extracted by PaddleOCR layout parser before any post-processing.* + ```markdown PT. CHAROEN POKPHAND INDONESIA TBK RAWASAN INDUSTRI MODERN, BANTEN @@ -4864,6 +5238,8 @@ Jika D.O. ini telah ditanda tangan oleh Penerima barang tanpa sanggahan, segala #### 🔍 Stage 2 — Layer 1: Regex Extraction (`parseDOMetadata`) +*Regex patterns are applied to raw markdown to extract header fields and item rows.* + **Header fields (raw regex output):** - **noDO**: `1659896184` @@ -4889,6 +5265,8 @@ Jika D.O. ini telah ditanda tangan oleh Penerima barang tanpa sanggahan, segala #### 🧹 Stage 3 — Layer 2: Sanitized (`sanitizeParsedMetadata`) +*Strict format enforcement: corrects date formats, trims whitespace, enforces field constraints.* + **Header fields (after sanitization):** - **noDO**: `1659896184` @@ -4914,6 +5292,8 @@ Jika D.O. ini telah ditanda tangan oleh Penerima barang tanpa sanggahan, segala #### ✅ Stage 4 — Layer 3: Final (`SKU triple-check + store resolution`) +*SKU validated against master list (score ≥ 0.6 threshold). Items with noise SKU codes are filtered out. Store resolved from DB.* + **Final metadata:** - **noDO**: `1659896184` @@ -4922,8 +5302,8 @@ Jika D.O. ini telah ditanda tangan oleh Penerima barang tanpa sanggahan, segala - **tanggal**: `16 April 2026` - **vendorInfo**: `PT. CHAROEN POKPHAND INDONESIA TBK RAWASAN INDUSTRI MODERN, BANTEN` - **customerInfo**: `PT.PRIMAFOOD INTERNATIONAL` -- **alamat**: *empty* -- **orderUntuk**: *empty* +- **alamat**: `JL. ANCOL BARAT VIII/1 KEL. ANCOL, KEC. PADEMANGAN JAKARTA UTARA, DKI JAKARTA` +- **orderUntuk**: `PX HEAD OFFICE ANCOL` - **platTruk**: *empty* **Final items after SKU validation (3 row(s)):** @@ -4936,6 +5316,8 @@ Jika D.O. ini telah ditanda tangan oleh Penerima barang tanpa sanggahan, segala #### 🗃️ Stage 5 — Submitted Items (ready-to-use JSON) +*These are the items actually returned to the caller and saved to the database.* + | kodeBarangOriginal | kodeBarang | namaBarang | banyak | jumlah | | --- | --- | --- | --- | --- | | 12080101 | 12080101 | FIESTA SPICY CHICK 400 GR/PAC | 1 BOX | 12 PAC | @@ -4955,6 +5337,8 @@ Jika D.O. ini telah ditanda tangan oleh Penerima barang tanpa sanggahan, segala #### 📄 Stage 1 — Raw OCR Markdown +*This is the raw text extracted by PaddleOCR layout parser before any post-processing.* + ```markdown PT. CHAROEN POKPHAND INDONESIA TBK KAWASAN INDUSTRI MODERN, BANTEN @@ -4996,6 +5380,8 @@ Jika D.O. ini telah ditanda tangan oleh Penerima barang tanpa sanggahan, segala #### 🔍 Stage 2 — Layer 1: Regex Extraction (`parseDOMetadata`) +*Regex patterns are applied to raw markdown to extract header fields and item rows.* + **Header fields (raw regex output):** - **noDO**: `1659922449` @@ -5018,6 +5404,8 @@ Jika D.O. ini telah ditanda tangan oleh Penerima barang tanpa sanggahan, segala #### 🧹 Stage 3 — Layer 2: Sanitized (`sanitizeParsedMetadata`) +*Strict format enforcement: corrects date formats, trims whitespace, enforces field constraints.* + **Header fields (after sanitization):** - **noDO**: `1659922449` @@ -5040,6 +5428,8 @@ Jika D.O. ini telah ditanda tangan oleh Penerima barang tanpa sanggahan, segala #### ✅ Stage 4 — Layer 3: Final (`SKU triple-check + store resolution`) +*SKU validated against master list (score ≥ 0.6 threshold). Items with noise SKU codes are filtered out. Store resolved from DB.* + **Final metadata:** - **noDO**: `1659922449` @@ -5048,8 +5438,8 @@ Jika D.O. ini telah ditanda tangan oleh Penerima barang tanpa sanggahan, segala - **tanggal**: `07 May 2026` - **vendorInfo**: `PT. CHAROEN POKPHAND INDONESIA TBK KAWASAN INDUSTRI MODERN, BANTEN` - **customerInfo**: `PT.PRIMAFOOD INTERNATIONAL` -- **alamat**: *empty* -- **orderUntuk**: *empty* +- **alamat**: `JL. ANCOL BARAT VIII/1 KEL. ANCOL, KEC. PADEMANGAN JAKARTA UTARA, DKI JAKARTA` +- **orderUntuk**: `PX HEAD OFFICE ANCOL` - **platTruk**: `B 9259 BCU` **Final items after SKU validation (1 row(s)):** @@ -5060,6 +5450,8 @@ Jika D.O. ini telah ditanda tangan oleh Penerima barang tanpa sanggahan, segala #### 🗃️ Stage 5 — Submitted Items (ready-to-use JSON) +*These are the items actually returned to the caller and saved to the database.* + | kodeBarangOriginal | kodeBarang | namaBarang | banyak | jumlah | | --- | --- | --- | --- | --- | | 11750050 | 11750050 | FILLET MITRA 1 KG(*) | 1 BOX | 10 KG | diff --git a/backend/sources/comparison_report.xlsx b/backend/sources/comparison_report.xlsx index 390670f76406f2d63b2fce25b820f3e931488ca0..2cd92b5376517fbdc7929209d8cf21af2197805c 100644 GIT binary patch delta 13565 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 diff --git a/backend/sources/comparison_side_by_side.md b/backend/sources/comparison_side_by_side.md new file mode 100644 index 0000000..1ec2bc4 --- /dev/null +++ b/backend/sources/comparison_side_by_side.md @@ -0,0 +1,341 @@ +# Side-by-Side Accuracy Comparison Report + +### Summary Accuracy Metrics + +| Field / Area | Total Checks | Matches | Mismatches | Accuracy (%) | +|---|---|---|---|---| +| PO Number | 14 | 11 | 3 | 78.57% | +| SO Number | 14 | 10 | 4 | 71.43% | +| DO Number | 14 | 10 | 4 | 71.43% | +| Date | 14 | 11 | 3 | 78.57% | +| Plat Nomor | 14 | 8 | 6 | 57.14% | +| Customer Name | 14 | 14 | 0 | 100.00% | +| Store Name | 14 | 11 | 3 | 78.57% | +| Alamat | 14 | 12 | 2 | 85.71% | +| Item SKU | 39 | 39 | 0 | 100.00% | +| Item Banyak | 39 | 38 | 1 | 97.44% | +| Item Jumlah | 39 | 39 | 0 | 100.00% | +| **OVERALL TOTAL** | **229** | **203** | **26** | **88.65%** | + + +## Detailed Comparison per File + +### 📄 `1782870899198-sample_do.jpeg` + +#### Header Fields +| Field | AI Value (OCR) | Manual Value (Ground Truth) | Status | +|---|---|---|---| +| PO Number | `PO/26/0000230828` | `PO/26/0000230828` | ✅ Match | +| SO Number | `1691960321` | `1691960321` | ✅ Match | +| DO Number | `1659980277` | `1659980277` | ✅ Match | +| Date | `23 JUNE 2026` | `23 JUNE 2026` | ✅ Match | +| Plat Nomor | `B 9427 UXT` | `B 9427 UXT` | ✅ Match | +| Customer Name | `PT.PRIMAFOOD INTERNATIONAL` | `PT.PRIMAFOOD INTERNATIONAL` | ✅ Match | +| Store Name | `PX HEAD OFFICE ANCOL` | `PX HEAD OFFICE ANCOL` | ✅ Match | +| Alamat | `JL. ANCOL BARAT VIII/1 KEL. ANCOL, KEC. PADEMANGAN JAKARTA UTARA, DKI JAKARTA` | `JL. ANCOL BARAT VIII/1 KEL. ANCOL, KEC. PADEMANGAN JAKARTA UTARA, DKI JAKARTA` | ✅ Match | + +#### Items List +| SKU | AI Banyak | Manual Banyak | Banyak Status | AI Jumlah | Manual Jumlah | Jumlah Status | +|---|---|---|---|---|---|---| +| `11310014` | `2 KRG` | `2 KRG` | ✅ Match | `40 PC` | `40 PC` | ✅ Match | +| `11310024` | `2 KRG` | `2 KRG` | ✅ Match | `40 PC` | `40 PC` | ✅ Match | +| `11620056` | `1 BOX` | `1 BOX` | ✅ Match | `10 KG` | `10 KG` | ✅ Match | +| `11690053` | `1 BOX` | `1 BOX` | ✅ Match | `10 KG` | `10 KG` | ✅ Match | +| `11720055` | `1 BOX` | `1 BOX` | ✅ Match | `10 KG` | `10 KG` | ✅ Match | + +--- + +### 📄 `1782884664859-rotated_1782884661516_rotated_1782884658097_rotated_1782884654697_CAP5956452738616729026.jpg` + +#### Header Fields +| Field | AI Value (OCR) | Manual Value (Ground Truth) | Status | +|---|---|---|---| +| PO Number | `PO/26/0000178435` | `PO/26/0000178435` | ✅ Match | +| SO Number | `1691908676` | `1691908676` | ✅ Match | +| DO Number | `1659932080` | `1659932080` | ✅ Match | +| Date | `15 MAY 2026` | `15 MAY 2026` | ✅ Match | +| Plat Nomor | `B 9723 CXS` | `B 9723 CXS` | ✅ Match | +| Customer Name | `PT.PRIMAFOOD INTERNATIONAL` | `PT.PRIMAFOOD INTERNATIONAL` | ✅ Match | +| Store Name | `AYAM HITZ HO ANCOL` | `AYAM HITZ HO ANCOL` | ✅ Match | +| Alamat | `JL. ANCOL BARAT VIII/1 KEL. ANCOL, KEC. PADEMANGAN JAKARTA UTARA, DKI JAKARTA` | `JL. ANCOL BARAT VIII/1 KEL. ANCOL, KEC. PADEMANGAN JAKARTA UTARA, DKI JAKARTA` | ✅ Match | + +#### Items List +| SKU | AI Banyak | Manual Banyak | Banyak Status | AI Jumlah | Manual Jumlah | Jumlah Status | +|---|---|---|---|---|---|---| +| `13012205` | `1 BOX` | `1 BOX` | ✅ Match | `15 PAC` | `15 PAC` | ✅ Match | + +--- + +### 📄 `1782888127716-CAP6161747431193129837.jpg` + +#### Header Fields +| Field | AI Value (OCR) | Manual Value (Ground Truth) | Status | +|---|---|---|---| +| PO Number | `PO/26/0000241938` | `PO/26/0000241938` | ✅ Match | +| SO Number | `1691972227` | `1691972227` | ✅ Match | +| DO Number | `1659990561` | `1659990561` | ✅ Match | +| Date | `30 JUNE 2026` | `30 JUNE 2026` | ✅ Match | +| Plat Nomor | `B 9257 JXR` | `B 9257 JXR` | ✅ Match | +| Customer Name | `PT.PRIMAFOOD INTERNATIONAL` | `PT.PRIMAFOOD INTERNATIONAL` | ✅ Match | +| Store Name | `PX HEAD OFFICE ANCOL` | `PX HEAD OFFICE ANCOL` | ✅ Match | +| Alamat | `JL. ANCOL BARAT VIII/1 KEL. ANCOL, KEC. PADEMANGAN JAKARTA UTARA, DKI JAKARTA` | `JL. ANCOL BARAT VIII/1 KEL. ANCOL, KEC. PADEMANGAN JAKARTA UTARA, DKI JAKARTA` | ✅ Match | + +#### Items List +| SKU | AI Banyak | Manual Banyak | Banyak Status | AI Jumlah | Manual Jumlah | Jumlah Status | +|---|---|---|---|---|---|---| +| `21002601` | `1 BOX` | `1 BOX` | ✅ Match | `6 PAC` | `6 PAC` | ✅ Match | + +--- + +### 📄 `1782888211457-rotated_1782888204591_rotated_1782888199962_rotated_1782888195402_CAP7202641176939787142.jpg` + +#### Header Fields +| Field | AI Value (OCR) | Manual Value (Ground Truth) | Status | +|---|---|---|---| +| PO Number | `PO/26/0000241938` | `PO/26/0000241938` | ✅ Match | +| SO Number | `1691972227` | `1691972227` | ✅ Match | +| DO Number | `1659990561` | `1659990561` | ✅ Match | +| Date | `30 JUNE 2026` | `30 JUNE 2026` | ✅ Match | +| Plat Nomor | `B 9257 JXR` | `B 9257 JXR` | ✅ Match | +| Customer Name | `PT.PRIMAFOOD INTERNATIONAL` | `PT.PRIMAFOOD INTERNATIONAL` | ✅ Match | +| Store Name | `PX HEAD OFFICE ANCOL` | `PX HEAD OFFICE ANCOL` | ✅ Match | +| Alamat | `JL. ANCOL BARAT VIII/1 KEL. ANCOL, KEC. PADEMANGAN JAKARTA UTARA, DKI JAKARTA` | `JL. ANCOL BARAT VIII/1 KEL. ANCOL, KEC. PADEMANGAN JAKARTA UTARA, DKI JAKARTA` | ✅ Match | + +#### Items List +| SKU | AI Banyak | Manual Banyak | Banyak Status | AI Jumlah | Manual Jumlah | Jumlah Status | +|---|---|---|---|---|---|---| +| `21002601` | `1 BOX` | `1 80X` | ❌ Mismatch | `6 PAC` | `6 PAC` | ✅ Match | + +--- + +### 📄 `1782888609885-rotated_1782888593813_1000000454.jpg` + +#### Header Fields +| Field | AI Value (OCR) | Manual Value (Ground Truth) | Status | +|---|---|---|---| +| PO Number | `PO/26/0000238723` | `PO/26/0000238723` | ✅ Match | +| SO Number | `(empty)` | `1691969268` | ❌ Mismatch | +| DO Number | `(empty)` | `1659987802` | ❌ Mismatch | +| Date | `(empty)` | `27 JUNE 2026` | ❌ Mismatch | +| Plat Nomor | `B 9715 UXU` | `B 9715 UXU` | ✅ Match | +| Customer Name | `PT.PRIMAFOOD INTERNATIONAL` | `PT.PRIMAFOOD INTERNATIONAL` | ✅ Match | +| Store Name | `PX HEAD OFFICE ANCOL` | `PX HEAD OFFICE ANCOL` | ✅ Match | +| Alamat | `JL. ANCOL BARAT VIII/1 KEL. ANCOL, KEC. PADEMANGAN JAKARTA UTARA, DKI JAKARTA` | `JL. ANCOL BARAT VIII/1 KEL. ANCOL, KEC. PADEMANGAN JAKARTA UTARA, DKI JAKARTA` | ✅ Match | + +#### Items List +| SKU | AI Banyak | Manual Banyak | Banyak Status | AI Jumlah | Manual Jumlah | Jumlah Status | +|---|---|---|---|---|---|---| +| `11310014` | `3 KRG` | `3 KRG` | ✅ Match | `60 PC` | `60 PC` | ✅ Match | +| `11310024` | `2 KRG` | `2 KRG` | ✅ Match | `40 PC` | `40 PC` | ✅ Match | +| `11660050` | `1 BOX` | `1 BOX` | ✅ Match | `10 KG` | `10 KG` | ✅ Match | +| `11690053` | `1 BOX` | `1 BOX` | ✅ Match | `10 KG` | `10 KG` | ✅ Match | +| `11720055` | `1 BOX` | `1 BOX` | ✅ Match | `10 KG` | `10 KG` | ✅ Match | +| `11750050` | `1 BOX` | `1 BOX` | ✅ Match | `10 KG` | `10 KG` | ✅ Match | + +--- + +### 📄 `1782890303600-1000000465.jpg` + +#### Header Fields +| Field | AI Value (OCR) | Manual Value (Ground Truth) | Status | +|---|---|---|---| +| PO Number | `PO/26/0000241302` | `PO/26/0000241302` | ✅ Match | +| SO Number | `1691972284` | `1691972284` | ✅ Match | +| DO Number | `1659990583` | `1659990583` | ✅ Match | +| Date | `30 JUNE 2026` | `30 JUNE 2026` | ✅ Match | +| Plat Nomor | `(empty)` | `B 9256 JXR` | ❌ Mismatch | +| Customer Name | `PT.PRIMAFOOD INTERNATIONAL` | `PT.PRIMAFOOD INTERNATIONAL` | ✅ Match | +| Store Name | `PX HEAD OFFICE ANCOL` | `PX HEAD OFFICE ANCOL` | ✅ Match | +| Alamat | `JL. ANCOL BARAT VIII/1 KEL. ANCOL, KEC. PADEMANGAN JAKARTA UTARA, DKI JAKARTA` | `JL. ANCOL BARAT VIII/1 KEL. ANCOL, KEC. PADEMANGAN JAKARTA UTARA, DKI JAKARTA` | ✅ Match | + +#### Items List +| SKU | AI Banyak | Manual Banyak | Banyak Status | AI Jumlah | Manual Jumlah | Jumlah Status | +|---|---|---|---|---|---|---| +| `12010509` | `1 BOX` | `1 BOX` | ✅ Match | `10 PAC` | `10 PAC` | ✅ Match | +| `12010512` | `1 BOX` | `1 BOX` | ✅ Match | `6 PAC` | `6 PAC` | ✅ Match | +| `12010519` | `1 BOX` | `1 BOX` | ✅ Match | `6 PAC` | `6 PAC` | ✅ Match | +| `12012501` | `1 BOX` | `1 BOX` | ✅ Match | `20 PAC` | `20 PAC` | ✅ Match | +| `12012503` | `1 BOX` | `1 BOX` | ✅ Match | `5 PAC` | `5 PAC` | ✅ Match | +| `13010116` | `1 BOX` | `1 BOX` | ✅ Match | `20 PAC` | `20 PAC` | ✅ Match | +| `13010514` | `1 BOX` | `1 BOX` | ✅ Match | `10 PAC` | `10 PAC` | ✅ Match | +| `13030502` | `1 BOX` | `1 BOX` | ✅ Match | `10 PAC` | `10 PAC` | ✅ Match | + +--- + +### 📄 `1782892728794-1000000466.jpg` + +#### Header Fields +| Field | AI Value (OCR) | Manual Value (Ground Truth) | Status | +|---|---|---|---| +| PO Number | `PO/26/0000241302` | `PO/26/0000241302` | ✅ Match | +| SO Number | `1691972284` | `1691972284` | ✅ Match | +| DO Number | `1659990583` | `1659990583` | ✅ Match | +| Date | `30 JUNE 2026` | `30 JUNE 2026` | ✅ Match | +| Plat Nomor | `B 9256 JXR` | `B 9256 JXR` | ✅ Match | +| Customer Name | `PT.PRIMAFOOD INTERNATIONAL` | `PT.PRIMAFOOD INTERNATIONAL` | ✅ Match | +| Store Name | `PX HEAD OFFICE ANCOL` | `PX HEAD OFFICE ANCOL` | ✅ Match | +| Alamat | `JL. ANCOL BARAT VIII/1 KEL. ANCOL, KEC. PADEMANGAN JAKARTA UTARA, DKI JAKARTA` | `JL. ANCOL BARAT VIII/1 KEL. ANCOL, KEC. PADEMANGAN JAKARTA UTARA, DKI JAKARTA` | ✅ Match | + +#### Items List +| SKU | AI Banyak | Manual Banyak | Banyak Status | AI Jumlah | Manual Jumlah | Jumlah Status | +|---|---|---|---|---|---|---| +| `15040101` | `1 BOX` | `1 BOX` | ✅ Match | `12 PAC` | `12 PAC` | ✅ Match | + +--- + +### 📄 `IMG_20260630_145445.jpg` + +#### Header Fields +| Field | AI Value (OCR) | Manual Value (Ground Truth) | Status | +|---|---|---|---| +| PO Number | `PO/26/0000170727` | `PO/26/0000190929` | ❌ Mismatch | +| SO Number | `1071721209` | `1691921200` | ❌ Mismatch | +| DO Number | `1057745004` | `1659943004` | ❌ Mismatch | +| Date | `25 MAY 2026` | `25 MAY 2026` | ✅ Match | +| Plat Nomor | `(empty)` | `B 9536 UCO` | ❌ Mismatch | +| Customer Name | `PT.PRIMAFOOD INTERNATIONAL` | `PT.PRIMAFOOD INTERNATIONAL` | ✅ Match | +| Store Name | `PX HEAD OFFICE ANCOL` | `PFM-KU` | ❌ Mismatch | +| Alamat | `JL. ANCOL BARAT VIII/1 KEL. ANCOL, KEC. PADEMANGAN JAKARTA UTARA, DKI JAKARTA` | `JL. ANCOL BARAT VIII/1 KEL. ANCOL, KEC. PADEMANGAN JAKARTA UTARA, DKI JAKARTA` | ✅ Match | + +#### Items List +| SKU | AI Banyak | Manual Banyak | Banyak Status | AI Jumlah | Manual Jumlah | Jumlah Status | +|---|---|---|---|---|---|---| +| `13030502` | `1 BOX` | `1 BOX` | ✅ Match | `10 PAC` | `10 PAC` | ✅ Match | + +--- + +### 📄 `IMG_20260701_134446.jpg` + +#### Header Fields +| Field | AI Value (OCR) | Manual Value (Ground Truth) | Status | +|---|---|---|---| +| PO Number | `(empty)` | `PO/26/0000241938` | ❌ Mismatch | +| SO Number | `(empty)` | `1691972227` | ❌ Mismatch | +| DO Number | `(empty)` | `1659990561` | ❌ Mismatch | +| Date | `(empty)` | `30 JUNE 2026` | ❌ Mismatch | +| Plat Nomor | `B 9257 JXR` | `B 9257 JXR` | ✅ Match | +| Customer Name | `PT.PRIMAFOOD INTERNATIONAL` | `PT.PRIMAFOOD INTERNATIONAL` | ✅ Match | +| Store Name | `PX HEAD OFFICE ANCOL` | `PX HEAD OFFICE ANCOL` | ✅ Match | +| Alamat | `JL. ANCOL BARAT VIII/1 KEL. ANCOL, KEC. PADEMANGAN JAKARTA UTARA, DKI JAKARTA` | `JL. ANCOL BARAT VIII/1 KEL. ANCOL, KEC. PADEMANGAN JAKARTA UTARA, DKI JAKARTA` | ✅ Match | + +#### Items List +| SKU | AI Banyak | Manual Banyak | Banyak Status | AI Jumlah | Manual Jumlah | Jumlah Status | +|---|---|---|---|---|---|---| +| `21002601` | `1 BOX` | `1 BOX` | ✅ Match | `6 PAC` | `6 PAC` | ✅ Match | + +--- + +### 📄 `IMG_20260701_134504.jpg` + +#### Header Fields +| Field | AI Value (OCR) | Manual Value (Ground Truth) | Status | +|---|---|---|---| +| PO Number | `PO/26/0000241303` | `PO/26/0000241303` | ✅ Match | +| SO Number | `1691972285` | `1691972285` | ✅ Match | +| DO Number | `1659990584` | `1659990584` | ✅ Match | +| Date | `30 JUNE 2026` | `30 JUNE 2026` | ✅ Match | +| Plat Nomor | `(empty)` | `B 9256 JXR` | ❌ Mismatch | +| Customer Name | `PT.PRIMAFOOD INTERNATIONAL` | `PT.PRIMAFOOD INTERNATIONAL` | ✅ Match | +| Store Name | `PRIMA XPRESS - TOWN HALL ANCOL` | `PX HEAD OFFICE ANCOL` | ❌ Mismatch | +| Alamat | `JL. ANCOL BARAT VIII/1 KEL. ANCOL, KEC. PADEMANGAN, JAKARTA UTARA, DKI JAKARTA (KANTIN CPI)` | `JL. ANCOL BARAT VIII/1 KEL. ANCOL, KEC. PADEMANGAN JAKARTA UTARA, DKI JAKARTA` | ❌ Mismatch | + +#### Items List +| SKU | AI Banyak | Manual Banyak | Banyak Status | AI Jumlah | Manual Jumlah | Jumlah Status | +|---|---|---|---|---|---|---| +| `21010104` | `1 BOX` | `1 BOX` | ✅ Match | `6 PAC` | `6 PAC` | ✅ Match | + +--- + +### 📄 `IMG_20260701_134555.jpg` + +#### Header Fields +| Field | AI Value (OCR) | Manual Value (Ground Truth) | Status | +|---|---|---|---| +| PO Number | `PO/26/0000241304` | `PO/26/0000241304` | ✅ Match | +| SO Number | `2271289510` | `2271289510` | ✅ Match | +| DO Number | `2272290022` | `2272290022` | ✅ Match | +| Date | `30 JUNE 2026` | `30 JUNE 2026` | ✅ Match | +| Plat Nomor | `(empty)` | `B 9836 UCH` | ❌ Mismatch | +| Customer Name | `PT.PRIMAFOOD INTERNATIONAL` | `PT.PRIMAFOOD INTERNATIONAL` | ✅ Match | +| Store Name | `PX HEAD OFFICE ANCOL` | `PX HEAD OFFICE ANCOL` | ✅ Match | +| Alamat | `JL. ANCOL BARAT VIII/1 KEL. ANCOL, KEC. PADEMANGAN JAKARTA UTARA, DKI JAKARTA` | `JL. ANCOL BARAT VIII/1 KEL. ANCOL, KEC. PADEMANGAN JAKARTA UTARA, DKI JAKARTA` | ✅ Match | + +#### Items List +| SKU | AI Banyak | Manual Banyak | Banyak Status | AI Jumlah | Manual Jumlah | Jumlah Status | +|---|---|---|---|---|---|---| +| `11048006` | `2 BOX` | `2 BOX` | ✅ Match | `30 PAC` | `30 PAC` | ✅ Match | + +--- + +### 📄 `IMG_20260701_134555~2.jpg` + +#### Header Fields +| Field | AI Value (OCR) | Manual Value (Ground Truth) | Status | +|---|---|---|---| +| PO Number | `PO/26/0000241304` | `PO/26/0000241304` | ✅ Match | +| SO Number | `2271289510` | `2271289510` | ✅ Match | +| DO Number | `2272290022` | `2272290022` | ✅ Match | +| Date | `30 JUNE 2026` | `30 JUNE 2026` | ✅ Match | +| Plat Nomor | `(empty)` | `B 9836 UCH` | ❌ Mismatch | +| Customer Name | `PT.PRIMAFOOD INTERNATIONAL` | `PT.PRIMAFOOD INTERNATIONAL` | ✅ Match | +| Store Name | `PX HEAD OFFICE ANCOL` | `PX HEAD OFFICE ANCOL` | ✅ Match | +| Alamat | `JL. ANCOL BARAT VIII/1 KEL. ANCOL, KEC. PADEMANGAN JAKARTA UTARA, DKI JAKARTA` | `JL. ANCOL BARAT VIII/1 KEL. ANCOL, KEC. PADEMANGAN JAKARTA UTARA, DKI JAKARTA` | ✅ Match | + +#### Items List +| SKU | AI Banyak | Manual Banyak | Banyak Status | AI Jumlah | Manual Jumlah | Jumlah Status | +|---|---|---|---|---|---|---| +| `11048000` | `2 BOX` | `2 BOX` | ✅ Match | `30 PAC` | `30 PAC` | ✅ Match | + +--- + +### 📄 `IMG_20260701_134646~2.jpg` + +#### Header Fields +| Field | AI Value (OCR) | Manual Value (Ground Truth) | Status | +|---|---|---|---| +| PO Number | `PO/26/0000230199` | `PO/26/0000230199` | ✅ Match | +| SO Number | `1691960321` | `1691960321` | ✅ Match | +| DO Number | `1659980277` | `1659980277` | ✅ Match | +| Date | `23 JUNE 2026` | `23 JUNE 2026` | ✅ Match | +| Plat Nomor | `B 9427 UXT` | `B 9427 UXT` | ✅ Match | +| Customer Name | `PT.PRIMAFOOD INTERNATIONAL` | `PT.PRIMAFOOD INTERNATIONAL` | ✅ Match | +| Store Name | `PX HEAD OFFICE ANCOL` | `PX HEAD OFFICE ANCOL` | ✅ Match | +| Alamat | `JL. ANCOL BARAT VIII/1 KEL. ANCOL, KEC. PADEMANGAN JAKARTA UTARA, DKI JAKARTA` | `JL. ANCOL BARAT VIII/1 KEL. ANCOL, KEC. PADEMANGAN JAKARTA UTARA, DKI JAKARTA` | ✅ Match | + +#### Items List +| SKU | AI Banyak | Manual Banyak | Banyak Status | AI Jumlah | Manual Jumlah | Jumlah Status | +|---|---|---|---|---|---|---| +| `11310014` | `2 KRG` | `2 KRG` | ✅ Match | `40 PC` | `40 PC` | ✅ Match | +| `11310024` | `2 KRG` | `2 KRG` | ✅ Match | `40 PC` | `40 PC` | ✅ Match | +| `11620056` | `1 BOX` | `1 BOX` | ✅ Match | `10 KG` | `10 KG` | ✅ Match | +| `11690053` | `1 BOX` | `1 BOX` | ✅ Match | `10 KG` | `10 KG` | ✅ Match | +| `11720055` | `1 BOX` | `1 BOX` | ✅ Match | `10 KG` | `10 KG` | ✅ Match | + +--- + +### 📄 `IMG_20260701_134810.jpg` + +#### Header Fields +| Field | AI Value (OCR) | Manual Value (Ground Truth) | Status | +|---|---|---|---| +| PO Number | `(empty)` | `PO/26/0000241301` | ❌ Mismatch | +| SO Number | `(empty)` | `1691972419` | ❌ Mismatch | +| DO Number | `(empty)` | `1659990664` | ❌ Mismatch | +| Date | `(empty)` | `30 JUNE 2026` | ❌ Mismatch | +| Plat Nomor | `(empty)` | `B 9256 JXR` | ❌ Mismatch | +| Customer Name | `PT.PRIMAFOOD INTERNATIONAL` | `PT.PRIMAFOOD INTERNATIONAL` | ✅ Match | +| Store Name | `(empty)` | `PX HEAD OFFICE ANCOL` | ❌ Mismatch | +| Alamat | `(empty)` | `JL. ANCOL BARAT VIII/1 KEL. ANCOL, KEC. PADEMANGAN JAKARTA UTARA, DKI JAKARTA` | ❌ Mismatch | + +#### Items List +| SKU | AI Banyak | Manual Banyak | Banyak Status | AI Jumlah | Manual Jumlah | Jumlah Status | +|---|---|---|---|---|---|---| +| `11140062` | `1 KRG` | `1 KRG` | ✅ Match | `20 KG` | `20 KG` | ✅ Match | +| `11150064` | `1 KRG` | `1 KRG` | ✅ Match | `20 KG` | `20 KG` | ✅ Match | +| `11310014` | `3 KRG` | `3 KRG` | ✅ Match | `60 PC` | `60 PC` | ✅ Match | +| `11600053` | `1 BOX` | `1 BOX` | ✅ Match | `10 KG` | `10 KG` | ✅ Match | +| `11650053` | `1 BOX` | `1 BOX` | ✅ Match | `10 KG` | `10 KG` | ✅ Match | +| `11750050` | `1 BOX` | `1 BOX` | ✅ Match | `10 KG` | `10 KG` | ✅ Match | + +--- + diff --git a/backend/sources/generate_side_by_side.py b/backend/sources/generate_side_by_side.py new file mode 100644 index 0000000..050b759 --- /dev/null +++ b/backend/sources/generate_side_by_side.py @@ -0,0 +1,160 @@ +import json +import os + +def clean_val(val): + if val is None: + return "" + s = str(val).strip().upper() + if s in ["N/A", "NOT FOUND", "NOTFOUND", "EMPTY", "NONE", "-", "N / A"]: + return "" + s = " ".join(s.split()) + s = s.replace("PT. ", "PT.") + s = s.replace("✓", "").replace("✔", "").strip() + return s + +def main(): + ai_file = "backend/sources/ai_results.json" + manual_file = "backend/sources/manual_labels.json" + output_md = "backend/sources/comparison_side_by_side.md" + + if not os.path.exists(ai_file) or not os.path.exists(manual_file): + print("Required files not found.") + return + + with open(ai_file, "r", encoding="utf-8") as f: + ai_data = json.load(f) + + with open(manual_file, "r", encoding="utf-8") as f: + manual_data = json.load(f) + + ai_dict = {item.get("filename"): item for item in ai_data if item.get("filename")} + manual_dict = {item.get("filename"): item for item in manual_data if item.get("filename")} + + common_filenames = sorted(list(set(ai_dict.keys()) & set(manual_dict.keys()))) + + header_fields = [ + ("noPO", "noPO", "PO Number"), + ("noSO", "noSO", "SO Number"), + ("noDO", "noDO", "DO Number"), + ("tanggal", "tanggal", "Date"), + ("plat", "platTruk", "Plat Nomor"), + ("customer", "customerInfo", "Customer Name"), + ("store", "orderUntuk", "Store Name"), + ("alamat", "alamat", "Alamat") + ] + + stats = { + "PO Number": {"match": 0, "total": 0}, + "SO Number": {"match": 0, "total": 0}, + "DO Number": {"match": 0, "total": 0}, + "Date": {"match": 0, "total": 0}, + "Plat Nomor": {"match": 0, "total": 0}, + "Customer Name": {"match": 0, "total": 0}, + "Store Name": {"match": 0, "total": 0}, + "Alamat": {"match": 0, "total": 0}, + "Item SKU": {"match": 0, "total": 0}, + "Item Banyak": {"match": 0, "total": 0}, + "Item Jumlah": {"match": 0, "total": 0} + } + + md_content = [] + md_content.append("# Side-by-Side Accuracy Comparison Report\n\n") + md_content.append("\n\n") + md_content.append("## Detailed Comparison per File\n\n") + + for filename in common_filenames: + manual = manual_dict[filename] + ai = ai_dict[filename] + ai_meta = ai.get("layer3Final", {}) + + md_content.append(f"### 📄 `{filename}`\n\n") + + # Header fields table + md_content.append("#### Header Fields\n") + md_content.append("| Field | AI Value (OCR) | Manual Value (Ground Truth) | Status |\n") + md_content.append("|---|---|---|---|\n") + + for manual_key, ai_key, field_label in header_fields: + m_val = clean_val(manual.get(manual_key)) + a_val = clean_val(ai_meta.get(ai_key)) + is_match = (m_val == a_val) + status = "✅ Match" if is_match else "❌ Mismatch" + + stats[field_label]["total"] += 1 + if is_match: + stats[field_label]["match"] += 1 + + md_content.append(f"| {field_label} | `{a_val or '(empty)'}` | `{m_val or '(empty)'}` | {status} |\n") + + md_content.append("\n") + + # Items comparison + m_items = manual.get("items", []) + ai_items = ai.get("items", []) + if not ai_items and "items" in ai_meta: + ai_items = ai_meta.get("items", []) + + m_items_dict = {clean_val(item.get("kodeBarang")): item for item in m_items if clean_val(item.get("kodeBarang"))} + ai_items_dict = {clean_val(item.get("kodeBarang")): item for item in ai_items if clean_val(item.get("kodeBarang"))} + all_skus = sorted(list(set(m_items_dict.keys()) | set(ai_items_dict.keys()))) + + md_content.append("#### Items List\n") + md_content.append("| SKU | AI Banyak | Manual Banyak | Banyak Status | AI Jumlah | Manual Jumlah | Jumlah Status |\n") + md_content.append("|---|---|---|---|---|---|---|\n") + + for sku in all_skus: + m_item = m_items_dict.get(sku) + ai_item = ai_items_dict.get(sku) + + sku_match = (m_item is not None) and (ai_item is not None) + stats["Item SKU"]["total"] += 1 + if sku_match: + stats["Item SKU"]["match"] += 1 + + m_banyak = clean_val(m_item.get("banyak")) if m_item else "" + ai_banyak = clean_val(ai_item.get("banyak")) if ai_item else "" + banyak_match = (m_banyak == ai_banyak) + banyak_status = "✅ Match" if banyak_match else "❌ Mismatch" + stats["Item Banyak"]["total"] += 1 + if banyak_match: + stats["Item Banyak"]["match"] += 1 + + m_jumlah = clean_val(m_item.get("jumlah")) if m_item else "" + ai_jumlah = clean_val(ai_item.get("jumlah")) if ai_item else "" + jumlah_match = (m_jumlah == ai_jumlah) + jumlah_status = "✅ Match" if jumlah_match else "❌ Mismatch" + stats["Item Jumlah"]["total"] += 1 + if jumlah_match: + stats["Item Jumlah"]["match"] += 1 + + md_content.append(f"| `{sku}` | `{ai_banyak or '(empty)'}` | `{m_banyak or '(empty)'}` | {banyak_status} | `{ai_jumlah or '(empty)'}` | `{m_jumlah or '(empty)'}` | {jumlah_status} |\n") + + md_content.append("\n---\n\n") + + # Generate summary block + sum_md = [] + sum_md.append("### Summary Accuracy Metrics\n\n") + sum_md.append("| Field / Area | Total Checks | Matches | Mismatches | Accuracy (%) |\n") + sum_md.append("|---|---|---|---|---|\n") + + total_matches = 0 + total_fields = 0 + for field_label, counts in stats.items(): + match_cnt = counts["match"] + total_cnt = counts["total"] + pct = (match_cnt / total_cnt * 100.0) if total_cnt > 0 else 100.0 + sum_md.append(f"| {field_label} | {total_cnt} | {match_cnt} | {total_cnt - match_cnt} | {pct:.2f}% |\n") + total_matches += match_cnt + total_fields += total_cnt + + overall_accuracy = (total_matches / total_fields * 100.0) if total_fields > 0 else 100.0 + sum_md.append(f"| **OVERALL TOTAL** | **{total_fields}** | **{total_matches}** | **{total_fields - total_matches}** | **{overall_accuracy:.2f}%** |\n") + + full_md = "".join(md_content).replace("", "".join(sum_md)) + + with open(output_md, "w", encoding="utf-8") as f: + f.write(full_md) + print(f"Side-by-side report generated at: {output_md}") + +if __name__ == "__main__": + main()