# 09 - Vendor BOM ## Storage contract Vendor BOM is stored in `local_configurations.vendor_spec` and synced with `qt_configurations.vendor_spec`. Each row uses this canonical shape: ```json { "sort_order": 10, "vendor_partnumber": "ABC-123", "quantity": 2, "description": "row description", "unit_price": 4500.0, "total_price": 9000.0, "lot_mappings": [ { "lot_name": "LOT_A", "quantity_per_pn": 1 } ] } ``` Rules: - `lot_mappings[]` is the only persisted PN -> LOT mapping contract; - QuoteForge does not use legacy BOM tables; - apply flow rebuilds cart rows from `lot_mappings[]`. ## Partnumber books Partnumber books are pull-only snapshots from PriceForge. Local tables: - `local_partnumber_books` - `local_partnumber_book_items` Server tables: - `qt_partnumber_books` - `qt_partnumber_book_items` Resolution flow: 1. load the active local book; 2. find `vendor_partnumber`; 3. copy `lots_json` into `lot_mappings[]`; 4. keep unresolved rows editable in the UI. ## CFXML import `POST /api/projects/:uuid/vendor-import` imports one vendor workspace into an existing project. Rules: - accepted file field is `file`; - maximum file size is `1 GiB`; - one `ProprietaryGroupIdentifier` becomes one QuoteForge configuration; - software rows stay inside their hardware group and never become standalone configurations; - primary group row is selected structurally, without vendor-specific SKU hardcoding; - imported configuration order follows workspace order. Imported configuration fields: - `name` from primary row `ProductName` - `server_count` from primary row `Quantity` - `server_model` from primary row `ProductDescription` - `article` or `support_code` from `ProprietaryProductIdentifier` Imported BOM rows become `vendor_spec` rows and are resolved through the active local partnumber book when possible.