import csv from pathlib import Path from django.core.management.base import BaseCommand, CommandError from django.core.exceptions import ValidationError from django.db import transaction from modules.crm.models import Client class Command(BaseCommand): help = "Uvozi kupce (vlasnike dizalica) iz CSV datoteke u Client model." expected_columns = [ "name", "client_type", "tax_id", "email", "phone", "address", "city", "postal_code", ] def add_arguments(self, parser): parser.add_argument("csv_path", type=str, help="Putanja do CSV datoteke.") parser.add_argument( "--dry-run", action="store_true", help="Validira i simulira import bez spremanja u bazu.", ) parser.add_argument( "--create-only", action="store_true", help="Kreira samo nove kupce; postojeće preskače.", ) def handle(self, *args, **options): csv_path = Path(options["csv_path"]).expanduser().resolve() dry_run = options["dry_run"] create_only = options["create_only"] if not csv_path.exists(): raise CommandError(f"CSV datoteka ne postoji: {csv_path}") created_count = 0 updated_count = 0 skipped_count = 0 with csv_path.open("r", encoding="utf-8-sig", newline="") as handle: reader = csv.DictReader(handle) if not reader.fieldnames: raise CommandError("CSV nema zaglavlje (header).") normalized_headers = [str(h).strip() for h in reader.fieldnames] missing = [column for column in self.expected_columns if column not in normalized_headers] if missing: raise CommandError("CSV nema obavezna polja: " + ", ".join(missing)) row_number = 1 with transaction.atomic(): for row in reader: row_number += 1 if not any((value or "").strip() for value in row.values()): continue tax_id = (row.get("tax_id") or "").strip() email = (row.get("email") or "").strip().lower() if not tax_id: raise CommandError(f"Red {row_number}: tax_id je obavezan.") if not email: raise CommandError(f"Red {row_number}: email je obavezan.") client = Client.objects.filter(tax_id=tax_id).first() if client and create_only: skipped_count += 1 self.stdout.write( self.style.WARNING( f"Red {row_number}: preskočeno (kupac već postoji) tax_id={tax_id}" ) ) continue is_create = client is None if is_create: client = Client(tax_id=tax_id) client_type = (row.get("client_type") or "legal").strip() if client_type not in {"legal", "individual"}: raise CommandError( f"Red {row_number}: client_type mora biti 'legal' ili 'individual'." ) client.name = (row.get("name") or "").strip() client.client_type = client_type client.email = email client.phone = (row.get("phone") or "").strip() or None client.address = (row.get("address") or "").strip() client.city = (row.get("city") or "").strip() client.postal_code = (row.get("postal_code") or "").strip() try: client.full_clean() except ValidationError as exc: raise CommandError( f"Red {row_number}: validacija nije prošla -> {exc.message_dict}" ) from exc if not dry_run: client.save() if is_create: created_count += 1 else: updated_count += 1 self.stdout.write( self.style.SUCCESS( f"Red {row_number}: {'kreiran' if is_create else 'ažuriran'} kupac {client.name}" ) ) if dry_run: transaction.set_rollback(True) summary = ( f"Import kupaca završen. created={created_count}, updated={updated_count}, " f"skipped={skipped_count}, dry_run={dry_run}" ) self.stdout.write(self.style.SUCCESS(summary))