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

40. Еженедельная выплата продавцам Wildberries

Сложная

Go · 57 строк

Каждый понедельник утром отчёт считает выплату продавцу за прошлую неделю с понедельника 00:00 до воскресенья 24:00 по Москве: продажи минус возвраты, комиссия 15,5 % от продаж и логистика. Если вышел минус, он переносится долгом на следующую неделю.

Активных продавцов 80 тыс. Отчёт иногда перезапускают вручную в воскресенье вечером. Серверы и база в UTC, sold_at — timestamptz. Отметьте строки с ошибками.

В работе: Финансовый отчёт в кабинете продавца и платёжное поручение на выплату по понедельникам.

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

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

  1. package payout
  2. import (
  3. "context"
  4. "database/sql"
  5. "math"
  6. "time"
  7. )
  8. type Line struct {
  9. SellerID int64
  10. Sales float64
  11. Returns float64
  12. Commission float64
  13. Logistics float64
  14. Payout float64
  15. }
  16. const commissionRate = 0.155
  17. // WeeklyReport собирает выплату продавцам за прошлую неделю (пн 00:00 — вс 24:00 МСК).
  18. func WeeklyReport(ctx context.Context, db *sql.DB, now time.Time) ([]Line, error) {
  19. weekday := int(now.Weekday())
  20. monday := now.AddDate(0, 0, -weekday-6)
  21. start := monday.Truncate(24 * time.Hour)
  22. end := start.AddDate(0, 0, 7)
  23. sellers, err := db.QueryContext(ctx, "SELECT id FROM sellers WHERE active")
  24. if err != nil {
  25. return nil, err
  26. }
  27. defer sellers.Close()
  28. var report []Line
  29. for sellers.Next() {
  30. var l Line
  31. sellers.Scan(&l.SellerID)
  32. err := db.QueryRowContext(ctx,
  33. "SELECT coalesce(sum(price), 0) FROM sales WHERE seller_id = $1 AND sold_at BETWEEN $2 AND $3",
  34. l.SellerID, start, end).Scan(&l.Sales)
  35. if err != nil {
  36. return nil, err
  37. }
  38. db.QueryRowContext(ctx,
  39. "SELECT coalesce(sum(price), 0) FROM returns WHERE seller_id = $1 AND returned_at >= $2 AND returned_at < $3",
  40. l.SellerID, start, end).Scan(&l.Returns)
  41. db.QueryRowContext(ctx, "SELECT coalesce(sum(cost), 0) FROM logistics WHERE seller_id = $1 AND week_start = $2",
  42. l.SellerID, start).Scan(&l.Logistics)
  43. l.Commission = l.Sales * commissionRate
  44. l.Payout = math.Round(l.Sales - l.Returns - l.Commission - l.Logistics)
  45. if l.Payout < 0 {
  46. l.Payout = 0
  47. }
  48. report = append(report, l)
  49. }
  50. return report, nil
  51. }