l-addac-price-list-convert
l-addac-price-list-convert
Convert an ADDAC System retail pricelist PDF/HTML into structured JSON for the ADDAC Order Calculator app.
Usage
/l-addac-price-list-convert <path-to-pdf-or-html>
The source file should be an ADDAC System Retail Pricelist (PDF or HTML conversion). If given a PDF, use the Read tool to extract its contents. If the PDF is not readable, convert it to HTML first (e.g., via pnpm dlx pdf-to-html or similar) and save to __inbox/.
Steps
-
Read the source file using the Read tool. For large files, read in chunks.
-
Identify all sections by their headings. The pricelist is organized into:
- Module sections (under “STANDALONE” and “MODULES” headings)
- Frame sections (under “FRAMES & 19” RACK UTILITIES” heading)
- Accessory sections (under “ACCESSORIES & OTHER” heading)
-
Extract all product items from each table. Each row contains:
- SKU (first column)
- Name (second column)
- Price columns (varies by section type, see below)
- MSRP (last column)
-
Map discount tiers per section type:
Modules (discountType: “modules”)
5 price columns:
lt3(<3, 15% off),gte3(>=3, 20%),gte5(>=5, 23%),gte7(>=7, 26%),gte10(>=10, 30%)Applies to sections:
standalone- “STANDALONE”addac10x- “ADDAC10X Series”addac20x- “ADDAC20X Series”addac30x- “ADDAC30X Series”addac40x- “ADDAC40X Series”addac50x- “ADDAC50X Series”addac60x- “ADDAC60X Series”addac70x- “ADDAC70X Series”addac80x- “ADDAC80X Series”addac90x- “ADDAC90X Series”
Frames (discountType: “frames”)
2 price columns:
lt5(<5, 10% off),gte5(>=5, 13%)Applies to sections:
frames-busboards- “Busboards”frames-portable- “Portable Frames”frames-flat- “Flat Frames”frames-tabletop- “Tabletop Frames”frames-monster- “Monster Frames”frames-wheeled-carts- “Wheeled Carts”frames-rack-3u- ‘19” Rack 3U’frames-rack-utilities- “Rack Utilities”
Accessories (discountType: “accessories”)
2 price columns:
lt3(<3, 10% off),gte3(>=3, 15%)Applies to sections:
accessories- “Accessories”accessories-stands- “Stands”
Cable Holders (discountType: “cable-holder”)
2 price columns:
lt3(<3, 15% off),gte3(>=3, 20%)Applies to sections:
accessories-cable-holder- “Cable Holders”
-
Parse prices as numbers. Strip the currency symbol (e.g., “€252.00” -> 252.00). Remove comma separators (e.g., “€1,258.00” -> 1258.00).
-
Mark discontinued items with
"discontinued": true. Look for the CSS classdiscontinuedor “(DISCONTINUED …)” in the name. Extract the discontinuation note into thenotesfield and remove it from thename. -
Write the output to:
sub-packages/addac-order/src/data/addac-products.json
Output JSON Schema
type DiscountType = 'modules' | 'frames' | 'accessories' | 'cable-holder';
interface ModulePrices {
lt3: number; // <3 individual (15% off MSRP)
gte3: number; // >=3 (20%)
gte5: number; // >=5 (23%)
gte7: number; // >=7 (26%)
gte10: number; // >=10 (30%)
}
interface FramePrices {
lt5: number; // <5 individual (10% off)
gte5: number; // >=5 (13% off)
}
interface AccessoryPrices {
lt3: number; // <3 (10% off)
gte3: number; // >=3 (15% off)
}
interface CableHolderPrices {
lt3: number; // <3 (15% off)
gte3: number; // >=3 (20% off)
}
interface ProductItem {
sku: string;
name: string;
msrp: number;
prices: ModulePrices | FramePrices | AccessoryPrices | CableHolderPrices;
discontinued?: boolean;
notes?: string;
}
interface Section {
id: string; // kebab-case slug
name: string; // display name
discountType: DiscountType;
items: ProductItem[];
}
interface ProductData {
source: string; // e.g. "ADDAC System Retail Pricelist - February 2026"
generatedAt: string; // ISO date string
sections: Section[];
}
PDF Quirks
- Module tables have 8 columns: SKU, Name, 5 price tiers, MSRP
- Frame/accessory/cable-holder tables have 5 columns: SKU, Name, 2 price tiers, MSRP
- The ADDAC90X series appears twice: once under Modules (power delay modules) and once under Frames (busboards). They are different products
- Cable Holders have their own discount structure (15%/20%) distinct from other accessories (10%/15%)
- Stands use the accessories discount type (10%/15%), not frames
- Some SKUs contain spaces (e.g., “ADDAC814 JACKS+CONTROLS”, “ADDAC901M 15U”)
- Product names may contain HTML entities in source (& -> &, > -> >)
- Discontinued items may have “(DISCONTINUED <date>)” appended to their name - extract this to
notesand clean the name
Verification
After generating, verify:
- Total section count matches expected (currently 21)
- Total item count matches the source (currently 145)
- Discontinued items are correctly flagged
- Price values are numbers, not strings
- Each section has the correct discountType and price field structure
Step 8: Check for missing product URLs
After writing addac-products.json, check which SKUs are missing from the URL mapping:
- Read
src/data/addac-urls.json(the SKU → official product page URL mapping) - Compare all SKUs in the newly written
sub-packages/addac-order/src/data/addac-products.jsonagainst the URL map - If any SKUs are missing from
addac-urls.json:- List the missing SKUs
- Web-search for each missing SKU:
site:addacsystem.com {SKU}(e.g.site:addacsystem.com ADDAC999) - Find the official product page URL on
https://www.addacsystem.com/ - Add any found URLs to
src/data/addac-urls.json, keeping the JSON alphabetically sorted by SKU
- If no SKUs are missing, confirm: “All SKUs have URL mappings.”
This ensures addac-urls.json stays up to date whenever new products appear in the pricelist.