Coverage for simulate_transactions.py: 0%
226 statements
« prev ^ index » next coverage.py v7.16.0, created at 2026-10-17 16:50 +0800
« prev ^ index » next coverage.py v7.16.0, created at 2026-10-17 16:50 +0800
1"""
2FUDO ERP - Comprehensive Transaction Simulation
3Simulates the full accounting cycle: chart of accounts, products, invoices, payments, shipments, etc.
4Run from: d:\FUDO\erp\apps\backend
5Usage: python manage.py shell < simulate_transactions.py
6"""
7import os
8import sys
9from decimal import Decimal
10from datetime import date, timedelta
12# Setup
13sys.path.insert(0, 'd:/FUDO/erp/apps/backend')
14os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'config.settings')
16import django
17django.setup()
19from django.utils import timezone
20from modules.authentication.models import User
21from modules.erp.models import (
22 Account, JournalEntry, JournalItem, Product, Warehouse,
23 StockMove, Invoice, InvoiceLine, Shipment
24)
25from modules.erp.services import ERPService
26from modules.crm.models import Company, Contact, Deal, Pipeline, Stage
27from modules.logistics.models import WarehouseReceipt, ShippingQuote, FreightQuote
28from modules.hr.models import Employee, Leave, PayrollRun, Payslip
29from modules.trucking.models import Vehicle, Driver, FuelLog, Trip
30from modules.customs.models import CustomsEntry, DutyRate
32# ── Get current user & tenant ─────────────────────────────────────────────────
33user = User.objects.filter(email__iexact='jusmedina@gmail.com').first() or \
34 User.objects.filter(email__iexact='admin@fudo.local').first() or \
35 User.objects.filter(is_superuser=True).first()
37if not user:
38 print("❌ No user found. Run Django first and create a user.")
39 sys.exit(1)
41tenant_id = user.tenant_id
42print(f"✅ User: {user.email} | Tenant: {tenant_id}")
44# ── 1. Chart of Accounts ────────────────────────────────────────────────────
45print("\n" + "="*70)
46print("1. CHART OF ACCOUNTS")
47print("="*70)
48ERPService.get_or_create_chart_of_accounts(tenant_id)
49accounts = Account.objects.filter(tenant_id=tenant_id).order_by('code')
50for a in accounts:
51 print(f" [{a.code}] {a.name:<35} {a.type}")
52print(f" Total accounts: {accounts.count()}")
54# ── 2. Products ──────────────────────────────────────────────────────────────
55print("\n" + "="*70)
56print("2. PRODUCTS / INVENTORY")
57print("="*70)
58product_data = [
59 ("SKU001", "International Freight Service", "Service", Decimal("1000.00"), Decimal("1500.00"), Decimal("0.00")),
60 ("SKU002", "Customs Brokerage Service", "Service", Decimal("500.00"), Decimal("800.00"), Decimal("0.00")),
61 ("SKU003", "Warehousing (per pallet/month)", "Service", Decimal("50.00"), Decimal("100.00"), Decimal("0.00")),
62 ("SKU004", "Trucking - Local Delivery", "Service", Decimal("200.00"), Decimal("350.00"), Decimal("0.00")),
63 ("SKU005", "Cargo Insurance", "Service", Decimal("100.00"), Decimal("150.00"), Decimal("12.00")),
64 ("SKU006", "Pharmaceutical Freight (Air)", "Service", Decimal("2000.00"), Decimal("3500.00"), Decimal("0.00")),
65 ("SKU007", "Hazardous Materials Handling", "Service", Decimal("500.00"), Decimal("900.00"), Decimal("0.00")),
66 ("SKU008", "Cold Chain Logistics", "Service", Decimal("800.00"), Decimal("1200.00"), Decimal("0.00")),
67]
68for sku, name, cat, cost, sell, tax in product_data:
69 p, created = Product.objects.get_or_create(
70 tenant_id=tenant_id, sku=sku,
71 defaults=dict(name=name, category=cat, cost_price=cost, selling_price=sell, tax_rate=tax)
72 )
73 status = "✅ Created" if created else "🔄 Exists"
74 print(f" {status}: {sku} - {name} | Sell: {sell} | Tax: {tax}%")
75print(f" Total products: {Product.objects.filter(tenant_id=tenant_id).count()}")
77# ── 3. Warehouse ─────────────────────────────────────────────────────────────
78print("\n" + "="*70)
79print("3. WAREHOUSES")
80print("="*70)
81warehouses_data = [
82 ("WH-MNL-01", "Manila Main Warehouse", "Metro Manila, Philippines"),
83 ("WH-宿雾-01", "Cebu Logistics Hub", "Cebu, Philippines"),
84 ("WH-DVO-01", "Davao Distribution Center", "Davao, Philippines"),
85]
86for code, name, addr in warehouses_data:
87 w, created = Warehouse.objects.get_or_create(
88 tenant_id=tenant_id, code=code,
89 defaults=dict(name=name, address=addr, is_active=True)
90 )
91 status = "✅ Created" if created else "🔄 Exists"
92 print(f" {status}: [{code}] {name} - {addr}")
93print(f" Total warehouses: {Warehouse.objects.filter(tenant_id=tenant_id).count()}")
95# ── 4. Stock Moves ───────────────────────────────────────────────────────────
96print("\n" + "="*70)
97print("4. STOCK MOVES (Inventory)")
98print("="*70)
99wh_main = Warehouse.objects.filter(tenant_id=tenant_id, code='WH-MNL-01').first()
100products = list(Product.objects.filter(tenant_id=tenant_id)[:3])
101if wh_main and products:
102 for i, prod in enumerate(products):
103 sm, created = StockMove.objects.get_or_create(
104 tenant_id=tenant_id,
105 product=prod,
106 source_warehouse=None,
107 dest_warehouse=wh_main,
108 move_type='INCOMING',
109 reference_doc=f"INIT-STOCK-{prod.sku}",
110 defaults=dict(
111 quantity=Decimal(f"{100 + i * 50}"),
112 unit_cost=prod.cost_price,
113 )
114 )
115 status = "✅ Created" if created else "🔄 Exists"
116 print(f" {status}: {prod.sku} → {wh_main.code} | Qty: {sm.quantity} × {sm.unit_cost}")
117print(f" Total stock moves: {StockMove.objects.filter(tenant_id=tenant_id).count()}")
119# ── 5. Shipping & Freight Quotes ─────────────────────────────────────────────
120print("\n" + "="*70)
121print("5. SHIPPING & FREIGHT QUOTES")
122print("="*70)
123sq_data = [
124 dict(quote_number="SQ-2024-001", carrier="2GO", service_type="Sea Freight",
125 origin="Manila", destination="Cebu", weight_kg=Decimal("500.00"),
126 volume_m3=Decimal("2.00"), estimated_cost=Decimal("2500.00"),
127 currency="PHP", valid_until=date.today() + timedelta(days=14), status="PENDING"),
128 dict(quote_number="SQ-2024-002", carrier="LBC", service_type="Air Freight",
129 origin="Manila", destination="Davao", weight_kg=Decimal("50.00"),
130 volume_m3=Decimal("0.50"), estimated_cost=Decimal("4500.00"),
131 currency="PHP", valid_until=date.today() + timedelta(days=7), status="PENDING"),
132]
133for data in sq_data:
134 sq, created = ShippingQuote.objects.get_or_create(
135 tenant_id=tenant_id, quote_number=data['quote_number'],
136 defaults=dict(**data, is_active=True)
137 )
138 status = "✅ Created" if created else "🔄 Exists"
139 print(f" {status}: {sq.quote_number} | {sq.carrier} {sq.service_type} | {sq.origin} → {sq.destination} | ₱{sq.estimated_cost}")
141fq_data = [
142 dict(quote_number="FQ-2024-001", carrier="Philex", route="Manila-Cebu",
143 container_type="20ft", estimated_cost=Decimal("15000.00"),
144 currency="PHP", valid_until=date.today() + timedelta(days=10), status="PENDING"),
145 dict(quote_number="FQ-2024-002", carrier="G nucleotide", route="Manila-Davao",
146 container_type="40ft", estimated_cost=Decimal("28000.00"),
147 currency="PHP", valid_until=date.today() + timedelta(days=10), status="PENDING"),
148]
149for data in fq_data:
150 fq, created = FreightQuote.objects.get_or_create(
151 tenant_id=tenant_id, quote_number=data['quote_number'],
152 defaults=dict(**data, is_active=True)
153 )
154 status = "✅ Created" if created else "🔄 Exists"
155 print(f" {status}: {fq.quote_number} | {fq.carrier} {fq.container_type} | {fq.route} | ₱{fq.estimated_cost}")
157# ── 6. Shipments ─────────────────────────────────────────────────────────────
158print("\n" + "="*70)
159print("6. SHIPMENTS")
160print("="*70)
161shipment_data = [
162 dict(reference_number="SHP-INIT-001", shipment_type="IMPORT",
163 status="IN_TRANSIT", origin="Shanghai, China", destination="Manila, PH",
164 carrier="COSCO", estimated_arrival=date.today() + timedelta(days=14),
165 declared_value=Decimal("50000.00"), duty_amount=Decimal("5000.00"),
166 freight_amount=Decimal("2500.00"), currency="USD"),
167 dict(reference_number="SHP-INIT-002", shipment_type="EXPORT",
168 status="DELIVERED", origin="Manila, PH", destination="Los Angeles, USA",
169 carrier="Maersk", estimated_arrival=date.today() - timedelta(days=2),
170 declared_value=Decimal("75000.00"), duty_amount=Decimal("0.00"),
171 freight_amount=Decimal("5000.00"), currency="USD"),
172 dict(reference_number="SHP-INIT-003", shipment_type="TRANSIT",
173 status="PENDING", origin="Hong Kong", destination="Manila, PH",
174 carrier="Yang Ming", estimated_arrival=date.today() + timedelta(days=7),
175 declared_value=Decimal("30000.00"), duty_amount=Decimal("3000.00"),
176 freight_amount=Decimal("1800.00"), currency="USD"),
177]
178for data in shipment_data:
179 s, created = Shipment.objects.get_or_create(
180 tenant_id=tenant_id, reference_number=data['reference_number'],
181 defaults=dict(**data)
182 )
183 status = "✅ Created" if created else "🔄 Exists"
184 print(f" {status}: {s.reference_number} | {s.shipment_type} | {s.status} | {s.origin} → {s.destination}")
185print(f" Total shipments: {Shipment.objects.filter(tenant_id=tenant_id).count()}")
187# ── 7. CRM - Companies, Contacts, Deals ─────────────────────────────────────
188print("\n" + "="*70)
189print("7. CRM - COMPANIES, CONTACTS & DEALS")
190print("="*70)
191companies_data = [
192 ("JLM Brokerage Corp", "jlm-brokerage.com", "Logistics", "+63-2-8123-4567", "Metro Manila"),
193 ("Medina Pharma Inc", "medina-pharma.com", "Pharmaceutical", "+63-2-8123-4568", "Makati City"),
194 ("Global Freight Solutions", "globalfreight.com", "Freight Forwarding", "+1-212-555-0100", "New York, USA"),
195 ("Pacific Trading Co", "pacifictrading.com", "Trading", "+65-6324-5678", "Singapore"),
196 ("Kintampo Logistics", "kintampo-logistics.com", "Logistics", "+233-32-123-4567", "Ghana"),
197]
198for name, domain, industry, phone, city in companies_data:
199 c, created = Company.objects.get_or_create(
200 tenant_id=tenant_id, name=name,
201 defaults=dict(domain=domain, industry=industry, phone=phone, city=city, country='Philippines')
202 )
203 status = "✅ Created" if created else "🔄 Exists"
204 print(f" {status}: {c.name} | {c.industry} | {c.city}")
206# Get or create pipeline
207pipeline, _ = Pipeline.objects.get_or_create(
208 tenant_id=tenant_id, name="Sales Pipeline",
209 defaults=dict(description="Default sales pipeline", is_active=True)
210)
211stage_won, _ = Stage.objects.get_or_create(
212 tenant_id=tenant_id, pipeline=pipeline, name="Won",
213 defaults=dict(order=1, probability=Decimal("100.00"))
214)
215stage_open, _ = Stage.objects.get_or_create(
216 tenant_id=tenant_id, pipeline=pipeline, name="Qualified",
217 defaults=dict(order=2, probability=Decimal("50.00"))
218)
220companies = list(Company.objects.filter(tenant_id=tenant_id)[:3])
221deals_data = [
222 ("JLM - Q4 Freight Contract", Decimal("150000.00"), "USD", stage_won, companies[0] if companies else None),
223 ("Medina Pharma - Cold Chain Setup", Decimal("85000.00"), "USD", stage_open, companies[1] if len(companies) > 1 else None),
224 ("Global Freight - Customs Brokerage", Decimal("45000.00"), "PHP", stage_won, companies[2] if len(companies) > 2 else None),
225]
226for title, value, curr, stage, company in deals_data:
227 d, created = Deal.objects.get_or_create(
228 tenant_id=tenant_id, title=title,
229 defaults=dict(value=value, currency=curr, status=stage.name,
230 pipeline=pipeline, stage=stage, company=company,
231 assigned_to=user, expected_close_date=date.today() + timedelta(days=30))
232 )
233 status = "✅ Created" if created else "🔄 Exists"
234 print(f" {status}: {d.title} | ₱{d.value} {d.currency} | {d.status}")
235print(f" Total deals: {Deal.objects.filter(tenant_id=tenant_id).count()}")
237# ── 8. Invoices ─────────────────────────────────────────────────────────────
238print("\n" + "="*70)
239print("8. INVOICES (Double-Entry Journal Entries)")
240print("="*70)
242# Build invoice payloads
243class InvoiceLinePayload:
244 def __init__(self, product_id, description, quantity, unit_price, tax_rate):
245 self.product_id = product_id
246 self.description = description
247 self.quantity = quantity
248 self.unit_price = unit_price
249 self.tax_rate = tax_rate
251class InvoicePayload:
252 def __init__(self, customer_name, customer_email, deal_id, due_date, currency, notes, lines):
253 self.customer_name = customer_name
254 self.customer_email = customer_email
255 self.deal_id = deal_id
256 self.due_date = due_date
257 self.currency = currency
258 self.notes = notes
259 self.terms = "Net 30"
260 self.lines = lines
262invoices_to_create = [
263 InvoicePayload(
264 customer_name="JLM Brokerage Corp",
265 customer_email="billing@jlm-brokerage.com",
266 deal_id=None,
267 due_date=date.today() + timedelta(days=30),
268 currency="PHP",
269 notes="Q4 International Freight Services",
270 lines=[
271 InvoiceLinePayload(products[0].id, "International Freight Service - Manila Hub", Decimal("2.00"), Decimal("1500.00"), Decimal("12.00")),
272 InvoiceLinePayload(products[1].id, "Customs Brokerage Service", Decimal("1.00"), Decimal("800.00"), Decimal("12.00")),
273 ]
274 ),
275 InvoicePayload(
276 customer_name="Medina Pharma Inc",
277 customer_email="accounts@medina-pharma.com",
278 deal_id=None,
279 due_date=date.today() + timedelta(days=30),
280 currency="PHP",
281 notes="Cold Chain Logistics - October 2024",
282 lines=[
283 InvoiceLinePayload(products[7].id, "Cold Chain Logistics Service", Decimal("5.00"), Decimal("1200.00"), Decimal("0.00")),
284 InvoiceLinePayload(products[4].id, "Cargo Insurance", Decimal("1.00"), Decimal("150.00"), Decimal("12.00")),
285 ]
286 ),
287]
288for inv_payload in invoices_to_create:
289 inv, created = Invoice.objects.get_or_create(
290 tenant_id=tenant_id,
291 invoice_number=f"INV-SIM-{invoices_to_create.index(inv_payload)+1:03d}",
292 defaults=dict(
293 customer_name=inv_payload.customer_name,
294 customer_email=inv_payload.customer_email,
295 deal_id=inv_payload.deal_id,
296 issue_date=date.today(),
297 due_date=inv_payload.due_date,
298 currency=inv_payload.currency,
299 subtotal=Decimal("0.00"), # computed in service
300 tax_total=Decimal("0.00"),
301 total_amount=Decimal("0.00"),
302 notes=inv_payload.notes,
303 terms=inv_payload.terms,
304 status="SENT",
305 )
306 )
307 if created:
308 # Manually compute lines since we're using get_or_create
309 for line in inv_payload.lines:
310 InvoiceLine.objects.create(
311 tenant_id=tenant_id,
312 invoice=inv,
313 product_id=line.product_id,
314 description=line.description,
315 quantity=line.quantity,
316 unit_price=line.unit_price,
317 tax_rate=line.tax_rate,
318 subtotal=line.quantity * line.unit_price,
319 tax_amount=(line.quantity * line.unit_price) * line.tax_rate / Decimal("100.00"),
320 total=(line.quantity * line.unit_price) * (Decimal("1.00") + line.tax_rate / Decimal("100.00")),
321 )
322 # Recompute totals
323 lines = InvoiceLine.objects.filter(invoice=inv)
324 inv.subtotal = sum(l.subtotal for l in lines)
325 inv.tax_total = sum(l.tax_amount for l in lines)
326 inv.total_amount = inv.subtotal + inv.tax_total
327 inv.save()
328 # Post journal
329 ERPService.post_invoice_journal(tenant_id, inv)
330 print(f" ✅ Created: INV-{inv.invoice_number} | {inv.customer_name} | ₱{inv.total_amount} | Status: {inv.status}")
331 else:
332 print(f" 🔄 Exists: INV-{inv.invoice_number} | {inv.customer_name} | ₱{inv.total_amount}")
334print(f" Total invoices: {Invoice.objects.filter(tenant_id=tenant_id).count()}")
335je_count = JournalEntry.objects.filter(tenant_id=tenant_id, reference_type='INVOICE').count()
336print(f" Total invoice journal entries: {je_count}")
338# ── 9. Record Payments ───────────────────────────────────────────────────────
339print("\n" + "="*70)
340print("9. PAYMENTS (Double-Entry Journal Entries)")
341print("="*70)
342invoices = Invoice.objects.filter(tenant_id=tenant_id, status__in=['SENT', 'PARTIALLY_PAID'])
343for inv in invoices:
344 # Record partial payment (50%)
345 payment_amount = inv.total_amount * Decimal("0.50")
346 try:
347 paid_inv = ERPService.record_payment(tenant_id, inv.id, payment_amount)
348 print(f" ✅ Payment recorded: INV-{inv.invoice_number} | ₱{payment_amount} paid | Status: {paid_inv.status}")
349 except Exception as e:
350 print(f" ⚠️ Payment failed: INV-{inv.invoice_number} | {e}")
352pay_je_count = JournalEntry.objects.filter(tenant_id=tenant_id, reference_type='PAYMENT').count()
353print(f" Total payment journal entries: {pay_je_count}")
355# ── 10. HR - Employees & Payroll ─────────────────────────────────────────────
356print("\n" + "="*70)
357print("10. HR - EMPLOYEES & PAYROLL")
358print("="*70)
359employees_data = [
360 ("Juan", "Dela Cruz", "juan.delacrux@fudo.local", "Logistics Manager", Decimal("75000.00"), "MONTHLY"),
361 ("Maria", "Santos", "maria.santos@fudo.local", "Operations Supervisor", Decimal("55000.00"), "MONTHLY"),
362 ("Carlos", "Mendoza", "carlos.mendoza@fudo.local", "Warehouse Lead", Decimal("40000.00"), "MONTHLY"),
363 ("Ana", "Reyes", "ana.reyes@fudo.local", "HR Coordinator", Decimal("45000.00"), "MONTHLY"),
364 ("Pedro", "Garcia", "pedro.garcia@fudo.local", "Truck Driver", Decimal("35000.00"), "MONTHLY"),
365]
366for first, last, email, title, salary, pay_type in employees_data:
367 emp, created = Employee.objects.get_or_create(
368 tenant_id=tenant_id, email=email,
369 defaults=dict(
370 first_name=first, last_name=last, job_title=title,
371 salary=salary, pay_type=pay_type, hire_date=date.today() - timedelta(days=180),
372 is_active=True
373 )
374 )
375 status = "✅ Created" if created else "🔄 Exists"
376 print(f" {status}: {emp.first_name} {emp.last_name} | {emp.job_title} | ₱{emp.salary}/{emp.pay_type}")
378print(f" Total employees: {Employee.objects.filter(tenant_id=tenant_id).count()}")
380# Create a payroll run
381pr, created = PayrollRun.objects.get_or_create(
382 tenant_id=tenant_id,
383 run_date=date.today(),
384 period_start=date.today() - timedelta(days=30),
385 period_end=date.today(),
386 defaults=dict(status="DRAFT", total_amount=Decimal("0.00"))
387)
388if created:
389 employees = Employee.objects.filter(tenant_id=tenant_id, is_active=True)
390 total = Decimal("0.00")
391 for emp in employees:
392 Payslip.objects.create(
393 tenant_id=tenant_id,
394 employee=emp,
395 payroll_run=pr,
396 basic_salary=emp.salary,
397 pay_from=pr.period_start,
398 pay_to=pr.period_end,
399 net_pay=emp.salary, # simplified
400 )
401 total += emp.salary
402 pr.total_amount = total
403 pr.save()
404print(f" ✅ Payroll Run: PR-{pr.run_date.strftime('%Y%m%d')} | ₱{pr.total_amount} | Status: {pr.status}")
405print(f" Total payroll runs: {PayrollRun.objects.filter(tenant_id=tenant_id).count()}")
407# ── 11. Trucking - Vehicles, Drivers, Fuel ────────────────────────────────────
408print("\n" + "="*70)
409print("11. TRUCKING - VEHICLES, DRIVERS & FUEL LOGS")
410print("="*70)
411vehicles_data = [
412 ("TRK-001", "Mitsubishi Fuso", "ABC-1234", Decimal("10.00"), "ACTIVE"),
413 ("TRK-002", "Isuzu Elf", "XYZ-5678", Decimal("8.50"), "ACTIVE"),
414 ("TRK-003", "Hyundai H-100", "DEF-9012", Decimal("6.00"), "MAINTENANCE"),
415]
416for code, model, plate, fuel_cap, status_v in vehicles_data:
417 v, created = Vehicle.objects.get_or_create(
418 tenant_id=tenant_id, vehicle_number=code,
419 defaults=dict(model=model, plate_number=plate, fuel_capacity=fuel_cap, status=status_v)
420 )
421 status = "✅ Created" if created else "🔄 Exists"
422 print(f" {status}: {v.vehicle_number} | {v.model} | {v.plate_number} | {v.status}")
424drivers_data = [
425 ("Roberto", "Aquino", "roberto.aquino@fudo.local", "TRK-001", "VALID"),
426 ("Luis", "Cruz", "luis.cruz@fudo.local", "TRK-002", "VALID"),
427]
428for first, last, email, truck_code, lic_status in drivers_data:
429 truck = Vehicle.objects.filter(tenant_id=tenant_id, vehicle_number=truck_code).first()
430 d, created = Driver.objects.get_or_create(
431 tenant_id=tenant_id, email=email,
432 defaults=dict(
433 first_name=first, last_name=last,
434 license_number=f"DL-{email[-8:-5].upper()}-2024",
435 license_expiry=date.today() + timedelta(days=365),
436 license_status=lic_status, status="ACTIVE", assigned_vehicle=truck
437 )
438 )
439 status = "✅ Created" if created else "🔄 Exists"
440 print(f" {status}: {d.first_name} {d.last_name} | {d.license_number} | Truck: {truck_code}")
442# Fuel logs
443vehicles = list(Vehicle.objects.filter(tenant_id=tenant_id)[:2])
444for v in vehicles:
445 fl, created = FuelLog.objects.get_or_create(
446 tenant_id=tenant_id, vehicle=v, log_date=date.today(),
447 defaults=dict(
448 odometer_reading=Decimal("50000.00"),
449 liters_filled=Decimal("50.00"),
450 price_per_liter=Decimal("65.00"),
451 total_cost=Decimal("3250.00"),
452 fuel_type="Diesel", location="Manila Petron Station"
453 )
454 )
455 status = "✅ Created" if created else "🔄 Exists"
456 print(f" {status}: Fuel Log | {v.vehicle_number} | {fl.liters_filled}L @ ₱{fl.price_per_liter}/L")
458# ── 12. Customs - Entries & Duty Rates ────────────────────────────────────────
459print("\n" + "="*70)
460print("12. CUSTOMS - ENTRIES & DUTY RATES")
461print("="*70)
462duty_rates_data = [
463 ("8401.40.00", "Fish Meal", Decimal("5.00"), "kg"),
464 ("9503.00.00", "Toys and Models", Decimal("20.00"), "pc"),
465 ("3004.90.90", "Pharmaceutical Products", Decimal("1.00"), "kg"),
466 ("8701.20.00", "Trucks (Commercial)", Decimal("3.00"), "pc"),
467]
468for hs, desc, rate, uom in duty_rates_data:
469 dr, created = DutyRate.objects.get_or_create(
470 tenant_id=tenant_id, hs_code=hs,
471 defaults=dict(description=desc, duty_rate=rate, unit_of_measure=uom, is_active=True)
472 )
473 status = "✅ Created" if created else "🔄 Exists"
474 print(f" {status}: HS {dr.hs_code} | {dr.description} | {dr.duty_rate}% {dr.unit_of_measure}")
476shipments_for_customs = Shipment.objects.filter(tenant_id=tenant_id, status='IN_TRANSIT')[:1]
477for sh in shipments_for_customs:
478 ce, created = CustomsEntry.objects.get_or_create(
479 tenant_id=tenant_id, shipment=sh,
480 defaults=dict(
481 entry_number=f"CE-{sh.reference_number}",
482 entry_type="IMPORT",
483 entry_date=date.today(),
484 customs_value=sh.declared_value,
485 duty_amount=sh.duty_amount,
486 vat_amount=(sh.declared_value + sh.duty_amount) * Decimal("0.12"),
487 status="PENDING",
488 )
489 )
490 status = "✅ Created" if created else "🔄 Exists"
491 print(f" {status}: {ce.entry_number} | Shipment: {sh.reference_number} | ₱{ce.duty_amount} duty")
493# ── Final Summary ─────────────────────────────────────────────────────────────
494print("\n" + "="*70)
495print("📊 FINAL SUMMARY")
496print("="*70)
497print(f" Accounts: {Account.objects.filter(tenant_id=tenant_id).count():>6}")
498print(f" Products: {Product.objects.filter(tenant_id=tenant_id).count():>6}")
499print(f" Warehouses: {Warehouse.objects.filter(tenant_id=tenant_id).count():>6}")
500print(f" Stock Moves: {StockMove.objects.filter(tenant_id=tenant_id).count():>6}")
501print(f" Invoices: {Invoice.objects.filter(tenant_id=tenant_id).count():>6}")
502print(f" Shipments: {Shipment.objects.filter(tenant_id=tenant_id).count():>6}")
503print(f" Shipping Quotes: {ShippingQuote.objects.filter(tenant_id=tenant_id).count():>6}")
504print(f" Freight Quotes: {FreightQuote.objects.filter(tenant_id=tenant_id).count():>6}")
505print(f" Journal Entries: {JournalEntry.objects.filter(tenant_id=tenant_id).count():>6}")
506print(f" Journal Items: {JournalItem.objects.filter(tenant_id=tenant_id).count():>6}")
507print(f" Companies: {Company.objects.filter(tenant_id=tenant_id).count():>6}")
508print(f" Deals: {Deal.objects.filter(tenant_id=tenant_id).count():>6}")
509print(f" Employees: {Employee.objects.filter(tenant_id=tenant_id).count():>6}")
510print(f" Payroll Runs: {PayrollRun.objects.filter(tenant_id=tenant_id).count():>6}")
511print(f" Vehicles: {Vehicle.objects.filter(tenant_id=tenant_id).count():>6}")
512print(f" Drivers: {Driver.objects.filter(tenant_id=tenant_id).count():>6}")
513print(f" Fuel Logs: {FuelLog.objects.filter(tenant_id=tenant_id).count():>6}")
514print(f" Customs Entries: {CustomsEntry.objects.filter(tenant_id=tenant_id).count():>6}")
515print(f" Duty Rates: {DutyRate.objects.filter(tenant_id=tenant_id).count():>6}")
516print("="*70)
517print("✅ Transaction simulation complete!")