Bulk APLT → Medusa Import
How It Works
Section titled “How It Works”The bulk import script (bulk_medusa_import.js) reads from magic_pim.aplt_products and inserts directly into the target Medusa database (magic_b2b_*). It populates all 9 tables that make up a complete Medusa product:
aplt_products (source) ↓product ← main product recordproduct_option ← "Kleur" option (one per product)product_option_value ← one per unique colorproduct_variant ← one per variant (with SKU)product_variant_option ← links variant ↔ option valueprice_set ← one per variantprice ← tiered price amounts (100/200/300/500/1000 qty)product_variant_price_set ← links variant ↔ price_setimage ← product images (optional)Everything runs inside one transaction per supplier — if anything fails, the entire supplier batch rolls back cleanly.
Supplier Grouping Logic
Section titled “Supplier Grouping Logic”Each supplier uses a different SKU structure. The script groups APLT rows into Medusa products using supplier-specific logic:
| Supplier | Base SKU (product) | Variant SKU | Example |
|---|---|---|---|
| Spranz (01) | Before first dot | variant_code | 101-05 / 101-05.001 |
| Langenberg (03) | sku as-is | variant_code | 10015 / 10015-01 |
| XD Connect (04) | sku as-is | variant_code | P308 / P308.399 |
| PF Concept (05) | sku as-is | variant_code | K0404 / K04041RM |
| MidOcean (06) | sku as-is | variant_code | AR1804 / AR1804-03 |
| Toppoint (07) | sku as-is | variant_code | LT87694 / LT87694-N2102 |
| NewWave (09) | sku as-is | variant_code | 027310 / 027310-55-5 |
Script Location & Usage
Section titled “Script Location & Usage”The script lives at /tmp/bulk_medusa_import.js and runs inside the backend container where the pg module is available.
# Copy into container (if not already there)docker cp /tmp/bulk_medusa_import.js magic_pim_backend_dev:/app/.medusa/server/
# Dry run — shows counts without touching datadocker exec magic_pim_backend_dev sh -c \ "cd /app/.medusa/server && node bulk_medusa_import.js 06 --dry-run"
# Run for a single supplierdocker exec magic_pim_backend_dev sh -c \ "cd /app/.medusa/server && node bulk_medusa_import.js 06"
# Run for all suppliersdocker exec magic_pim_backend_dev sh -c \ "cd /app/.medusa/server && node bulk_medusa_import.js all"Supplier codes
Section titled “Supplier codes”| Code | Supplier |
|---|---|
01 | Spranz |
03 | Langenberg |
04 | XD Connect |
05 | PF Concept |
06 | MidOcean |
07 | Toppoint |
09 | NewWave |
all | All of the above |
Always Backup First
Section titled “Always Backup First”# Backupdocker exec magic_pim_postgres_dev pg_dump -U postgres magic_b2b_development \ | gzip > /mnt/data/backups/magic_b2b_development_$(date +%Y%m%d_%H%M%S).sql.gz
# Restore if neededgunzip -c /mnt/data/backups/magic_b2b_development_YYYYMMDD_HHMMSS.sql.gz \ | docker exec -i magic_pim_postgres_dev psql -U postgres magic_b2b_developmentDry Run Results (2026-03-12)
Section titled “Dry Run Results (2026-03-12)”Executed before the actual import. Existing records are detected by handle and skipped automatically.
| Supplier | APLT Rows | Products | New Products | Variants | Prices | Already in Medusa |
|---|---|---|---|---|---|---|
| Spranz (01) | 760 | 491 | 38 | 52 | 250 | 454 |
| Langenberg (03) | 244 | 244 | 0 | — | — | 244 ✅ |
| XD Connect (04) | 11,526 | 940 | 116 | 3,604 | 6,268 | 2,610 |
| PF Concept (05) | 19,431 | 2,498 | 2,498 | 19,431 | 19,431 | 0 |
| MidOcean (06) | 14,496 | 2,443 | 2,443 | 14,496 | 14,496 | 0 |
| Toppoint (07) | 5,856 | 1,842 | 1,842 | 5,856 | 6,426 | 0 |
| NewWave (09) | 26,239 | 959 | 959 | 26,239 | 93,723 | 0 |
| Total | 78,552 | 9,417 | 7,896 | 69,678 | 140,594 |
Actual Import Results (2026-03-12)
Section titled “Actual Import Results (2026-03-12)”Run after dry run. The script skips handles that already exist in Medusa globally (all suppliers) and post-verifies variant inserts to handle unique constraint conflicts on barcode/EAN.
| Supplier | Products Inserted | Variants Inserted | Prices Inserted | Skipped (conflicts) |
|---|---|---|---|---|
| Spranz (01) | 38 | 52 | 250 | — |
| Langenberg (03) | 0 | — | — | All already in Medusa |
| XD Connect (04) | 114 | 1,786 | 2,038 | 577 variants (barcode/EAN conflict) |
| PF Concept (05) | 2,491 | 19,405 | Fixed: barcode nulled for supplier 05 — all variants now inserted | |
| MidOcean (06) | 2,443 | 14,492 | 14,492 | 4 variants (barcode conflict) |
| Toppoint (07) | 1,842 | 5,856 | 6,426 | — |
| NewWave (09) | 959 | 26,239 | 93,723 | — |
| Total new | 5,887 | 67,830 | 136,334 |
Medusa dev totals after import + PF Concept fix: 11,195 products · 72,336 variants · 146,728 prices
What the Script Does NOT Do
Section titled “What the Script Does NOT Do”The following are handled separately or not yet implemented:
- Category links —
product_category_productrecords are not inserted. Run a separate category sync after the bulk import. - Medusa product sync hash — Products inserted this way won’t have a
sync_hashin metadata. The next run ofmedusa-syncwill re-sync and update them via the API path. - Tenant databases — This script targets one database at a time. To import into Brinxx or other tenants, change
DEV_CONFIG.databasein the script. - Update existing — The script only inserts new products (skipped by handle). To update existing ones, delete them first or use
medusa-syncfor updates.
Troubleshooting
Section titled “Troubleshooting””⚠ N variants skipped (unique constraint conflicts)”
Normal — the script post-verifies which variants were actually inserted and automatically filters product_variant_option, price_set, price, and product_variant_price_set to only reference inserted variants. No action needed unless the count seems unexpectedly high.
Transaction rolled back Check the error message. Most FK constraint issues were fixed in the 2026-03-12 revision. Common remaining causes: schema mismatch (wrong Medusa version), or a column type error in the insert values.
“relation does not exist”
You’re targeting the wrong database. Verify the DEV_CONFIG.database value matches the container’s actual DB name.