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:
186
myproject/create_demo_orders.sql
Normal file
186
myproject/create_demo_orders.sql
Normal 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 $$;
|
||||||
1
myproject/orders/management/__init__.py
Normal file
1
myproject/orders/management/__init__.py
Normal file
@@ -0,0 +1 @@
|
|||||||
|
# Management commands for orders app
|
||||||
1
myproject/orders/management/commands/__init__.py
Normal file
1
myproject/orders/management/commands/__init__.py
Normal file
@@ -0,0 +1 @@
|
|||||||
|
# Management commands
|
||||||
202
myproject/orders/management/commands/create_demo_orders.py
Normal file
202
myproject/orders/management/commands/create_demo_orders.py
Normal 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)}')
|
||||||
24
myproject/run_demo_orders.py
Normal file
24
myproject/run_demo_orders.py
Normal 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
|
||||||
Reference in New Issue
Block a user