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

15. Применение промокода к заказу

Средняя

Go · 47 строк

Промокод даёт скидку в процентах, у него есть срок действия и лимит использований (например, 1 000 первых покупателей). Один пользователь может применить код один раз.

Отметьте строки с ошибками.

В работе: Промокоды блогеров: за первые минуты после публикации их пробуют тысячи человек.

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

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

Давали на собеседовании? Ответов пока мало — ваш поможет.
  1. package promo
  2. import (
  3. "context"
  4. "database/sql"
  5. "errors"
  6. "fmt"
  7. "strings"
  8. "time"
  9. )
  10. type Promo struct {
  11. Code string
  12. Percent int
  13. MaxUses int
  14. Used int
  15. ExpiresAt time.Time
  16. }
  17. var ErrInvalid = errors.New("промокод недействителен")
  18. type Service struct {
  19. db *sql.DB
  20. }
  21. func (s *Service) Apply(ctx context.Context, userID int64, code string, cartKop int64) (int64, error) {
  22. code = strings.ToUpper(code)
  23. var p Promo
  24. q := fmt.Sprintf("SELECT code, percent, max_uses, used, expires_at FROM promos WHERE code = '%s'", code)
  25. err := s.db.QueryRowContext(ctx, q).Scan(&p.Code, &p.Percent, &p.MaxUses, &p.Used, &p.ExpiresAt)
  26. if err != nil {
  27. return 0, ErrInvalid
  28. }
  29. if p.ExpiresAt.Before(time.Now()) {
  30. return 0, ErrInvalid
  31. }
  32. if p.Used > p.MaxUses {
  33. return 0, ErrInvalid
  34. }
  35. discount := cartKop * int64(p.Percent/100)
  36. _, err = s.db.ExecContext(ctx, "UPDATE promos SET used = used + 1 WHERE code = $1", code)
  37. if err != nil {
  38. return 0, err
  39. }
  40. _, err = s.db.ExecContext(ctx, "INSERT INTO promo_uses(code, user_id) VALUES ($1, $2)", code, userID)
  41. return cartKop - discount, err
  42. }