Add demo orders creation scripts

- Created management command for generating demo orders
- Added SQL script to create 25 orders with random dates (±15 days)
- Added Python runner script for executing SQL
- Demo orders include varied statuses, payment methods, and delivery types
- Orders distributed across different dates for testing date filter

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2025-11-07 23:49:06 +03:00
parent fea650a35c
commit e3bab2252e
5 changed files with 414 additions and 0 deletions

View File

@@ -0,0 +1,186 @@
-- Создание демо-заказов для схемы grach
SET search_path TO grach;
-- Создаем 25 заказов с разными датами (от -15 до +15 дней от сегодня)
DO $$
DECLARE
customer_ids INT[];
product_ids INT[];
address_ids INT[];
shop_ids INT[];
i INT;
random_customer_id INT;
random_product_id INT;
random_address_id INT;
random_shop_id INT;
is_delivery_flag BOOLEAN;
delivery_date_val DATE;
status_val VARCHAR(20);
payment_status_val VARCHAR(20);
payment_method_val VARCHAR(20);
order_id INT;
items_total DECIMAL(10,2);
delivery_cost_val DECIMAL(10,2);
total_amount_val DECIMAL(10,2);
BEGIN
-- Получаем существующие ID
SELECT ARRAY_AGG(id) INTO customer_ids FROM grach.customers_customer;
SELECT ARRAY_AGG(id) INTO product_ids FROM grach.products_product;
SELECT ARRAY_AGG(id) INTO address_ids FROM grach.customers_address;
SELECT ARRAY_AGG(id) INTO shop_ids FROM grach.shops_shop;
-- Проверяем наличие данных
IF customer_ids IS NULL OR array_length(customer_ids, 1) = 0 THEN
RAISE EXCEPTION 'Нет клиентов в базе!';
END IF;
IF product_ids IS NULL OR array_length(product_ids, 1) = 0 THEN
RAISE EXCEPTION 'Нет товаров в базе!';
END IF;
-- Создаем 25 заказов
FOR i IN 1..25 LOOP
-- Случайные значения
random_customer_id := customer_ids[1 + floor(random() * array_length(customer_ids, 1))::int];
is_delivery_flag := (random() > 0.5);
delivery_date_val := CURRENT_DATE + (floor(random() * 31) - 15)::int;
-- Случайный статус
CASE floor(random() * 6)::int
WHEN 0 THEN status_val := 'new';
WHEN 1 THEN status_val := 'confirmed';
WHEN 2 THEN status_val := 'in_assembly';
WHEN 3 THEN status_val := 'in_delivery';
WHEN 4 THEN status_val := 'delivered';
ELSE status_val := 'cancelled';
END CASE;
-- Случайный статус оплаты
CASE floor(random() * 3)::int
WHEN 0 THEN payment_status_val := 'unpaid';
WHEN 1 THEN payment_status_val := 'partial';
ELSE payment_status_val := 'paid';
END CASE;
-- Случайный способ оплаты
CASE floor(random() * 4)::int
WHEN 0 THEN payment_method_val := 'cash_to_courier';
WHEN 1 THEN payment_method_val := 'card_to_courier';
WHEN 2 THEN payment_method_val := 'online';
ELSE payment_method_val := 'bank_transfer';
END CASE;
-- Стоимость доставки
IF is_delivery_flag THEN
delivery_cost_val := 200 + floor(random() * 300)::int;
ELSE
delivery_cost_val := 0;
END IF;
-- Создаем заказ
INSERT INTO grach.orders_order (
customer_id,
order_number,
is_delivery,
delivery_address_id,
pickup_shop_id,
delivery_date,
delivery_time_start,
delivery_time_end,
delivery_cost,
status,
payment_method,
is_paid,
total_amount,
discount_amount,
amount_paid,
payment_status,
customer_is_recipient,
recipient_name,
recipient_phone,
is_anonymous,
special_instructions,
created_at,
updated_at,
modified_by_id
) VALUES (
random_customer_id,
'ORD-' || to_char(CURRENT_DATE, 'YYYYMMDD') || '-' || substring(md5(random()::text) from 1 for 4),
is_delivery_flag,
CASE WHEN is_delivery_flag AND address_ids IS NOT NULL THEN address_ids[1 + floor(random() * array_length(address_ids, 1))::int] ELSE NULL END,
CASE WHEN NOT is_delivery_flag AND shop_ids IS NOT NULL THEN shop_ids[1 + floor(random() * array_length(shop_ids, 1))::int] ELSE NULL END,
delivery_date_val,
CASE WHEN random() > 0.3 THEN ((9 + floor(random() * 10)::int)::text || ':00:00')::time ELSE NULL END,
CASE WHEN random() > 0.3 THEN ((11 + floor(random() * 8)::int)::text || ':00:00')::time ELSE NULL END,
delivery_cost_val,
status_val,
payment_method_val,
(payment_status_val = 'paid'),
1000, -- Временное значение, пересчитаем позже
CASE WHEN random() > 0.8 THEN (100 + floor(random() * 400)::int) ELSE 0 END,
0, -- Временное значение
payment_status_val,
(random() > 0.7),
CASE WHEN random() > 0.7 THEN 'Получатель ' || i ELSE NULL END,
CASE WHEN random() > 0.7 THEN '+79' || lpad(floor(random() * 1000000000)::text, 9, '0') ELSE NULL END,
(random() > 0.8),
CASE WHEN random() > 0.5 THEN
CASE floor(random() * 5)::int
WHEN 0 THEN 'Позвонить за час до доставки'
WHEN 1 THEN 'Доставить точно в указанное время'
WHEN 2 THEN 'Не звонить в дверь'
WHEN 3 THEN 'Упаковать покрасивее'
ELSE 'Приложить открытку'
END
ELSE NULL END,
CURRENT_TIMESTAMP,
CURRENT_TIMESTAMP,
NULL
) RETURNING id INTO order_id;
-- Добавляем 1-3 товара в заказ
items_total := 0;
FOR j IN 1..(1 + floor(random() * 3)::int) LOOP
random_product_id := product_ids[1 + floor(random() * array_length(product_ids, 1))::int];
-- Получаем цену товара и добавляем позицию
INSERT INTO grach.orders_orderitem (
order_id,
product_id,
product_kit_id,
quantity,
price,
is_custom_price,
created_at
)
SELECT
order_id,
random_product_id,
NULL,
1 + floor(random() * 3)::int,
price,
FALSE,
CURRENT_TIMESTAMP
FROM grach.products_product
WHERE id = random_product_id
RETURNING (quantity * price) INTO STRICT total_amount_val;
items_total := items_total + total_amount_val;
END LOOP;
-- Обновляем итоговую сумму заказа
UPDATE grach.orders_order
SET
total_amount = items_total + delivery_cost - discount_amount,
amount_paid = CASE
WHEN payment_status = 'paid' THEN items_total + delivery_cost - discount_amount
WHEN payment_status = 'partial' THEN (items_total + delivery_cost - discount_amount) * (0.2 + random() * 0.6)
ELSE 0
END
WHERE id = order_id;
RAISE NOTICE 'Создан заказ % на дату %', order_id, delivery_date_val;
END LOOP;
RAISE NOTICE 'Успешно создано 25 заказов!';
END $$;

View File

@@ -0,0 +1 @@
# Management commands for orders app

View File

@@ -0,0 +1 @@
# Management commands

View File

@@ -0,0 +1,202 @@
"""
Management команда для создания демо-заказов на разные даты
"""
from django.core.management.base import BaseCommand
from django.utils import timezone
from django.db import connection
from datetime import datetime, timedelta
import random
from decimal import Decimal
from orders.models import Order, OrderItem
from customers.models import Customer, Address
from shops.models import Shop
from products.models import Product
class Command(BaseCommand):
help = 'Создает 20-30 демо-заказов на разные даты'
def add_arguments(self, parser):
parser.add_argument(
'--count',
type=int,
default=25,
help='Количество заказов для создания (по умолчанию: 25)'
)
parser.add_argument(
'--schema',
type=str,
default='grach',
help='Схема базы данных (tenant) для создания заказов'
)
def handle(self, *args, **options):
count = options['count']
schema_name = options['schema']
# Устанавливаем схему для работы с tenant
with connection.cursor() as cursor:
cursor.execute(f'SET search_path TO {schema_name}')
self.stdout.write(f'Начинаем создание демо-заказов в схеме {schema_name}...')
# Проверяем наличие необходимых данных
customers = list(Customer.objects.all())
if not customers:
self.stdout.write(self.style.ERROR('Нет клиентов в базе! Создайте хотя бы одного клиента.'))
return
products = list(Product.objects.all())
if not products:
self.stdout.write(self.style.ERROR('Нет товаров в базе! Создайте хотя бы один товар.'))
return
addresses = list(Address.objects.all())
shops = list(Shop.objects.all())
if not addresses and not shops:
self.stdout.write(self.style.ERROR('Нет ни адресов, ни магазинов! Создайте хотя бы что-то одно.'))
return
# Статусы и их вероятности
statuses = [
('new', 0.15),
('confirmed', 0.25),
('in_assembly', 0.20),
('in_delivery', 0.15),
('delivered', 0.20),
('cancelled', 0.05),
]
payment_statuses = [
('unpaid', 0.30),
('partial', 0.20),
('paid', 0.50),
]
payment_methods = [
'cash_to_courier',
'card_to_courier',
'online',
'bank_transfer',
]
# Генерируем даты в диапазоне ±15 дней от сегодня
today = datetime.now().date()
created_count = 0
for i in range(count):
try:
# Случайная дата доставки
days_offset = random.randint(-15, 15)
delivery_date = today + timedelta(days=days_offset)
# Выбираем клиента
customer = random.choice(customers)
# Выбираем тип доставки
is_delivery = random.choice([True, False]) if addresses and shops else bool(addresses)
# Создаем заказ
order = Order()
order.customer = customer
order.is_delivery = is_delivery
# Устанавливаем адрес или магазин
if is_delivery and addresses:
# Для доставки выбираем адрес клиента или случайный
customer_addresses = list(customer.addresses.all())
if customer_addresses:
order.delivery_address = random.choice(customer_addresses)
else:
order.delivery_address = random.choice(addresses)
order.delivery_cost = Decimal(random.randint(200, 500))
elif shops:
order.pickup_shop = random.choice(shops)
order.delivery_cost = Decimal(0)
# Дата и время
order.delivery_date = delivery_date
if random.random() > 0.3: # 70% заказов с указанным временем
start_hour = random.randint(9, 18)
order.delivery_time_start = f"{start_hour:02d}:00:00"
order.delivery_time_end = f"{start_hour + 2:02d}:00:00"
# Статус
status_choices = [s[0] for s in statuses]
status_weights = [s[1] for s in statuses]
order.status = random.choices(status_choices, weights=status_weights)[0]
# Способ оплаты
order.payment_method = random.choice(payment_methods)
# Дополнительная информация
if random.random() > 0.7: # 30% - подарок другому человеку
order.customer_is_recipient = False
order.recipient_name = f"Получатель {i+1}"
order.recipient_phone = f"+7{random.randint(9000000000, 9999999999)}"
if random.random() > 0.8: # 20% анонимных
order.is_anonymous = True
if random.random() > 0.5: # 50% с комментариями
comments = [
"Позвонить за час до доставки",
"Доставить точно в указанное время",
"Не звонить в дверь, только по телефону",
"Упаковать покрасивее",
"Приложить открытку",
]
order.special_instructions = random.choice(comments)
# Сохраняем заказ (чтобы получить ID)
order.save()
# Добавляем товары в заказ
items_count = random.randint(1, 4)
order_products = random.sample(products, min(items_count, len(products)))
items_total = Decimal(0)
for product in order_products:
item = OrderItem()
item.order = order
item.product = product
item.quantity = random.randint(1, 3)
item.price = product.price
item.save()
items_total += item.get_total_price()
# Рассчитываем итоговую сумму
order.total_amount = items_total + order.delivery_cost
# Скидка (20% заказов)
if random.random() > 0.8:
order.discount_amount = Decimal(random.randint(100, 500))
order.total_amount -= order.discount_amount
# Статус оплаты
payment_status_choices = [s[0] for s in payment_statuses]
payment_status_weights = [s[1] for s in payment_statuses]
order.payment_status = random.choices(payment_status_choices, weights=payment_status_weights)[0]
if order.payment_status == 'paid':
order.amount_paid = order.total_amount
order.is_paid = True
elif order.payment_status == 'partial':
order.amount_paid = order.total_amount * Decimal(random.uniform(0.2, 0.8))
order.is_paid = False
else:
order.amount_paid = Decimal(0)
order.is_paid = False
order.save()
created_count += 1
self.stdout.write(f' Создан заказ #{order.order_number} на {delivery_date}')
except Exception as e:
self.stdout.write(self.style.ERROR(f'Ошибка при создании заказа {i+1}: {str(e)}'))
self.stdout.write(self.style.SUCCESS(f'\nУспешно создано {created_count} заказов!'))
self.stdout.write(f'Даты доставки: от {today - timedelta(days=15)} до {today + timedelta(days=15)}')

View File

@@ -0,0 +1,24 @@
"""
Скрипт для создания демо-заказов напрямую через SQL
"""
import os
import django
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'myproject.settings')
django.setup()
from django.db import connection
# Читаем SQL скрипт
with open('create_demo_orders.sql', 'r', encoding='utf-8') as f:
sql = f.read()
# Выполняем SQL
with connection.cursor() as cursor:
try:
cursor.execute(sql)
print("[OK] SQL script executed successfully!")
print("[OK] 25 demo orders created!")
except Exception as e:
print(f"[ERROR] {e}")
raise