Data Seeding#
Atomberg receives costing sheets from suppliers as Excel files. Each supplier has their own format. We have management commands that read these files and load the data into the database.
How It Works (The Big Picture)#
Excel file from supplier
↓
Management command parses it
↓
Creates/finds: Supplier, Part, PartSupplier
↓
Creates: Values (prices, weights, costs)
↓
Creates: ViewTemplate + ViewTemplateValues (display layout)
Every command:
Reads the Excel file using
openpyxlParses part codes, names, categories, and numeric values
Creates database records (idempotent — safe to re-run)
Links formula values to their dependencies
Builds view templates for the frontend
Commands by Category#
Plastic Parts#
Command: bulk_upload_plastic
Files: 14 supplier sheets in _raw_data/plastic/
Format: Flat table — one row per part, columns for each cost component
# Import all 14 files
python manage.py bulk_upload_plastic --dir backend/_raw_data/plastic/
# Import a single file
python manage.py bulk_upload_plastic --file backend/_raw_data/plastic/Apex_...xlsx
# Preview without writing to DB
python manage.py bulk_upload_plastic --dir backend/_raw_data/plastic/ --dry-run
What it imports: 407 parts across 14 suppliers with ~35 cost components each (gross weight, RM rate, process cost, BOP cost, freight, PO price, etc.)
Smart features:
Auto-detects sheet name (case-insensitive: “New Format”, “NEW FORMAT”, “NEW SUMMARY”)
Auto-detects header row (varies by supplier: row 5, 7, or 8)
Auto-detects supplier info from rows 1-4 (checks both col A and col B)
Auto-generates supplier codes when missing
Handles header typos (for example, “Mould Maintanance” →
mouldMaintenance)Links formula values (for example,
existingRmCost = (rmRate*(1-mbPercent)+mbCost)*grossWt/1000)
Supplier |
Code |
Parts |
|---|---|---|
Apex Engineers |
602035 |
32 |
Atharva Polymer |
602072 |
48 |
Future Finishers |
603276 |
9 |
Microplast |
MICROPLAST |
20 |
Megaklc |
MEGAKLC |
18 |
PG Electroplast |
602741 |
59 |
Pro-Mould |
601555 |
24 |
Pune Polymer |
602480 |
141 |
Ramashri |
601592 |
64 |
Shree Varad |
601244 |
37 |
Sunshine |
603720 |
1 |
EPS (Expanded Polystyrene)#
Command: bulk_upload_eps
File: _raw_data/eps/EPS costing.xlsx
Format: 6 supplier sheets in one workbook, each with different column layouts
python manage.py bulk_upload_eps
python manage.py bulk_upload_eps --dry-run
What it imports: 44 parts across 5 suppliers (Styrotech, Kamaksha, KK Nag, Stypack, Hakimuddin). Skips Thermofoam (summary-only sheet).
Special handling: KK Nag has hierarchical rows (Model → Top/Bottom) with no explicit part codes — codes are auto-generated like GV3-TOP, GV3-BOTTOM.
Corrugated Boxes (Boxline)#
Command: bulk_upload_boxline
File: _raw_data/boxline-foam/Boxline- Apr Cost (Ok).xlsx
Format: Flat table with 94 box products
python manage.py bulk_upload_boxline
python manage.py bulk_upload_boxline --dry-run
What it imports: 94 box configurations with dimensions (L/W/H), ply count, flute types, and final box cost. Categories include “RSC Box” and “Blade Box”.
Foam (Kamaksha)#
Command: bulk_upload_foam
File: _raw_data/foam/Costing - Kamaksha Foam (Ok).xlsx
Format: Transposed — part codes are columns, cost components are rows (opposite of plastic!)
python manage.py bulk_upload_foam
python manage.py bulk_upload_foam --dry-run
What it imports: 12 foam packaging parts with 20 cost components each (dimensions, sheet cost, labor, overhead, rejection, ICC, profit, transport).
Tape (Tackon)#
Command: bulk_upload_tape
File: _raw_data/tape/Tackon Tape costing.xlsx
Format: “Cost Impact” summary sheet with 6 BOPP tape products
python manage.py bulk_upload_tape
python manage.py bulk_upload_tape --dry-run
What it imports: 6 tape products with current price, revised price, April volume, and cost impact.
Polybag & Foam Bag (Wrybillpack)#
Command: bulk_upload_polybag
File: _raw_data/polybag/B2C Wrybillpack - Polybag & foam bag costing.xlsx
Format: Two sheets — foam bags and polybags with dimensions and pricing
python manage.py bulk_upload_polybag
python manage.py bulk_upload_polybag --dry-run
What it imports: 3 foam bags + 1 polybag with dimensions, material weights, and cost breakdowns.
Washer (Chinar International)#
Command: bulk_upload_washer
File: _raw_data/washer/M8 & M3 Washer Updated Cost Sheets.xlsx
Format: Vertical layout — 1 part per sheet, cost components in specific rows
python manage.py bulk_upload_washer
python manage.py bulk_upload_washer --dry-run
What it imports: 2 washer parts (M8 and M3) with weights, material rates, and cost per piece.
Shaft (ATPL)#
Command: bulk_upload_atpl
File: _raw_data/atpl/ATPL Working.xlsx
Format: Vertical layout with 2 suppliers side-by-side per part
python manage.py bulk_upload_atpl
python manage.py bulk_upload_atpl --dry-run
What it imports: 2 shaft parts (Aris and Panda), each with 2 suppliers (Moon Engitech and ATPL) — so 4 PartSupplier records total. Compares material costs, process costs, and overheads.
Casting (Elicast)#
Command: bulk_upload_casting
File: _raw_data/casting/Costing Sample_Castings.xlsx
Format: Multi-sheet vertical breakdown for a single cast part
python manage.py bulk_upload_casting
python manage.py bulk_upload_casting --dry-run
What it imports: 1 casting part (A428502 - Canary Top Machined) with ~41 cost components scanned from the “Part Cost” sheet (RM cost, die casting, machining, buffing, overhead, profit, etc.)
Database Totals (After All Imports)#
Metric |
Count |
|---|---|
Parts |
567 |
PartSuppliers |
634 |
Values |
16,289 |
ViewTemplates |
623 |
Suppliers |
26+ |
Categories |
40+ |
Adding New Supplier Data#
When a new costing sheet arrives:
Check the format — Does it match an existing command’s format?
If yes: Place the file in the right
_raw_data/folder and run the commandIf no: Create a new management command following the same patterns
Always dry-run first: Use
--dry-runto preview what will be createdSafe to re-run: All commands are idempotent (they skip existing records)
Key patterns for new commands:#
# Supplier lookup (code is NOT unique)
supplier = Supplier.objects.filter(code=code).first()
# PartSupplier lookup (no unique constraint)
ps = PartSupplier.objects.filter(part=part, supplier=supplier).first()
# ValueHead, CategoryType, Part (have unique constraints)
head, created = ValueHead.objects.get_or_create(name=name, defaults={...})