Files
004.erp.generic/backend/modules/crm/management/commands/import_clients_csv.py
mariomitte 4e3bf6dab0
Some checks failed
ERP CI/CD Pipeline / test (push) Has been cancelled
ERP CI/CD Pipeline / Deploy (server git pull + compose) (push) Has been cancelled
patch oko teksta PDFa i UI tablica
2026-07-12 03:25:03 +02:00

131 lines
4.8 KiB
Python

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))