Расчет корзины, скидок, баллов

IMSHOP Retail Protocol (IRP) является объектом интеллектуальной собственности ООО «АЙ ЭМ СОЛЮШНЗ» (IMSHOP) и защищён как объект авторского права. Свидетельство о депонировании произведения № 023-014461 от 16 января 2023 г. подтверждает исключительные права ООО «АЙ ЭМ СОЛЮШНЗ» на данные технологии.

IMSHOP Retail Protocol создан по заказу ООО «АЙ ЭМ СОЛЮШНЗ». Использование IMSHOP Retail Protocol допустимо только при взаимодействии с ООО "АЙ ЭМ СОЛЮШНЗ" и наличии действующего лицензионного договора. Более подробно можно ознакомиться здесь.

Дополнительные интеграции вводятся в эксплуатацию после завершения основных интеграций:

Для подключения дополнительных интеграций обратитесь к вашему менеджеру в IMSHOP.IO

IMSHOP.IO позволяет при помощи webhook подключить уже существующую на вашей стороне систему пересчета корзины с учетом акций, предложений, бонусных баллов итд.

Пересчет корзины через webhook означает, что для каждого изменения состава корзины IMSHOP.IO будет отправлять данные о заказе в систему клиента и ожидать в ответ данные об итоговой стоимости заказа и примененных маркетинговых акциях.

Формат запроса и примеры

Пример запроса

{
    "city": "Москва",
    "cityKladr": "7700000000000",
    "fiasCode": "77000000000000000000000",
    "deliveryId": null,
    "paymentId": null,
    "deliveryPickupId": "a1",
    "items": [
        {
          "name": "Тестовый товар 1",
          "id": "00a03026-412a-54fe-a9df-dcf9325f8618",
          "privateId": "3464",
          "configurationId": "3464",
          "price": 3735,
          "quantity": 1,
          "subtotal": 3735,
          "addons": [
            {
              "configurationId": "1234"
            }
          ],
          "itemKitId": "test-kit-1",
          "selected": true
        },
        {
          "name": "Тестовый товар 2",
          "id": "605e0108-dc95-5dab-95a2-7f459da6aade",
          "privateId": "29117",
          "configurationId": "29117",
          "price": 14540,
          "quantity": 1,
          "subtotal": 14540,
          "selected": true
        },
        {
          "name": "Тестовый товар 3",
          "id": "3ccd380e-1f40-5056-8a7a-ef6e8a9582b5",
          "privateId": "34607",
          "configurationId": "34607",
          "price": 5723,
          "quantity": 2,
          "subtotal": 11446,
          "selected": true
        },
        {
          "name": "Тестовый товар 4",
          "id": "523036eb-b776-5795-b24b-0f224f2d8b17",
          "privateId": "6527",
          "configurationId": "6527",
          "price": 29336,
          "quantity": 1,
          "subtotal": 29336,
          "selected": true
        },
        {
          "name": "Кабель питания Baseus",
          "id": "02ebe9c7-20f0-4cf0-8160-396ef2604daa",
          "privateId": "1234567800",
          "configurationId": "1234567800",
          "price": 2000,
          "quantity": 2,
          "appliedDiscounts": ["dd771099"],
          "selected": true
        }
    ],
    "externalUserId": "XXXXXXX",
    "promocode": "12345",
    "giftCards": [
      {
        "number": "123",
        "pin": "123",
      },
    ],
    "promoGroup": [
        {
          "id": "dd771099",
          "gifts": [
            {
              "id": "56789",
              "quantity": 1
            }
          ]
        }
    ],
    "installId": "ed6b1eec-082f-4880-9100-bcd8e2016cd1",
    "groupId": "1f3a5ced-2a79-4dda-b432-05b8188475fd",
    "loyaltyCard": "12345",
    "preferredPickupId": null
}

Описание формата запроса

  • city - Стандартизированное название города из системы ФИАС

  • cityKladr - КЛАДР города

  • fiasCode - ФИАС код

  • deliveryId - идентификатор выбранной службы доставки в IMSHOP.IO (null если доставка еще не выбрана)

  • paymentId - идентификатор выбранной службы оплаты в IMSHOP.IO (null если оплата еще не выбрана)

  • deliveryPickupId - (опционально) выбранный желаемый пункт выдачи / магазин для получения заказа

  • preferredPickupId - (опционально) id любимого пункта самовывоза (если есть), выбранный в списке любимых магазинов, например на этапе корзины

Если на корзине используется механика "любимого" магазина/аптеки, идентификатор точки самовывоза будет приходить в этом поле вместо deliveryPickupId

  • items - состав корзины

    • name - наименование

    • id - идентификатор товара в системе клиента (group_id)

    • privateId - идентификатор товарного предложения в системе клиента (offer ID в фиде)

    • configurationId - идентификатор товарного предложения (offer ID в фиде)

    • price - цена товара на момент добавления в корзину (если товар - это подарок на выбор, то тут передается 0)

    • quantity - количество

    • subtotal - итого по позиции (subtotal = price * quantity)

    • appliedDiscounts - если предыдущий расчет показал наличие маркетинговой акции, или это - подарок на выбор, то передаем идентификатор акции из прошлого ответа от API

    • deliveryGroup - (опционально) выбранная группа доставки товара, при разбиениии корзины

    • addons - (опционально, в разработке) доп. товары, например "Основание для кровати"

      • configurationId - идентификатор товарного предложения из фида

    • itemKitId - string, id товарного набора, передается только если товар был добавлен из товарного набора

    • selected - boolean, если true, то означает, что товар отмечен галочкой и покупатель берет его. если false, то товар либо недоступен для выбора либо покупатель хочет отложить его

  • externalUserId - идентификатор покупателя в системе клиента, если известен

  • promocode - промокод, введенный покупателем

  • giftCards - подарочные карты, по одной

    • number - номер карты

    • pin – пин-код карты

  • earlyAccess -параметр определяющий что заказ из раннего доступа true

  • installId - идентификатор установки приложения

  • groupId - если вы разделяете корзину пользователя на несколько отправлений, используйте groupId, чтобы корректно рассчитывать итоговую стоимость каждого отправления с учетом скидок на всю корзину целиком. У исходной корзины и у каждой части корзины приходит одинаковое значение groupId

  • loyaltyCard - номер карты лояльности (обычно карта лояльности передаваться не будет, так как она часто уже прикреплена к аккаунту покупателя. используется для анонимных заказов, или если клиент не имеет привязки карт лояльности к профилям пользователей)

  • customSectionValues - индивидуальные секции в оформлении заказа (к примеру добавить открытку, если пользователь приобретает товар в подарок)

В полях запроса могут быть переданы идентификаторы даты/времени интервала доставки (в разработке)

  • deliveryDateIntervalId - (опционально) идентификатор, привязанный к датам, полученный в поле dateIntervals[<index>].id ендпоинта доставок

  • deliveryTimeIntervalId - (опционально) идентификатор, привязанный ко времени, полученный в поле dateIntervals[<index>].timeIntervals[<index>].id ендпоинта доставок

{
    ...
      "deliveryDateIntervalId": "21-06-10",
      "deliveryTimeIntervalId": "10-15",
    ...
}

Маркетинговые акции, активированные в корзине

Ритейлер имеет возможность обновить логику подсчёта полной стоимости и доступных услуг, учитывая добавленные акционные подарки и/или скидки.

Доп. поле promoGroup передаётся в запрос пересчета корзины. Описание формата приведено в разделе Список "Маркетинговые акции"

Для маркетплейсов.

В полях запроса для каждого товара могут быть переданы идентификаторы магазина/ООО (в разработке).

  • warehouseId — (опционально) идентификатор склада/магазина/аутлета/ООО из фида наличия для маркетплейсов

{    
    ...
    "items": [
        {
            ...
            "warehouseId": "AF-1416"
            ....
        }
    ]
    ...
}

Формат ответа и примеры

Описание формата

Бекенд клиента должен ответить на запрос с application/json в следующем формате:

  • totalPrice - итоговая цена корзины с учетом всех скидок и МА, без учета бонусов (Покупатель сам решает сколько потратить бонусов. Максимальное количество бонусов для списание контроллируется полем bonuses.canSpend)

  • appliedPromocode - примененный промокод (null если промокод не применен, или если введенный промокод невозможно применить)

  • notice - вне объекта items передается когда нужно вывести общее сообщение на всю корзину

  • promocodeStatus -статусы раннего доступа:

    • success -Код прикреплён

    • notFound -Неверный код

    • alreadyRedeemed -Код уже использованен

    • notRedeemable -Условия применения кода не выполнены

  • discount - суммарная скидка на заказ

  • showDoNotCallMeCheckbox - показывать чекбокс Не перезванивать

  • skipPayment - пропустить этап оплаты при оформлении заказа (опционально)

  • items - новый состав корзины (со скидками и подарками)

    • id - идентификатор товарного предложения в системе клиента (configurationID)

    • price - изначальная цена одного товара до скидок

    • discount - примененная скидка на всю позицию (на всё количество)

    • quantity - количество

    • subtotal - итого (subtotal = (price * quantity) - discount)

    • gift - (опционально) количество товаров данной позиции в подарок

    • appliedDiscounts - (опционально) JSON список идентификаторов примененных акций (например ["a1123767", "a98723677"])

    • bonuses - (опционально) информация по бонусам для данной позиции:

      • canSpend - максимальное число баллов для списания на данную позицию

      • willEarn - максимальное число баллов для накопления на данную позицию

    • itemKitId - string, id товарного набора, передается только если товар был добавлен из товарного набора

    • error - (опционально). Текст ошибки, если есть. Если есть хотя бы одна позиция с ошибкой, оформить такой заказ будет невозможно. Ошибка выводится в корзине напротив товара. Пример: "Товар недоступен для заказа"

    • notice - (опционально). Текст сообщения, выводится в корзине около товара, например, если есть акция 1+1 = 3 на данный товар, чтобы уведомить покупателя.

    • unavailableDeliveryMessage - (опционально,). Текст сообщения о проблеме с доставкой для этого товара, выводится в корзине около товара, например, если для товара недоступен самовывоз, чтобы покупатель понял почему у него он не доступен.

    • deliveryGroups - (опционально; значения: default, express, large) группы доступных доставок, массив; значение по умолчанию: ["default", "express", "large"] . Каждому из товаров можно назначить одну или несколько групп. По умолчанию будет принадлежать той группе, которая передана первой в списке. Пользователь сможет перемещать товар между группами, если их передано несколько (например, если доставка у одного из двух товаров недоступна, отказаться от доставки и забрать оба товара самовывозом).

    • canBePurchased - boolean, флаг, разрешающий покупателю ометить товар галочкой, делает товар доступным для выбора в корзине (опциональный, по умолчанию имеет значение true)

    • selected - boolean, флаг, задающий состояние галочки у товара, если true, то товар будет отмечен для оформления в заказ, если false, то товар будет отложен и останется в корзине (опциональный, по умолчанию имеет значение true)

Список поддерживаемых групп отправлений и их порядок отображения в корзине настраивается менеджером

  • addons - (опционально,) Доп. товары, например "Основание для кровати"

    • configurationId - ид товарного предложения из фида

  • warehouseId - (опционально) идентификатор склада/магазина/аутлета/ООО из фида наличия для маркетплейсов

  • bonuses - информация по бонусам для данного заказа

    • canSpend - можно списать бонусов на весь заказ суммарно

    • willEarn - будет накоплено баллов после заказа

  • deliveryGroupsBonuses - (опционально) информация по бонусам для разделенной корзины (см. пример)

    • deliveryGroupId - id группы доставок, представленной сейчас в корзине

      • canSpend - можно списать бонусов для заказов из группы deliveryGroupId

  • giftCards - подарочные карты, по одной

    • number - номер карты

    • pin – пин-код карты

    • success – возможность привязки карты, boolean

    • status – комментарий (отображение привязки подарочной карты в корзине, либо сообщение с причиной ошибки)

  • availablePromocodes – доступные промокоды (в разработке)

    • promocode – значение промокода, который добавится в корзину при выборе (до 30 символов, включая пробелы)

    • title – заголовок / название акции (до 20 символов, включая пробелы); напр. "Скидка 15%", "Доставка бесплатно"

    • description – краткое описание / призыв к действию / срок действия в свободном формате (до 35 символов, включая пробелы); напр. "На заказ от 8000р", "Только сегодня!", "Доступно до 31 декабря"

    • availableUntil – крайний срок возможности активации промокода; поле опционально (timestamp, отображается вместо description)

    • longDescription – подробное описание (до 100 символов, включая пробелы); текст доступен по нажатию на информер рядом с заголовком (поле опционально; при отсутствии значения, информер не отображается)

Пользователь может выбрать один из перечисленных промокодов. Одновременный выбор в рамках одного заказа недоступен. Если вас интересует такой сценарий - обсудите возможность его реализации с продакт-менеджером IMSHOP.IO

  • extraServices - дополнительные услуги, как реализовать *клик

  • eula – (опционально) договоры/пользовательские соглашения, которые должен принять пользователь для оформления заказа

{
    "totalPrice": 95000,
    "appliedPromocode": null,
    "discount": 1000,
    "notice": "Промокод действителен на курьерской доставке"
    "skipPayment": false,
    "items": [
        {
            "name": "Apple iPad (2018) 64Gb Wi-Fi, серебристый",
            "id": "12345",
            "price": 29990,
            "discount": 0,
            "quantity": 1,
            "subtotal": 29990,
            "bonuses": { "canSpend": 1990 },
            "addons": [
                {
                    "configurationId": "1234"
                }
            ],
            "itemKitId": "test-kit-1"
        },
        {
            "name": "Apple Pencil 1-го поколения",
            "id": "22345",
            "price": 8890,
            "discount": 1000,
            "quantity": 1,
            "subtotal": 7890,
            "appliedDiscounts": ["dd76656711"],
            "bonuses": { "canSpend": 0 },
            "unavailableDeliveryMessage": "Для корзины с этим товаром будет недоступен самомывывоз"
        },
        {
            "name": "Чехол Baseus для iPad 2018 черный",
            "id": "32345",
            "price": 2999,
            "discount": 2999,
            "quantity": 1,
            "appliedDiscounts": ["dd1218888"],
            "bonuses": { "canSpend": 0 }
        },
        {
            "name": "Чехол Baseus для iPad 2018 коричневый",
            "id": "42345",
            "price": 1000,
            "discount": 2000,
            "quantity": 3,
            "gift": 2,
            "appliedDiscounts": ["dd771086"],
            "notice": "Товар доступен только на самовывозе",
            "bonuses": { "canSpend": 0 }
        },
        {
            "name": "Чехол Baseus для iPad 2018 черный",
            "id": "87787",
            "price": 1000,
            "discount": 1000,
            "quantity": 1,
            "appliedDiscounts": ["dd771099"],
            "gift": 1,
            "bonuses": { "canSpend": 0 }
        },
        {
            "name": "Apple Mac Pro 2020",
            "id": "80008",
            "price": 5000000,
            "discount": 1000,
            "quantity": 1,
            "bonuses": { "canSpend": 0 },
         

Маркетинговые акции

Пользователь имеет возможность получить подарки, дополнительную скидку, или другую выгоду при оформлении заказа.

Формат ответа при пересчете корзины

Описание формата приведено в разделе Список "Маркетинговые акции"

{
  ...
  "promoGroups": [
    [
      {
        "id": "promo-id-1",
        "name": "Gift selection promo",
        "sumsWithBonuses": false,
        "giftOptions": [
          {
            "id": "8252",
            "quantity": 2
          },
          {
            "id": "13654",
            "quantity": 1
          }
        ],
        "giftOptionsLimit": 1
      },
      {
        "id": "promo-id-1-discount",
        "name": "Discount promo",
        "sumsWithBonuses": true,
        "discount": 1000
      }
    ],
    [
      {
        "id": "promo-id-2",
        "name": "Simple gifts promo",
        "sumsWithBonuses": true,
        "gifts": [
          {
            "id": "13654",
            "quantity": 1
          },
          {
            "id": "8252",
            "quantity": 2
          }
        ]
      }
    ]
  ]
  ...
}

Синхронизация корзины с сайтом и наоборот

Добавляется в запрос и в ответ расчета корзины:

  • lastSyncDate - (опционально) это timestamp, время последней синхронизации (в миллисекундах) корзины

{
    ...
      "lastSyncDate": 1644419057514,
    ...
}

Это поле отправляется в запросе только тогда, когда пользователь авторизован. Если приходит 0 (ноль) в запросе, то это означает что пользователь ничего не добавлял в корзину пока был неавторизован.

При реализации этой фичи мы ожидаем что вы:

  1. Добавите новое поле к примеру тоже lastSyncDate в базу данных с корзинами пользователей и изначальное значение этого поля для всех текущих и будущих корзин должно быть 0.

  2. При любом изменении корзины пользователя в базе данных, должны будете обновить поле lastSyncDate на текущий timestamp (время в миллисекундах).

  3. Добавите это поле в ответ, которое будет передавать его.

  4. При запросе от нас вы должны будете сравнивать две даты, которая пришла в запросе и которая хранится у вас в базе данных, в случае если дата в запросе свежее, то необходимо заменить весь состав корзины в вашей базе данных из нашего запроса и обновить поле lastSyncDate на то которое пришло из нашего запроса, а если же дата из вашей базы данных окажется свежее, то вы должны будете отправить то состояние корзины которое в вашей базе данных и отправить тот lastSyncDate которое у вас. Если же даты равные, то все отлично и запрос можно обработать как обычно. Если мы отправили 0 и у вас 0, то вам необходимо провести слияние (merge) нашего и вашего состава корзины и обновить поле lastSyncDate на текущий timestamp (время в миллисекундах).

  5. Если в запросе нет поля lastSyncDate значит юзер не залогинен в приложении и его корзину синхронизировать не надо.

Last updated