""" Firebase → Django mahsulotlarni sinxronlashtirish skripti. Ishlatish: python sync_firebase_products.py python sync_firebase_products.py --dry-run # haqiqatda saqlamaydi python sync_firebase_products.py --update # mavjudlarni ham yangilaydi Logika: - firestore_id bo'yicha tekshiradi - Mavjud bo'lsa — o'tkazib ketadi (--update bilan yangilaydi) - Yangi bo'lsa — create qiladi """ import os import sys import argparse import django import firebase_admin from firebase_admin import credentials, firestore from decimal import Decimal, InvalidOperation # ── Django sozlash ─────────────────────────────────────────────────────────── BASE_DIR = os.path.dirname(os.path.abspath(__file__)) sys.path.insert(0, BASE_DIR) os.environ.setdefault("DJANGO_SETTINGS_MODULE", "config.settings.local") try: django.setup() except Exception as e: print(f"[XATO] Django setup: {e}") sys.exit(1) from core.apps.vendors.models import ( VendorproductModel, CategoryModel, SectionModel, ) # ── Firebase ulanish ───────────────────────────────────────────────────────── CERT_PATH = os.path.join(BASE_DIR, "fondexuzb-firebase-adminsdk-fbsvc-7b0e2d6200.json") if not os.path.exists(CERT_PATH): print(f"[XATO] Firebase credentials topilmadi: {CERT_PATH}") sys.exit(1) if not firebase_admin._apps: cred = credentials.Certificate(CERT_PATH) firebase_admin.initialize_app(cred) db = firestore.client() # ── Yordamchi funksiyalar ──────────────────────────────────────────────────── def to_decimal(value, default=Decimal("0")): """Har qanday qiymatni Decimal'ga o'tkazadi.""" try: return Decimal(str(value)).quantize(Decimal("0.01")) except (InvalidOperation, TypeError): return default def to_int(value, default=-1): try: return int(value) except (TypeError, ValueError): return default def get_category(firestore_id: str): """CategoryModel'ni firestore_id bo'yicha topadi.""" if not firestore_id: return None return CategoryModel.objects.filter(firestore_id=firestore_id).first() def get_section(firestore_id: str): """SectionModel'ni firestore_id bo'yicha topadi.""" if not firestore_id: return None return SectionModel.objects.filter(firestore_id=firestore_id).first() def build_product_data(doc_id: str, data: dict) -> dict: """Firebase hujjatidan Django model uchun dict yasaydi.""" # product_specification: {"Og'irlik": "1 kg", "Hajm": "500 ml"} kabi spec = data.get("product_specification") if isinstance(spec, str): # Ba'zida JSON string sifatida keladi import json try: spec = json.loads(spec) except Exception: spec = None if not isinstance(spec, dict) or not spec: spec = None return dict( firestore_id=doc_id, vendor=data.get("vendorID") or data.get("vendor") or "", name=(data.get("name") or "").strip() or "—", description=data.get("description") or "", price=to_decimal(data.get("price", 0)), discount_price=to_decimal(data.get("disPrice", 0)), quantity=to_int(data.get("quantity", -1)), is_publish=bool(data.get("publish", True)), photos_json=data.get("photos") or None, product_specification=spec, # ForeignKey'lar ayrida to'ldiriladi _category_id=data.get("categoryID") or "", _section_id=data.get("section_id") or "", ) def sync_products(dry_run: bool = False, update: bool = False): print("Firebase vendor_products kolleksiyasi o'qilmoqda…") docs = list(db.collection("vendor_products").stream()) print(f"Jami Firebase'da: {len(docs)} ta mahsulot\n") created = 0 updated = 0 skipped = 0 errors = 0 for doc in docs: doc_id = doc.id data = doc.to_dict() or {} if not data.get("name"): print(f" [O'TKAZILDI] {doc_id} — nomi yo'q") skipped += 1 continue try: product_data = build_product_data(doc_id, data) category_fid = product_data.pop("_category_id") section_fid = product_data.pop("_section_id") exists = VendorproductModel.objects.filter(firestore_id=doc_id).first() if exists and not update: skipped += 1 continue # ForeignKey topish category = get_category(category_fid) section = get_section(section_fid) if exists and update: for field, val in product_data.items(): setattr(exists, field, val) exists.category = category exists.section = section if not dry_run: exists.save() print(f" [YANGILANDI] {doc_id} — {product_data['name']}") updated += 1 else: if not dry_run: VendorproductModel.objects.create( **product_data, category=category, section=section, ) print(f" [YARATILDI] {doc_id} — {product_data['name']}") created += 1 except Exception as e: print(f" [XATO] {doc_id}: {e}") errors += 1 print("\n" + "=" * 50) print(f"Yaratildi : {created}") print(f"Yangilandi: {updated}") print(f"O'tkazildi: {skipped}") print(f"Xatolar : {errors}") if dry_run: print("\n[DRY-RUN] Hech narsa saqlanmadi.") # ── Entry point ─────────────────────────────────────────────────────────────── if __name__ == "__main__": parser = argparse.ArgumentParser(description="Firebase → Django mahsulot sync") parser.add_argument( "--dry-run", action="store_true", help="Haqiqatda DB'ga yozmaydi, faqat natijalari ko'rsatadi", ) parser.add_argument( "--update", action="store_true", help="Mavjud mahsulotlarni ham yangilaydi (default: o'tkazib ketadi)", ) args = parser.parse_args() sync_products(dry_run=args.dry_run, update=args.update)