2026-09-16 20:09:19 +00:00
<!DOCTYPE html>
< html lang = "en" >
< head >
< meta charset = "UTF-8" >
< title > Invoice Parser< / title >
< link rel = "stylesheet" href = "css/style.css" >
< script src = "js/jquery-3.5.1.min.js" > < / script >
< script src = "js/app.js" > < / script >
< / head >
< body >
< h1 >
Invoice Parser < span id = "pageMode" style = "color:#aaa;font-size:12px;font-weight:normal" > < / span >
2026-09-30 18:50:04 +00:00
< a href = "index.html" id = "navHome" > Home / Upload< / a >
2026-09-16 20:09:19 +00:00
< a href = "pending.html" > Pending< / a >
< a href = "archive.html" > Archive< / a >
2026-09-30 18:50:04 +00:00
< a href = "changes.html" > Changes< / a >
< button id = "btnPrevDraft" type = "button" class = "nav-draft" title = "Previous draft ready for review" disabled > ‹ Prev< / button >
< span id = "draftPos" class = "draft-pos" > < / span >
< button id = "btnNextDraft" type = "button" class = "nav-draft" title = "Next draft ready for review" disabled > Next › < / button >
2026-09-16 20:09:19 +00:00
< button id = "btnViewParsed" type = "button" title = "Compare what the parser read against the products it matched" > Parsed vs matched< / button >
< button id = "btnTogglePreview" type = "button" title = "Hide the invoice preview to give the form the full window" > « Hide preview< / button >
< / h1 >
<!-- ============ Review layout (?pending=<id>) ============ -->
< div id = "layout" >
< div id = "leftPanel" >
< div id = "uploadPrompt" style = "display:none" > < / div >
< div id = "previewToolbar" >
< button id = "btnZoomOut" type = "button" title = "Zoom out" > − < / button >
< span id = "zoomLevel" > 100%< / span >
< button id = "btnZoomIn" type = "button" title = "Zoom in" > +< / button >
< button id = "btnZoomFit" type = "button" title = "Fit the page to the panel width" > Fit< / button >
< span class = "field-note" > Ctrl + scroll to zoom< / span >
< / div >
< div id = "canvasWrapper" > < / div >
< div id = "scanSection" style = "display:none;align-items:center;gap:10px;padding:4px 0" >
< button id = "btnScan" > Scan Invoice< / button >
< / div >
< / div >
< div id = "splitter" title = "Drag to resize the preview" > < / div >
< div id = "rightPanel" >
< div id = "statusBar" > < / div >
< div id = "reviewSection" >
< div class = "form-section header-section" >
< h2 > Invoice Header< / h2 >
< div class = "hdr-grid" >
< div class = "hdr-field" >
< label for = "vendorSelect" > Vendor< / label >
< div class = "hdr-ctl" >
< select id = "vendorSelect" name = "vendor_id" style = "width:210px" >
< option value = "" > -- Select Vendor --< / option >
< / select >
< span id = "vendorBadge" class = "match-badge" style = "display:none" > < / span >
< / div >
< small class = "parsed-hint" id = "hintVendor" style = "display:none" > < / small >
< / div >
< div class = "hdr-field" >
< label for = "invoiceNumber" > Invoice #< / label >
< div class = "hdr-ctl" >
2026-09-30 18:50:04 +00:00
< input id = "invoiceNumber" name = "invoice_number" style = "width:130px" >
2026-09-16 20:09:19 +00:00
< / div >
2026-09-30 18:50:04 +00:00
< small class = "field-error" id = "errInvoiceNumber" style = "display:none" > < / small >
2026-09-16 20:09:19 +00:00
< small class = "parsed-hint" id = "hintInvoiceNumber" style = "display:none" > < / small >
< / div >
< div class = "hdr-field" >
< label for = "invoiceDate" > Invoice Date< / label >
< div class = "hdr-ctl" >
< input id = "invoiceDate" name = "invoice_date" type = "date" style = "width:135px" >
< / div >
< small class = "parsed-hint" id = "hintInvoiceDate" style = "display:none" > < / small >
< / div >
< div class = "hdr-field" >
< label for = "poSelect" > PO Number< / label >
< div class = "hdr-ctl" >
< select id = "poSelect" style = "width:230px" >
< option value = "" > No PO (auto-assign)< / option >
< / select >
< / div >
< / div >
< div class = "hdr-field" >
< label for = "invoiceTotal" > Total< / label >
< div class = "hdr-ctl" >
< input id = "invoiceTotal" name = "vendor_total" type = "number" step = "0.01" style = "width:100px" >
< / div >
< small class = "parsed-hint" id = "hintInvoiceTotal" style = "display:none" > < / small >
< / div >
< / div >
< / div >
< div class = "form-section items-section" >
2026-09-30 18:50:04 +00:00
< h2 > Line Items < span id = "lineSummary" class = "po-summary" > < / span > < span id = "totalCheck" class = "po-summary" > < / span > < span id = "poCompareSummary" class = "po-summary" > < / span >
2026-09-16 20:09:19 +00:00
< span class = "h2-actions" >
2026-09-30 18:50:04 +00:00
< label class = "diff-only" title = "Hide rows that are already reviewed" > < input type = "checkbox" id = "chkAttentionOnly" > attention only< / label >
2026-09-16 20:09:19 +00:00
< button id = "btnAddLine" type = "button" title = "Add a line item the parser missed" > + Add Line< / button >
< button id = "btnAcceptAll" type = "button" > Accept All< / button >
< / span >
< / h2 >
< div class = "table-scroll" >
< table id = "lineItemsTable" >
< colgroup >
< col class = "c-upc" >
< col class = "c-desc" >
< col class = "c-cert" >
< col class = "c-po" >
< col class = "c-po" >
< col class = "c-pocost" >
< col class = "c-qty" >
< col class = "c-cost" >
< col class = "c-pack" >
< col class = "c-unitcost" >
< col class = "c-retail" >
< col class = "c-gm" >
< col class = "c-total" >
< col class = "c-size" >
< col class = "c-uom" >
< col class = "c-match" >
< col class = "c-del" >
< / colgroup >
< thead >
< tr >
< th > UPC< / th >
< th > Description< / th >
< th > Cert Code< / th >
< th title = "PO cases" > PO Cs< / th >
< th title = "PO pieces" > PO Pc< / th >
< th title = "PO cost" > PO $< / th >
< th title = "Invoice quantity" > Qty< / th >
< th title = "Cost of one case as billed on the invoice" > Case Cost< / th >
< th title = "Units per case from the product file, or from the invoice PACK/SIZE column when the product has none - edit it to fix the margin" > Pack< / th >
< th title = "Case cost divided by pack" > Unit Cost< / th >
< th title = "Shelf retail from the product file" > Retail< / th >
< th title = "Gross margin: (retail - unit cost) / retail" > GM %< / th >
< th > Total< / th >
< th > Size< / th >
< th > UOM< / th >
< th > Match< / th >
< th > < / th >
< / tr >
< / thead >
< tbody id = "lineItemsBody" > < / tbody >
< / table >
< / div >
< / div >
< div class = "form-section actions-section" >
2026-09-30 18:50:04 +00:00
< button id = "btnRestoreDefaults" type = "button" class = "btn-quiet" > Restore defaults< / button >
< button id = "btnDeleteDraft" type = "button" class = "btn-quiet btn-quiet-danger" > Delete draft< / button >
< span id = "autosaveStatus" class = "field-note" title = "Edits save to Pending automatically" > Draft auto-saves to Pending< / span >
2026-09-16 20:09:19 +00:00
< span id = "saveBlockers" class = "save-blockers" style = "display:none" > < / span >
< span class = "actions-right" >
2026-09-30 18:50:04 +00:00
< button id = "btnSave" title = "Save Invoice (Ctrl+S)" > Save Invoice< / button >
2026-09-16 20:09:19 +00:00
< / span >
< / div >
< / div > <!-- /reviewSection -->
< / div > <!-- /rightPanel -->
< / div > <!-- /layout -->
<!-- ============ Landing dashboard ============ -->
< div id = "dashboard" >
2026-09-30 18:50:04 +00:00
< h2 id = "dashWelcome" class = "dash-welcome" style = "display:none" > < / h2 >
2026-09-16 20:09:19 +00:00
< div class = "dash-hero" >
2026-09-30 18:50:04 +00:00
< div id = "uploadZone" role = "button" tabindex = "0" onclick = "document.getElementById('fileInput').click()" >
2026-09-16 20:09:19 +00:00
< input type = "file" id = "fileInput" accept = ".pdf,.jpg,.jpeg,.png" multiple >
< span class = "up-icon" > 📤 < / span >
< label > Scan Invoices< / label >
< div id = "uploadPromptDash" style = "color:#aaa;margin-top:10px;font-size:13px" > Drag and drop or click - PDF or image (JPG, PNG). Select multiple to batch upload. Files parse automatically in the background; review them under Pending.< / div >
< / div >
< div id = "dashStatusBar" style = "display:none;padding:7px 12px;border-radius:4px;font-size:12px;margin-top:14px" > < / div >
2026-09-30 18:50:04 +00:00
< ul id = "uploadList" class = "upload-list" style = "display:none" > < / ul >
2026-09-16 20:09:19 +00:00
< / div >
< div class = "dash-actions" >
2026-09-30 18:50:04 +00:00
< a class = "dash-btn primary" id = "btnReviewNext" href = "pending.html" > Review next invoice< / a >
< span id = "reviewNextNote" class = "dash-note" > < / span >
2026-09-16 20:09:19 +00:00
< / div >
2026-09-30 18:50:04 +00:00
< div class = "stats-grid stats-primary" >
2026-09-16 20:09:19 +00:00
< a class = "stat-card sc-ready" href = "pending.html" title = "Parsed and waiting for your review" >
< div class = "stat-num" id = "statReady" > -< / div >
< div class = "stat-label" > Ready to review< / div >
< / a >
< a class = "stat-card sc-queued" href = "pending.html" title = "Uploaded, waiting for the parser" >
< div class = "stat-num" id = "statQueued" > -< / div >
< div class = "stat-label" > Queued< / div >
< div class = "stat-sub" id = "statProcessingSub" > < / div >
< / a >
< a class = "stat-card sc-error" href = "pending.html" title = "Background parsing failed - retry from Pending" >
< div class = "stat-num" id = "statError" > -< / div >
< div class = "stat-label" > Errors< / div >
< / a >
2026-09-30 18:50:04 +00:00
< / div >
< div class = "stats-grid stats-secondary" >
< a class = "stat-card sc-progress" href = "pending.html" title = "Drafts you have started editing" >
< div class = "stat-num" id = "statProgress" > -< / div >
< div class = "stat-label" > In progress< / div >
< / a >
2026-09-16 20:09:19 +00:00
< div class = "stat-card" title = "Uploaded today" >
< div class = "stat-num" id = "statToday" > -< / div >
< div class = "stat-label" > Uploaded today< / div >
< / div >
< a class = "stat-card sc-archived" href = "archive.html" title = "Completed and archived" >
< div class = "stat-num" id = "statArchived" > -< / div >
< div class = "stat-label" > Archived< / div >
< / a >
< a class = "stat-card sc-total" href = "pending.html" title = "All invoices in the pending queue" >
< div class = "stat-num" id = "statTotal" > -< / div >
< div class = "stat-label" > Total pending< / div >
< / a >
< div class = "stat-card sc-value" title = "Sum of invoice totals across all pending drafts" >
< div class = "stat-num" id = "statValue" > -< / div >
< div class = "stat-label" > Pending value< / div >
< / div >
< div class = "stat-card sc-lines" title = "Line items across all pending drafts" >
< div class = "stat-num" id = "statLines" > -< / div >
< div class = "stat-label" > Pending line items< / div >
< / div >
< / div >
< div class = "dash-foot" id = "dashUpdated" > < / div >
< / div > <!-- /dashboard -->
<!-- Parsed data viewer -->
< div id = "parsedModal" >
< div class = "modal-box parsed-box" >
< h2 >
Parsed vs matched
< span id = "ocrMethod" > < / span >
< label class = "diff-only" > < input type = "checkbox" id = "chkDiffOnly" > differences only< / label >
< button id = "btnCloseParsed" type = "button" > Close< / button >
< / h2 >
< div class = "parsed-tabs" >
< button class = "parsed-tab active" type = "button" data-pane = "paneCompare" > Line items< / button >
< button class = "parsed-tab" type = "button" data-pane = "paneText" > Extracted text< / button >
< / div >
< div class = "parsed-pane" id = "paneCompare" style = "display:flex" >
< div class = "field-note" > Left is what the parser read off the invoice; right is the product it was matched to. Differences are highlighted. Click a row to jump to it.< / div >
< div id = "compareScroll" >
< table id = "compareHeader" >
< thead >
< tr > < th > Header field< / th > < th > Parsed< / th > < th > In use< / th > < / tr >
< / thead >
< tbody id = "compareHeaderBody" > < / tbody >
< / table >
< table id = "compareTable" >
< thead >
< tr > < th > #< / th > < th > Parsed from invoice< / th > < th > Matched product< / th > < th > Status< / th > < / tr >
< / thead >
< tbody id = "compareBody" > < / tbody >
< / table >
< / div >
< / div >
< div class = "parsed-pane" id = "paneText" style = "display:none" >
< div class = "field-note" > Text pulled off the invoice. Edits are kept with the draft and used if you re-scan.< / div >
< textarea id = "ocrText" > < / textarea >
< / div >
< / div >
< / div >
<!-- New Product Modal -->
< div id = "newProductModal" >
< div class = "modal-box" >
< h2 > Create New Product< / h2 >
< div class = "field-row" >
< label > UPC < span style = "color:#ff8888" > *< / span > < / label >
< input id = "np_upc" style = "width:180px" maxlength = "13" placeholder = "e.g. 012345678901" >
< / div >
< div class = "field-row" >
< label > Description < span style = "color:#ff8888" > *< / span > < / label >
< input id = "np_desc" style = "width:220px" maxlength = "30" >
< / div >
< div class = "field-row" >
< label > Price < span style = "color:#ff8888" > *< / span > < / label >
< input id = "np_price" type = "text" style = "width:120px" placeholder = "2.99 or 2/5.00" >
< small class = "field-note" > plain price, or n/total for group pricing< / small >
< / div >
< div class = "field-row" >
< label > Department < span style = "color:#ff8888" > *< / span > < / label >
< select id = "np_dept" class = "np-select" style = "width:200px" >
< option value = "" > -- Select Department --< / option >
< / select >
< / div >
< div class = "field-row" >
< label > Tax< / label >
< select id = "np_tax" class = "np-select" style = "width:110px" >
< option value = "0" > 0 - No< / option >
< option value = "1" > 1 - Yes< / option >
< / select >
< small class = "field-note" id = "np_flagsNote" > from department< / small >
< / div >
< div class = "field-row" >
< label > Food Stamp< / label >
< select id = "np_fs" class = "np-select" style = "width:110px" >
< option value = "0" > 0 - No< / option >
< option value = "1" > 1 - Yes< / option >
< / select >
< / div >
< div class = "field-row" >
< label > Cost< / label >
< input id = "np_cost" type = "number" step = "0.01" min = "0" style = "width:100px" >
< / div >
< div class = "field-row" >
< label > Pack< / label >
< input id = "np_pack" type = "number" step = "1" min = "0" style = "width:100px" >
< / div >
< div class = "field-row" >
< label > Size< / label >
< input id = "np_size" style = "width:100px" maxlength = "9" >
< / div >
< div class = "field-row" >
< label > Item Code< / label >
< input id = "np_code" style = "width:140px" maxlength = "15" placeholder = "cert / item code" >
< / div >
< div style = "margin-top:14px;display:flex;gap:8px" >
< button id = "btnCreateProduct" style = "background:#6699CC;color:#111;border:none;padding:7px 18px;border-radius:4px;font-size:13px;font-weight:bold;cursor:pointer" > Create Product< / button >
< button id = "btnCloseModal" style = "background:#555;color:#eee;border:none;padding:7px 16px;border-radius:4px;font-size:13px;cursor:pointer" > Cancel< / button >
< / div >
< div id = "newProductStatus" style = "display:none;margin-top:10px;font-size:11px" > < / div >
< / div >
< / div >
< / body >
< / html >