""" Management команда для пересчета quantity_reserved для всех Stock записей Используется после добавления сигналов для Reservation """ from django.core.management.base import BaseCommand from django.db import connection, transaction class Command(BaseCommand): help = 'Пересчитывает quantity_reserved для всех Stock записей' def add_arguments(self, parser): parser.add_argument( '--schema', type=str, default='grach', help='Схема базы данных (tenant) для работы' ) def handle(self, *args, **options): schema_name = options['schema'] self.stdout.write(f'[НАЧАЛО] Пересчет quantity_reserved для всех Stock записей в схеме {schema_name}...') updated_count = 0 reserved_count = 0 # Используем прямой SQL для пересчета quantity_reserved # Это обходит проблему с tenant routing в Django ORM with connection.cursor() as cursor, transaction.atomic(): # Устанавливаем схему cursor.execute(f'SET search_path TO {schema_name}') # Получаем общее количество Stock записей cursor.execute(f'SELECT COUNT(*) FROM {schema_name}.inventory_stock') total_count = cursor.fetchone()[0] self.stdout.write(f'[INFO] Найдено Stock записей: {total_count}') # Получаем все Stock записи с информацией о продукте cursor.execute(f""" SELECT s.id as stock_id, s.product_id, p.name as product_name, s.warehouse_id FROM {schema_name}.inventory_stock s JOIN {schema_name}.products_product p ON p.id = s.product_id """) stocks = cursor.fetchall() # Обрабатываем каждый Stock for stock_id, product_id, product_name, warehouse_id in stocks: try: # Пересчитываем quantity_reserved и quantity_available # Логика из Stock.refresh_from_batches() # 1. Считаем общее количество из активных партий cursor.execute(f""" SELECT COALESCE(SUM(quantity), 0) FROM {schema_name}.inventory_stockbatch WHERE product_id = %s AND warehouse_id = %s AND is_active = true """, [product_id, warehouse_id]) total_qty = cursor.fetchone()[0] # 2. Считаем зарезервированное количество cursor.execute(f""" SELECT COALESCE(SUM(quantity), 0) FROM {schema_name}.inventory_reservation WHERE product_id = %s AND warehouse_id = %s AND status = 'reserved' """, [product_id, warehouse_id]) total_reserved = cursor.fetchone()[0] # 3. Обновляем Stock cursor.execute(f""" UPDATE {schema_name}.inventory_stock SET quantity_available = %s, quantity_reserved = %s, updated_at = CURRENT_TIMESTAMP WHERE id = %s """, [total_qty, total_reserved, stock_id]) updated_count += 1 if total_reserved > 0: reserved_count += 1 self.stdout.write( f' [OK] Stock #{stock_id}: {product_name} - ' f'зарезервировано: {total_reserved}' ) except Exception as e: self.stdout.write( self.style.ERROR(f' [ОШИБКА] Stock #{stock_id}: {str(e)}') ) self.stdout.write('\n' + '=' * 60) self.stdout.write(self.style.SUCCESS('[ЗАВЕРШЕНО] Результаты:')) self.stdout.write(f' Всего Stock записей: {total_count}') self.stdout.write(f' Обновлено записей: {updated_count}') self.stdout.write(f' Записей с резервами: {reserved_count}') self.stdout.write(self.style.SUCCESS('\n[OK] Все резервы пересчитаны!'))