Войти Регистрация
Код-ревью

29. Заявка на возврат товара в Ozon

Средняя

Python · 41 строк

Покупатель выбирает в заказе товары и оформляет возврат. Окно — 14 дней с получения, бельё, косметика и цифровые товары не возвращаются. Если вернули весь заказ, возвращаем и платную доставку.

Функцию вызывает API мобильного приложения: order_id и item_ids приходят из JSON как есть. В проекте USE_TZ = True, поля цен — DecimalField. Отметьте строки с ошибками.

В работе: Раздел «Мои заказы» → «Вернуть товар»: в распродажу 11.11 сюда приходят тысячи заявок в час.

Как проверяем Нажмите на строку с ошибкой и коротко напишите, что не так. Баг засчитан, если отмечена хотя бы одна его строка. Зачёт — найдено не меньше 60 % багов с учётом серьёзности (критичный весит 3, обычный 2, мелкий 1), а лишних отметок не больше, чем багов в коде. Пустые строки, скобки и комментарии лишними не считаем. Ответ один на подход: после него показываем разбор.
Django ORMчасовые поясаденьгиSQL-инъекцияN+1

Источник: наша задача на данных Ozon: возвраты и заказы. Условие пересказано своими словами.

  1. from datetime import datetime, timedelta
  2. from django.db import connection
  3. from .models import Order, OrderItem, ReturnRequest
  4. from .notify import send_sms
  5. RETURN_DAYS = 14
  6. NON_RETURNABLE = {"underwear", "cosmetics", "digital"}
  7. def create_return(user, order_id, item_ids, reason):
  8. order = Order.objects.get(id=order_id)
  9. if order.delivered_at is None:
  10. return {"error": "Заказ ещё не получен"}
  11. deadline = order.delivered_at + timedelta(days=RETURN_DAYS)
  12. if datetime.now() > deadline:
  13. return {"error": "Срок возврата истёк"}
  14. refund = 0.0
  15. items = []
  16. for item_id in item_ids:
  17. item = OrderItem.objects.get(id=item_id)
  18. if item.product.category in NON_RETURNABLE:
  19. continue
  20. refund += item.price * item.quantity
  21. items.append(item)
  22. if order.delivery_paid and len(items) == order.items.count():
  23. refund += order.delivery_price
  24. with connection.cursor() as cur:
  25. cur.execute(
  26. "UPDATE order_items SET status = 'return_requested' "
  27. f"WHERE order_id = {order_id} AND id IN ({','.join(map(str, item_ids))})"
  28. )
  29. req = ReturnRequest.objects.create(
  30. order=order, user=user, reason=reason, refund=round(refund, 2)
  31. )
  32. send_sms(order.phone, f"Заявка на возврат {req.id}: вернём {refund} ₽")
  33. return {"id": req.id, "refund": refund}