""" Commande Django pour associer par défaut à chaque produit les emplacements dans lesquels il est actuellement renseigné dans le stock. """ from django.core.management.base import BaseCommand from django.db import transaction from stock.models import Product class Command(BaseCommand): help = "Associe les emplacements de stock existants aux emplacements autorisés des produits." def add_arguments(self, parser): parser.add_argument( '--positive-only', action='store_true', help="Associe uniquement les emplacements où la quantité en stock est strictement supérieure à 0.", ) parser.add_argument( '--dry-run', action='store_true', help="Simule l'exécution en affichant ce qui serait modifié sans enregistrer en base.", ) def handle(self, *args, **options): positive_only = options['positive_only'] dry_run = options['dry_run'] if dry_run: self.stdout.write(self.style.WARNING("--- MODE SIMULATION (DRY-RUN) ---")) # Optimisation : prefetch_related pour éviter les requêtes N+1 products = Product.objects.all().prefetch_related('authorized_locations', 'stocks__location') updated_products_count = 0 total_associations_count = 0 self.stdout.write(f"Analyse de {products.count()} produits...") # Si dry_run, pas besoin de transaction atomique if dry_run: updated_products_count, total_associations_count = self.process_associations( products, positive_only, dry_run=True ) else: with transaction.atomic(): updated_products_count, total_associations_count = self.process_associations( products, positive_only, dry_run=False ) if dry_run: self.stdout.write( self.style.SUCCESS( f"✓ Simulation terminée. {updated_products_count} produits auraient été mis à jour " f"avec {total_associations_count} nouvelles associations d'emplacements." ) ) else: self.stdout.write( self.style.SUCCESS( f"✓ Mise à jour terminée ! {updated_products_count} produits mis à jour " f"avec {total_associations_count} nouvelles associations d'emplacements." ) ) def process_associations(self, products, positive_only, dry_run): updated_products_count = 0 total_associations_count = 0 for product in products: product_stocks = list(product.stocks.all()) if positive_only: product_stocks = [s for s in product_stocks if s.quantity > 0] if not product_stocks: continue current_authorized = set(product.authorized_locations.all()) locations_to_add = [] for stock in product_stocks: if stock.location not in current_authorized: locations_to_add.append(stock.location) if locations_to_add: loc_names = ", ".join(f"'{loc.name}'" for loc in locations_to_add) self.stdout.write( f"Produit '{product.name}' (code: {product.code}) : " f"Ajout des emplacements : {loc_names}" ) if not dry_run: product.authorized_locations.add(*locations_to_add) updated_products_count += 1 total_associations_count += len(locations_to_add) return updated_products_count, total_associations_count