@@ -3,7 +3,7 @@ use std::io::{self, Write};
33use comfy_table:: { Cell , Color , Table } ;
44use terminal_hyperlink:: Hyperlink as _;
55
6- use crate :: { AvailabilityData , Bom } ;
6+ use crate :: { AvailabilityData , Bom , GenericComponent } ;
77
88/// Sourcing status for component availability
99enum SourcingStatus {
@@ -12,32 +12,59 @@ enum SourcingStatus {
1212 Good , // Green - plenty available
1313}
1414
15+ /// Check if this is a small generic passive requiring higher stock threshold
16+ fn is_small_generic_passive (
17+ generic_data : Option < & GenericComponent > ,
18+ package : Option < & str > ,
19+ ) -> bool {
20+ let is_generic_passive = matches ! (
21+ generic_data,
22+ Some ( GenericComponent :: Resistor ( _) | GenericComponent :: Capacitor ( _) )
23+ ) ;
24+ let is_small_package = matches ! ( package, Some ( "0201" | "0402" | "0603" ) ) ;
25+
26+ is_generic_passive && is_small_package
27+ }
28+
1529/// Determine sourcing status from availability data
1630fn get_sourcing_status (
1731 stock_data : Option < & AvailabilityData > ,
1832 mpn : & str ,
1933 manufacturer : & str ,
2034 qty : usize ,
35+ generic_data : Option < & GenericComponent > ,
36+ package : Option < & str > ,
2137) -> SourcingStatus {
22- if let Some ( avail) = stock_data {
23- let stock = avail. stock_total ;
24- let has_mpn_and_mfr = !mpn. is_empty ( ) && !manufacturer. is_empty ( ) ;
25- let qty_for_20_boards = ( qty as i32 ) * 20 ;
26-
27- if stock == 0 {
28- SourcingStatus :: None
29- } else if !has_mpn_and_mfr || stock < qty_for_20_boards {
30- SourcingStatus :: Limited
31- } else {
32- SourcingStatus :: Good
33- }
34- } else {
38+ let Some ( avail) = stock_data else {
3539 // No availability data - fallback to basic check
36- if mpn. is_empty ( ) || manufacturer. is_empty ( ) {
40+ return if mpn. is_empty ( ) || manufacturer. is_empty ( ) {
3741 SourcingStatus :: None
3842 } else {
3943 SourcingStatus :: Good
40- }
44+ } ;
45+ } ;
46+
47+ let stock = avail. stock_total ;
48+ if stock == 0 {
49+ return SourcingStatus :: None ;
50+ }
51+
52+ let has_mpn_and_mfr = !mpn. is_empty ( ) && !manufacturer. is_empty ( ) ;
53+ if !has_mpn_and_mfr {
54+ return SourcingStatus :: Limited ;
55+ }
56+
57+ // Small generic passives need ≥100 stock, others need qty × 20
58+ let required_stock = if is_small_generic_passive ( generic_data, package) {
59+ 100
60+ } else {
61+ ( qty as i32 ) * 20
62+ } ;
63+
64+ if stock >= required_stock {
65+ SourcingStatus :: Good
66+ } else {
67+ SourcingStatus :: Limited
4168 }
4269}
4370
@@ -183,7 +210,21 @@ impl Bom {
183210 None
184211 } ;
185212
186- let sourcing_status = get_sourcing_status ( stock_data, mpn, manufacturer, qty) ;
213+ // Get generic_data and package for sourcing status
214+ let generic_data = entry
215+ . get ( "generic_data" )
216+ . and_then ( |gd| serde_json:: from_value :: < GenericComponent > ( gd. clone ( ) ) . ok ( ) ) ;
217+
218+ let package = entry. get ( "package" ) . and_then ( |p| p. as_str ( ) ) ;
219+
220+ let sourcing_status = get_sourcing_status (
221+ stock_data,
222+ mpn,
223+ manufacturer,
224+ qty,
225+ generic_data. as_ref ( ) ,
226+ package,
227+ ) ;
187228
188229 // Create qty cell
189230 let qty_cell = if is_dnp {
0 commit comments