Skip to content

Commit 7a11787

Browse files
committed
Require 100 stock for small generics to consider "plenty available"
1 parent 2756617 commit 7a11787

File tree

1 file changed

+58
-17
lines changed

1 file changed

+58
-17
lines changed

crates/pcb-sch/src/bom_table.rs

Lines changed: 58 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use std::io::{self, Write};
33
use comfy_table::{Cell, Color, Table};
44
use terminal_hyperlink::Hyperlink as _;
55

6-
use crate::{AvailabilityData, Bom};
6+
use crate::{AvailabilityData, Bom, GenericComponent};
77

88
/// Sourcing status for component availability
99
enum 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
1630
fn 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

Comments
 (0)