From 554fde44473c3cbaf2d90745530256f02a56c5d1 Mon Sep 17 00:00:00 2001 From: Admin Date: Fri, 25 Sep 2026 21:08:24 +0000 Subject: [PATCH] fix: scope pallet diff parsing to card region --- package.json | 2 +- src-tauri/Cargo.toml | 2 +- src-tauri/src/pallet.rs | 82 +++++++++++++++++++++++++++++++++++++-- src-tauri/tauri.conf.json | 2 +- src/main.ts | 2 +- 5 files changed, 83 insertions(+), 7 deletions(-) diff --git a/package.json b/package.json index 73ef9f1..fbb510e 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@fieldlens/print", - "version": "0.1.20", + "version": "0.1.21", "private": true, "type": "module", "scripts": { diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml index 86830f3..378d176 100644 --- a/src-tauri/Cargo.toml +++ b/src-tauri/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "fieldlens-print" -version = "0.1.20" +version = "0.1.21" description = "FieldLens print-stream barcode capture companion" authors = ["Arrowstack"] edition = "2021" diff --git a/src-tauri/src/pallet.rs b/src-tauri/src/pallet.rs index 5ae1f1a..d5141a1 100644 --- a/src-tauri/src/pallet.rs +++ b/src-tauri/src/pallet.rs @@ -41,6 +41,39 @@ fn column_slice(line: &str, start: usize, end: Option) -> &str { } } + +fn scope_card_region(raw_text: &str) -> String { + let lines: Vec<&str> = raw_text.lines().collect(); + + let header_index = lines.iter().position(|line| { + find_ci(line, "ORIGIN").is_some() + && find_ci(line, "VAR").is_some() + && find_ci(line, "BRAND").is_some() + && find_ci(line, "CLASS").is_some() + }); + + let title_index = lines.iter().position(|line| { + find_ci(line, "Avocados").is_some() && line.contains('-') + }); + + let start = match (title_index, header_index) { + (Some(title), Some(header)) if title <= header && header.saturating_sub(title) <= 4 => title, + (_, Some(header)) => header, + (Some(title), None) => title, + (None, None) => return raw_text.to_string(), + }; + + let end = lines + .iter() + .enumerate() + .skip(start) + .find(|(_, line)| find_ci(line, "Total").is_some()) + .map(|(index, _)| index) + .unwrap_or_else(|| (start + 40).min(lines.len().saturating_sub(1))); + + lines[start..=end].join("\n") +} + fn parse_layout_tables(raw_text: &str, snapshot: &mut PalletSnapshot) { let lines: Vec<&str> = raw_text.lines().collect(); let right_col = lines @@ -121,7 +154,8 @@ fn parse_layout_tables(raw_text: &str, snapshot: &mut PalletSnapshot) { } pub fn parse_pallet_snapshot(raw_text: &str, pallet_id: &str) -> PalletSnapshot { - let flat = raw_text.split_whitespace().collect::>().join(" "); + let card_text = scope_card_region(raw_text); + let flat = card_text.split_whitespace().collect::>().join(" "); let mut snapshot = PalletSnapshot { pallet_id: pallet_id.trim().to_string(), ..PalletSnapshot::default() @@ -144,7 +178,7 @@ pub fn parse_pallet_snapshot(raw_text: &str, pallet_id: &str) -> PalletSnapshot ); snapshot.total = capture(&flat, r"(?i)\bTotal\s+([0-9]{1,5})\b", 1); - parse_layout_tables(raw_text, &mut snapshot); + parse_layout_tables(&card_text, &mut snapshot); if snapshot.grower.is_none() { if let Ok(regex) = Regex::new( @@ -174,7 +208,7 @@ pub fn parse_pallet_snapshot(raw_text: &str, pallet_id: &str) -> PalletSnapshot if snapshot.variety.is_none() { if let Ok(regex) = Regex::new(r"(?i)^\s*Avocados?\s*-\s*([A-Z][A-Z -]{1,20})\s*$") { - snapshot.variety = raw_text.lines().find_map(|line| { + snapshot.variety = card_text.lines().find_map(|line| { regex .captures(line) .and_then(|captures| captures.get(1)) @@ -277,6 +311,48 @@ mod tests { Total 30 "#; + const WHOLE_SHEET: &str = r#" + 20 JA 40595983 + JA 40595983 JA 40595983 JA 40595983 + 20 + Avocados - Hass + ORIGIN VAR BRAND CLASS Pallet: 40595983 + NZ Hass NZAG CLASS 3. Grower Packrun Size Qty + BASE PACK 89930 89930/16/17/26 20 30 + CHEP B37 + Pick Date: 16/09/2026 + Pack Date: 17/09/2026 + Time: 14:46:10 + This product meets export quality specifications + Signature: + Total 30 + JA 40595983 JA 40595983 JA 40595983 + 20 20 20 20 + "#; + + #[test] + fn scopes_the_two_column_card_inside_the_full_print_sheet() { + let scoped = scope_card_region(WHOLE_SHEET); + assert!(scoped.contains("ORIGIN")); + assert!(scoped.contains("Grower")); + assert!(scoped.contains("Total")); + assert!(!scoped.contains("20 JA 40595983")); + assert!(!scoped.contains("20 20 20 20")); + + let snapshot = parse_pallet_snapshot(WHOLE_SHEET, "40595983"); + assert_eq!(snapshot.origin.as_deref(), Some("NZ")); + assert_eq!(snapshot.variety.as_deref(), Some("Hass")); + assert_eq!(snapshot.brand.as_deref(), Some("NZAG")); + assert_eq!(snapshot.class.as_deref(), Some("CLASS 3")); + assert_eq!(snapshot.base.as_deref(), Some("CHEP")); + assert_eq!(snapshot.pack.as_deref(), Some("B37")); + assert_eq!(snapshot.grower.as_deref(), Some("89930")); + assert_eq!(snapshot.packrun.as_deref(), Some("89930/16/17/26")); + assert_eq!(snapshot.size.as_deref(), Some("20")); + assert_eq!(snapshot.qty.as_deref(), Some("30")); + assert_eq!(snapshot.total.as_deref(), Some("30")); + } + #[test] fn parses_export_card_fields() { let snapshot = parse_pallet_snapshot(CARD, "40595983"); diff --git a/src-tauri/tauri.conf.json b/src-tauri/tauri.conf.json index 9326a77..c8c9bb6 100644 --- a/src-tauri/tauri.conf.json +++ b/src-tauri/tauri.conf.json @@ -1,7 +1,7 @@ { "$schema": "https://schema.tauri.app/config/2", "productName": "FieldLens Print", - "version": "0.1.20", + "version": "0.1.21", "identifier": "dev.arrowstack.fieldlens.print", "build": { "beforeDevCommand": "npm run dev", diff --git a/src/main.ts b/src/main.ts index 1293be7..f530afc 100644 --- a/src/main.ts +++ b/src/main.ts @@ -141,7 +141,7 @@ let config: AppConfig let jobs: Job[] = [] let status: Status = { running: false, mode: 'raw-proxy', pending: 0, jobs: 0 } let loginTimer: number | undefined -let currentVersion = '0.1.20' +let currentVersion = '0.1.21' let bundleType: BundleType | null = null let availableUpdate: Update | null = null let availableManualUpdate: ManualUpdate | null = null