Skip to content

Модуль Commerce (Продукты, Корзина, Заказы)

Обзор

Модуль Commerce обеспечивает полную функциональность электронной коммерции платформы IWM, включая управление каталогом продуктов, операции с корзиной, процесс оформления заказа, выполнение заказов, обработку платежей и интеграцию с доставкой. Он интегрируется с модулем MLM для реферальной атрибуции и начисления комиссий.

Зоны ответственности

  • Каталог продуктов и управление категориями
  • Отслеживание инвентаря и управление запасами
  • Корзина покупок (гостевая и авторизованная)
  • Многошаговый процесс оформления заказа
  • Управление жизненным циклом заказа
  • Обработка платежей (Stripe, YooKassa)
  • Интеграция с доставкой (CDEK, DHL)
  • Обработка возвратов и рефандов
  • Реферальная атрибуция для заказов

Доменные сущности

Product

Основная сущность продукта для каталога.

ПолеТипОписание
idUUIDИдентификатор продукта
category_idUUIDСсылка на категорию
skuVARCHAR(50)Артикул (уникальный)
nameVARCHAR(200)Название продукта
slugVARCHAR(200)URL-дружественный идентификатор
short_descriptionVARCHAR(500)Краткое описание
descriptionTEXTПолное описание
base_priceDECIMALОбычная цена
sale_priceDECIMALЦена со скидкой
cost_priceDECIMALСебестоимость
currencyVARCHAR(3)Валюта цены
statusENUMСтатус продукта
stock_quantityINTДоступный запас
low_stock_thresholdINTПорог предупреждения
weight_gramsINTВес продукта
dimensionsJSONBДлина, ширина, высота
career_points_valueDECIMALMLM очки за покупку
is_featuredBOOLEANФлаг рекомендуемого

Category

Категория продуктов с иерархической структурой.

ПолеТипОписание
idUUIDИдентификатор категории
nameVARCHAR(100)Название категории
slugVARCHAR(100)URL-дружественный идентификатор
descriptionTEXTОписание категории
parent_idUUIDРодительская категория
pathLTREEМатериализованный путь для иерархии
image_urlVARCHAR(500)Изображение категории
sort_orderINTПорядок отображения
is_activeBOOLEANСтатус активности

Cart

Корзина покупок для пользователей и гостей.

ПолеТипОписание
idUUIDИдентификатор корзины
user_idUUIDСсылка на пользователя (опционально)
session_idVARCHAR(100)ID гостевой сессии
referring_partner_idUUIDMLM атрибуция
statusENUMСтатус корзины
subtotalDECIMALСумма товаров
discount_totalDECIMALПрименненые скидки
totalDECIMALИтоговая сумма
currencyVARCHAR(3)Валюта корзины
expires_atTIMESTAMPСрок истечения корзины

CartItem

Отдельные товары в корзине.

ПолеТипОписание
idUUIDИдентификатор товара
cart_idUUIDСсылка на корзину
product_idUUIDСсылка на продукт
quantityINTКоличество
unit_priceDECIMALЦена за единицу
total_priceDECIMALСумма позиции
added_atTIMESTAMPВремя добавления

Order

Запись о заказе клиента.

ПолеТипОписание
idUUIDИдентификатор заказа
order_numberVARCHAR(20)Читаемый номер
user_idUUIDСсылка на клиента
statusENUMСтатус заказа
subtotalDECIMALСумма товаров
discount_totalDECIMALПримененные скидки
shipping_costDECIMALСтоимость доставки
tax_amountDECIMALПрименимые налоги
totalDECIMALИтоговая сумма
currencyVARCHAR(3)Валюта заказа
shipping_address_idUUIDАдрес доставки
billing_address_idUUIDАдрес для счета
shipping_method_idUUIDСпособ доставки
referring_partner_idUUIDMLM атрибуция
notesTEXTПримечания клиента

OrderItem

Позиции заказа (снимок продукта на момент покупки).

ПолеТипОписание
idUUIDИдентификатор позиции
order_idUUIDСсылка на заказ
product_idUUIDСсылка на продукт
skuVARCHAR(50)Снимок артикула
nameVARCHAR(200)Снимок названия
quantityINTКоличество
unit_priceDECIMALЦена за единицу
total_priceDECIMALСумма позиции
career_points_valueDECIMALЗаработанные MLM очки

Payment

Платежная транзакция для заказа.

ПолеТипОписание
idUUIDИдентификатор платежа
order_idUUIDСсылка на заказ
amountDECIMALСумма платежа
currencyVARCHAR(3)Валюта платежа
methodENUMCARD, EWALLET, BANK_TRANSFER
providerENUMSTRIPE, YOOKASSA
statusENUMСтатус платежа
provider_referenceVARCHAR(255)Внешний ID транзакции
provider_responseJSONBПолный ответ провайдера
paid_atTIMESTAMPВремя успешного платежа
failed_atTIMESTAMPВремя неудачи
refunded_atTIMESTAMPВремя рефанда

Shipment

Отслеживание доставки заказа.

ПолеТипОписание
idUUIDИдентификатор отправления
order_idUUIDСсылка на заказ
carrierVARCHAR(50)CDEK, DHL и т.д.
tracking_numberVARCHAR(100)Номер отслеживания
statusENUMСтатус отправления
shipped_atTIMESTAMPДата отправки
estimated_deliveryDATEОжидаемая доставка
delivered_atTIMESTAMPФактическая доставка
tracking_eventsJSONBИстория отслеживания

Address

Адреса клиентов для доставки/счетов.

ПолеТипОписание
idUUIDИдентификатор адреса
user_idUUIDСсылка на пользователя
typeENUMSHIPPING, BILLING
first_nameVARCHAR(100)Имя получателя
last_nameVARCHAR(100)Фамилия получателя
companyVARCHAR(200)Название компании
address_line1VARCHAR(255)Адрес улицы
address_line2VARCHAR(255)Квартира, офис и т.д.
cityVARCHAR(100)Город
stateVARCHAR(100)Область/регион
postal_codeVARCHAR(20)Почтовый индекс
countryVARCHAR(3)ISO 3166-1 alpha-3
phoneVARCHAR(20)Контактный телефон
is_defaultBOOLEANФлаг адреса по умолчанию

Каталог продуктов

Иерархия категорий (LTREE)

Категории используют PostgreSQL LTREE для эффективных иерархических запросов:

Ключевые запросы LTREE:

sql
-- Get all products in "Health" and subcategories
SELECT p.* FROM products p
JOIN categories c ON p.category_id = c.id
WHERE c.path <@ 'health';

-- Get direct children of a category
SELECT * FROM categories
WHERE path ~ 'health.*{1}';

-- Get all ancestors of a category
SELECT * FROM categories
WHERE 'health.vitamins.multivitamins' <@ path;

Атрибуты продуктов

Продукты поддерживают динамические атрибуты через JSONB:

json
{
  "color": "Blue",
  "size": "Large",
  "material": "Organic Cotton",
  "weight_net": "500g",
  "ingredients": ["Vitamin C", "Zinc", "Elderberry"]
}

Изображения продуктов

Несколько изображений на продукт с сортировкой:

ПолеОписание
urlCDN URL изображения
alt_textТекст для доступности
sort_orderПорядок отображения
is_primaryГлавное изображение продукта

Управление инвентарем

Отслеживание запасов

Операции с запасами

ОперацияТриггерЭффект
ReserveДобавление в корзинуВременно резервирует запас
ReleaseИстечение корзины, удаление товараВозвращает зарезервированный запас
CommitПодтверждение заказаПостоянно выделяет запас
DeductОтправка заказаСписывает из инвентаря
RestoreОтмена заказа/рефандВозвращает выделенный запас

Предупреждения о низком запасе

Когда stock_quantity <= low_stock_threshold:

  1. Отправляется уведомление администратору
  2. Продукт помечается для дозаказа
  3. Опционально: Автоскрытие при запасе = 0

Правила резервирования запасов

  • Резервирование корзины: 30 минут
  • Резервирование оформления: 15 минут
  • Подтверждение заказа: Постоянное до отправки/отмены
  • Неудачный платеж: Запас освобождается через 1 час

Система корзины

Гостевые vs Пользовательские корзины

Гостевые корзины

  • Идентифицируются по session_id (UUID в cookie)
  • Истекают через 7 дней неактивности
  • Реферальная атрибуция сохраняется в корзине

Пользовательские корзины

  • Привязаны к user_id
  • Сохраняются бессрочно
  • Автовосстановление при входе

Слияние корзин при входе

Когда гость с товарами входит в систему:

  1. Найти существующую корзину пользователя (если есть)
  2. Для каждого товара гостевой корзины:
    • Если продукт есть в корзине пользователя: Обновить количество
    • Если продукта нет в корзине пользователя: Добавить товар
  3. Пересчитать итоги
  4. Удалить гостевую корзину
  5. Сохранить реферальную атрибуцию (побеждает последняя)

Истечение корзины


Процесс оформления заказа

Многошаговое оформление

Шаг 1: Валидация корзины

  • Проверить наличие всех товаров на складе
  • Проверить доступность продуктов (не сняты с продажи)
  • Пересчитать цены (могли измениться)
  • Применить автоматические скидки

Шаг 2: Выбор доставки

  • Пользователь выбирает/добавляет адрес доставки
  • Рассчитываются доступные способы доставки
  • Отображается стоимость доставки
  • Показываются ожидаемые сроки доставки

Шаг 3: Оплата

  • Выбор способа оплаты
  • Ввод платежных данных
  • Применение промокодов
  • Расчет итоговой суммы с налогами

Шаг 4: Подтверждение

  • Проверка сводки заказа
  • Принятие условий
  • Окончательное оформление заказа
  • Обработка платежа

Машина состояний заказа

Диаграмма состояний

Допустимые переходы

ИзВТриггерУсловия
PENDINGCONFIRMEDpayment_successПлатеж выполнен
PENDINGCANCELLEDcancelПлатеж не прошел или пользователь отменил
CONFIRMEDPROCESSINGstart_processingНачало комплектации
CONFIRMEDCANCELLEDcancelТолько до отправки
PROCESSINGSHIPPEDshipПрисвоен номер отслеживания
PROCESSINGCANCELLEDcancelТовар недоступен
SHIPPEDDELIVEREDdeliverПодтверждение от курьера
DELIVEREDREFUNDEDrefundВ пределах 14-дневного окна

Временные метки заказа

СтатусПоле временной метки
CONFIRMEDconfirmed_at
SHIPPEDshipped_at
DELIVEREDdelivered_at
CANCELLEDcancelled_at
REFUNDEDrefunded_at

Интеграция платежей

Поддерживаемые провайдеры

ПровайдерРынкиМетоды
StripeМеждународныйCard, Apple Pay, Google Pay
YooKassaРоссия/СНГCard, SberPay, YooMoney

Процесс оплаты

Обработка вебхуков

Идемпотентность

  • Каждый платеж имеет уникальный idempotency_key
  • Предотвращает повторные списания при повторных попытках
  • Формат ключа: order_{orderId}_{timestamp}

Статусы платежей

СтатусОписание
PENDINGПлатеж инициирован
PROCESSINGОбрабатывается провайдером
COMPLETEDУспешно списано
FAILEDПлатеж не прошел
REFUNDEDПолностью возвращен

Интеграция доставки

Поддерживаемые курьерские службы

СлужбаПокрытиеФункции
CDEKРоссия, СНГКурьером до двери, пункты выдачи
DHLМеждународныйЭкспресс, стандарт

Процесс доставки

Статусы отправления

СтатусОписание
PREPARINGЗаказ упаковывается
SHIPPEDПередан курьеру
IN_TRANSITУ курьера, в пути
OUT_FOR_DELIVERYНа последней миле
DELIVEREDУспешно доставлен
RETURNEDВозвращен отправителю

События отслеживания

Сохраняются как JSONB массив:

json
[
  {
    "timestamp": "2024-01-15T10:30:00Z",
    "status": "SHIPPED",
    "location": "Moscow, Russia",
    "description": "Shipment picked up"
  },
  {
    "timestamp": "2024-01-16T14:20:00Z",
    "status": "IN_TRANSIT",
    "location": "Novosibirsk, Russia",
    "description": "In transit to destination"
  }
]

Возвраты и рефанды

Окно возврата

  • Стандартное: 14 дней с момента доставки
  • Расширенное (VIP): 30 дней
  • Без возврата: Цифровые продукты, вскрытые добавки

Процесс рефанда

Частичные рефанды

  • Поддерживаются для заказов с несколькими товарами
  • Можно возвратить отдельные позиции
  • Возврат стоимости доставки опционален
  • Пропорциональная корректировка скидок

Влияние рефанда на MLM

При возврате заказа:

  1. Связанные комиссии отменяются
  2. Если комиссии были выплачены, создается clawback
  3. Карьерные очки вычитаются
  4. Балансы партнеров корректируются

Публикуемые события

СобытиеТриггерPayload
ProductCreatedДобавлен новый продуктproductId, sku, categoryId
ProductUpdatedПродукт измененproductId, changedFields
ProductStatusChangedПереход статусаproductId, fromStatus, toStatus
StockLevelChangedИзменение инвентаряproductId, previousQty, newQty
LowStockAlertНиже порогаproductId, currentQty, threshold
CartCreatedНовая корзинаcartId, userId/sessionId
CartItemAddedТовар добавлен в корзинуcartId, productId, quantity
CartItemRemovedТовар удален из корзиныcartId, productId
CartAbandonedКорзина истеклаcartId, userId, items
OrderCreatedЗаказ размещенorderId, userId, total
OrderConfirmedПлатеж успешенorderId, paymentId
OrderStatusChangedПереход статусаorderId, fromStatus, toStatus
OrderCancelledЗаказ отмененorderId, reason
OrderShippedОтправление созданоorderId, trackingNumber
OrderDeliveredДоставка подтвержденаorderId, deliveredAt
PaymentReceivedПлатеж успешенpaymentId, orderId, amount
PaymentFailedПлатеж не прошелpaymentId, orderId, reason
RefundInitiatedРефанд начатorderId, amount, reason
RefundCompletedРефанд обработанorderId, refundId, amount
ShipmentUpdatedОбновление отслеживанияshipmentId, status, location

Потребляемые события

СобытиеИсточникОбработчик
UserRegisteredCoreСлить гостевую корзину, если есть
UserLoggedInCoreВосстановить/слить корзину пользователя
ReferralAttributedMLMСохранить атрибуцию в корзине

Бизнес-правила и инварианты

Правила продуктов

  1. SKU должен быть уникальным среди всех продуктов
  2. Цена со скидкой не может превышать базовую цену
  3. Количество на складе не может быть отрицательным
  4. Снятые с продажи продукты нельзя добавить в корзину
  5. Продукты с запасом 0 показываются как "Нет в наличии"

Правила корзины

  1. Максимум 50 уникальных позиций на корзину
  2. Максимальное количество на позицию: 99
  3. Сумма корзины не может превышать лимиты платформы
  4. Гостевые корзины истекают через 7 дней
  5. Реферальная атрибуция сохраняется через оформление заказа

Правила заказов

  1. Формат номера заказа: IWM-{YYYYMMDD}-
  2. Переходы статусов должны следовать машине состояний
  3. Нельзя отменить после отправки
  4. Окно возврата: 14 дней с момента доставки
  5. Может применяться минимальная сумма заказа

Правила платежей

  1. Один успешный платеж на заказ
  2. Ключ идемпотентности предотвращает повторные списания
  3. Подпись вебхука должна быть проверена
  4. Неудачные платежи повторяются до 3 раз

Правила инвентаря

  1. Запас резервируется при добавлении в корзину
  2. Зарезервированный запас освобождается при истечении корзины
  3. Запас фиксируется при подтверждении заказа
  4. Запас восстанавливается при отмене заказа

Точки интеграции

Предоставляет другим модулям

ИнтерфейсПотребителиНазначение
IOrderServiceMLMПолучить детали заказа для комиссии
IProductServiceMLMПолучить значение карьерных очков продукта

Потребляет от других модулей

ИнтерфейсПровайдерНазначение
IUserLookupServiceCoreПолучить данные клиента
IPartnerLookupServiceMLMПроверить реферальную атрибуцию
IAttributionServiceMLMПолучить реферального партнера для заказа

Связанные документы