Подписка с дополнениями

Подписка с дополнениями позволяет объединить несколько продуктов по подписке, которые можно приобрести, оплатить и которыми можно управлять вместе. Существующие подписки из каталога товаров можно предлагать в качестве дополнений без предварительного указания или дополнительной настройки. Вы можете запустить процесс покупки с несколькими существующими подписками и продавать их как дополнения.

Что нужно учесть

При использовании подписок с дополнениями учитывайте следующее:

  • Подписки с дополнениями поддерживаются только для основных планов с автоматическим продлением.

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

  • В подписке с дополнениями может быть не более 50 позиций.

  • Эта функция недоступна в Южной Корее (KR).

Интеграция с библиотекой Play Платежей

В этом разделе описывается, как интегрировать подписку с дополнениями в библиотеку Google Play Платежей. Предполагается, что вы знакомы с начальными этапами интеграции библиотеки Google Play Платежей, такими как добавление зависимости библиотеки в приложение, инициализация BillingClient и подключение к Google Play. В этом разделе рассматриваются аспекты интеграции PBL, относящиеся к подписке с дополнениями.

Запуск процесса покупки

Чтобы запустить процесс покупки подписки с дополнениями, выполните следующие действия:

  1. Получите все объекты подписки с помощью метода BillingClient.queryProductDetailsAsync.

  2. Задайте объект ProductDetailsParams для каждого товара.

    Объект ProductDetailsParams, представляющий товар, указывает как ProductDetails, обозначающий товар по подписке, так и offerToken, выбирающий определенную подписку base plan или offer.

  3. Укажите сведения об объекте в методе BillingFlowParams.Builder.setProductDetailsParamsList. Класс BillingFlowParams определяет детали процесса покупки.

    В примере ниже показано, как запустить сценарий оплаты для покупки подписки с несколькими товарами.

    Java

       BillingClient billingClient = …;
    
        // ProductDetails obtained from queryProductDetailsAsync().
        ProductDetailsParams productDetails1 = ...;
        ProductDetailsParams productDetails2 = ...;
        ArrayList productDetailsList = new ArrayList<>();
        productDetailsList.add(productDetails1);
        productDetailsList.add(productDetails2);
    
        BillingFlowParams billingFlowParams =
            BillingFlowParams.newBuilder()
               .setProductDetailsParamsList(productDetailsList)
               .build();
        billingClient.launchBillingFlow(billingFlowParams);

Правила, применимые к товарам в покупке

  • Чтобы даты продления дополнения и основного контента совпадали, Google Play может взимать пропорциональную плату после окончания пробного периода или действия начальной цены.
  • Соответствие требованиям будет оцениваться отдельно для каждого товара.

Обработка покупок

Обработка подписки с дополнениями выполняется так же, как и обработка покупки одной подписки, описанная в статье Как интегрировать библиотеку Google Play Платежей в приложение. Единственное отличие заключается в том, что пользователь может получить несколько прав доступа в рамках одной покупки. При покупке подписки с дополнениями возвращается несколько объектов, которые можно получить с помощью метода Purchase.getProducts() в библиотеке Google Play Платежей, а затем списка lineItems в purchases.subscriptionsv2.get Google Play Developer API.

Как изменить подписку с дополнениями

Любые изменения в подписке с дополнениями приводят к повышению или понижению уровня. Подробнее о смене подписки…

Чтобы изменить или восстановить существующую покупку подписки с дополнениями в приложении, вызовите API launchBillingFlow с дополнительными параметрами и убедитесь, что:

  • Всегда вызывайте setOldPurchaseToken с токеном покупки текущей подписки.
  • Чтобы повысить, понизить или изменить уровень подписки, вызовите метод SubscriptionProductReplacementParams.setReplacementMode и укажите, как должен выполняться переход со старого плана на новый. В противном случае задавать SubscriptionProductReplacementParams не нужно.
  • Если базовый объект не изменен, вы все равно можете вызвать SubscriptionProductReplacementParams.setSubscriptionReplacementMode, чтобы применить определенное поведение замены. В этом случае действуют правила, описанные в разделе Повторное оформление или смена тарифного плана в рамках одной подписки.
  • Новые дополнения начнут действовать сразу, а сумма первого платежа за них будет изменена пропорционально времени, оставшемуся до окончания текущего расчетного периода. Это нужно, чтобы основная подписка и дополнение продлевались совместно.
  • Срок действия удаленных дополнений истечет в конце текущего расчетного периода.
  • При запуске сценария оплаты вам нужно будет указать все активные элементы в подписке с дополнениями, за исключением тех, которые нужно удалить, а также все новые дополнения.

В примере ниже показано, как вызвать API launchBillingFlow при изменении существующей покупки подписки с дополнениями.

Java

BillingClient billingClient = …;

int replacementMode =…;

// ProductDetails obtained from queryProductDetailsAsync().
ProductDetailsParams productDetails1 = ...;
ProductDetailsParams productDetails2 = ...;
ProductDetailsParams productDetails3 = ...;

ArrayList newProductDetailsList = new ArrayList<>();
newProductDetailsList.add(productDetails1);
newProductDetailsList.add(productDetails1);
newProductDetailsList.add(productDetails1);

BillingFlowParams billingFlowParams =
    BillingFlowParams.newBuilder()
        .setSubscriptionUpdateParams(
          SubscriptionUpdateParams.newBuilder()
              .setOldPurchaseToken(purchaseTokenOfExistingSubscription)
              // No need to set if change does not affect the base item.
             .setSubscriptionReplacementMode(replacementMode)
             .build())
        .setProductDetailsParamsList(productDetailsList)
        .build();

billingClient.launchBillingFlow(billingFlowParams);

Сценарии изменения подписки

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

При использовании SubscriptionProductReplacementParams

Существующие объекты Измененные объекты Нужно ли задавать режим замены в SubscriptionProductReplacementParams? Поведение
A (базовый объект), B A (базовый товар) Да (используйте KEEP_EXISTING)
  • Объект B запланирован для отложенного удаления.
  • Объект А сохраняется.
  • Для пользователей сохранится текущая цена на объект A, включая остаток начальных платежей, которые они получили при регистрации.
A A (базовый объект), B Да (используйте KEEP_EXISTING для A)
  • Объект B добавляется сразу с пропорциональной оплатой.
  • Объект А сохраняется.
  • Для пользователей сохранится текущая цена на объект A, включая остаток начальных платежей, которые они получили при регистрации.
A (базовый объект), B A (базовый объект), C Да (используйте KEEP_EXISTING для A)
  • Видео B будет удалено позже.
  • C добавляется сразу с пропорциональной оплатой.
  • Объект А сохраняется.
  • Для пользователей сохранится текущая цена на объект A, включая остаток начальных платежей, которые они получили при регистрации.
A (базовый объект), B B (базовый объект) Нет Видео A будет удалено через семь дней.
A (базовый объект), B C (базовый объект) Да
  • Замена A -> C зависит от SubscriptionProductReplacementParams replacementMode
  • Видео B запланировано к удалению.
A (базовый объект), B C (базовый товар), B Да
  • Замена для A -> C зависит от SubscriptionProductReplacementParams replacementMode.
  • Чтобы оставить объект B без изменений, задайте для него режим замены KEEP_EXISTING.
A (базовый объект), B C (базовый объект), D Да
  • Замена для A -> C зависит от SubscriptionProductReplacementParams replacementMode.
  • Видео B будет удалено позже.
  • D добавляется сразу с перерасчетом стоимости.
A (базовый объект), B A (базовый объект), C Да
  • Замена A -> A и B -> C зависит от режима замены, указанного в SubscriptionProductReplacementParams replacementMode в каждом ProductDetailsParams.
  • Чтобы оставить объект A без изменений, задайте для него режим замены KEEP_EXISTING.
A (базовый объект), B, C D (базовый объект), B, C Да
  • Замена A->D, B->B и C->C зависит от режима замены, указанного в SubscriptionProductReplacementParams replacementMode в каждом ProductDetailsParams.
  • Чтобы оставить объекты B и C без изменений, задайте для них режим замены KEEP_EXISTING.

При использовании SubscriptionUpdateParams

Существующие объекты Измененные объекты Нужно ли задавать информацию о замене? Поведение
A (базовый объект), B A (базовый товар) Нет
  • Объект B запланирован к отложенному удалению.
  • Поведение объекта A зависит от настройки Изменения основного плана и специального предложения.
  • Цена на товар А обновляется до последней, и пользователи могут потерять все начальные платежи, которые они получили во время регистрации, в зависимости от критериев соответствия предложения.
A A (базовый объект), B Нет
  • Объект B добавляется сразу с пропорциональной оплатой.
  • Поведение объекта А зависит от настройки Изменения основного плана и специального предложения в основном плане.
  • Цена на товар А будет обновлена до актуальной, и пользователи могут потерять доступ к начальной цене, которую они получили при оформлении подписки, в зависимости от критериев допуска к специальному предложению.
A (базовый объект), B A (базовый объект), C Нет
A (базовый объект), B B (базовый объект) Нет Видео A будет удалено через семь дней.
A (базовый объект), B C (базовый объект) Да
  • Замена A -> C зависит от setSubscriptionReplacementMode (устарело в PBL 8.1).
  • Видео B будет удалено позже.
A (базовый объект), B C (базовый товар), B Да Замена для A -> C зависит от setSubscriptionReplacementMode (устарело в PBL 8.1).
A (базовый объект), B C (базовый объект), D Да
  • Замена для A -> C зависит от setSubscriptionReplacementMode (устарело в PBL 8.1).
  • Видео B будет удалено позже.
  • D добавляется сразу с пропорциональной оплатой.

Уведомления для разработчиков в режиме реального времени

Поле subscriptionId не указывается в уведомлениях для разработчиков в режиме реального времени о покупке подписок с дополнениями, которые содержат несколько прав на контент. Вместо этого вы можете использовать Play Developer API, чтобы получить информацию о покупке и связанных с ней правах на контент.

Изменение цен для существующих подписчиков

Изменение стоимости подписки с дополнениями для существующих подписчиков выполняется так же, как и для обычной подписки. Подробнее о том, как изменить стоимость подписки… Однако есть некоторые ограничения и функциональные различия, описанные в этом разделе.

Как отключить когорту старых цен

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

  • Для всех ожидающих повышения цен с запросом согласия должно быть установлено одно и то же время продления с новой ценой. Если для объекта в подписке с дополнениями повышается цена с запросом согласия и пользователь ещё не подтвердил это, то любое новое повышение цены с запросом согласия для других объектов в покупке будет игнорироваться, если только оно не приведет к тому же времени продления применения новой цены, что и существующее повышение цены в состоянии OUTSTANDING. После того как пользователь подтвердит повышение цены, будут зарегистрированы все новые изменения цены. Пользователи могут принять все неподтвержденные повышения цены с запросом согласия только одновременно.

    Пример:

    • Рассмотрим подписку с дополнениями (товары A и B), которая продлевается 7-го числа каждого месяца.
    • Цена на товар А повышается с 7 до 10 долларов США. Изменение должно вступить в силу 7 июля.
    • 2 июня начинается обновление цены для товара Б – с 5 до 6 долларов США. Поскольку повышение цены с запросом согласия начинается через 37 дней после переноса, самое раннее повышение цены для товара Б произойдет 7 августа.

    В этом случае, пока пользователь не примет изменение цены для объекта A (пока он не перейдет в состояние CONFIRMED), изменение цены для объекта B не будет зарегистрировано для этой покупки подписки, а SubscriptionPurchaseV2 не вернет сведения об изменении цены для объекта B. После того как пользователь подтвердит изменение цены для товара А, начнется изменение цены для товара Б. Пользователь получит уведомление о повышении цены с запросом согласия на товар Б только после того, как согласится на повышение цены с запросом согласия на товар А.

  • В письме от Google Play будет список всех товаров, цены на которые повысятся или понизятся в один и тот же день.

Как отменить подписку с дополнениями

Пользователи могут отменить всю покупку подписки с дополнениями в центре подписок Google Play, а вы – только с помощью Google Play Developer API.

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

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

Ниже приведены некоторые рекомендации по отмене подписок и возврату средств за них.

  • В Play Console можно вернуть средства за определенный заказ, не отменяя доступ к подписке.

  • Вызовите метод orders.refund, чтобы полностью вернуть средства за определенные платежи по подписке, не отменяя доступ к ней.

  • Вызовите метод purchases.subscriptionsv2.revoke, чтобы немедленно отозвать доступ ко всем объектам подписки. С помощью этого API вы можете:

    • Закрыть доступ ко всем товарам и вернуть средства пропорционально.

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

    • Отзовите доступ ко всем товарам и выполните полный возврат средств (FullRefund).

    • Отменить доступ к отдельному объекту с полным возвратом средств за него.

Как отменить отдельный элемент в подписке с дополнениями

Чтобы отозвать отдельные элементы подписки с дополнениями, не отменяя всю покупку, вызовите метод purchases.subscriptionsv2.revoke с полем ItemBasedRefund, заданным в RevocationContext. В поле ItemBasedRefund можно указать productId товара, который нужно отозвать и за который нужно вернуть средства.

Поле ItemBasedRefund можно задать для покупок с одним или несколькими товарами, приобретаемыми по подписке с автоматическим продлением.

  • Если после отзыва товара, указанного в ItemBasedRefund, в подписке останутся активные товары, будет отозван только этот товар и за него будет полностью возвращена оплата. Статус подписки не изменится.
  • Если после отзыва объекта, указанного в ItemBasedRefund, в подписке не осталось активных объектов, то объект отзывается, средства за него возвращаются в полном объеме, а подписка отменяется.

Что нужно учесть

  • При использовании ItemBasedRefund можно отозвать только один элемент за раз. Если нужно отозвать несколько объектов, запрос можно вызвать несколько раз.
  • Если покупка подписки находится в любом из состояний отклонения платежа или если объект, указанный в ItemBasedRefund, не принадлежит пользователю или срок его действия истек, то отказ от объекта блокируется.
  • В подписке с предоплатой нельзя уменьшить количество лицензий.

Отложить оплату

Вы можете перенести дату следующего платежа за подписку с дополнениями, используя метод Purchases.subscriptionsv2:defer.

Если вы откладываете подписку с дополнениями, все ее элементы откладываются на один и тот же срок. В течение этого периода пользователь сохраняет полный доступ ко всем товарам, но плата с него не взимается. Дата продления для всех элементов будет изменена на новую.

Это может быть полезно для проведения промоакций или в качестве жеста доброй воли по отношению к клиентам. Оплату можно отложить на срок от одного дня до одного года за вызов API. Вы можете вызывать API несколько раз, чтобы продлить отсрочку до наступления новой даты оплаты.

При этом срабатывает уведомление для разработчиков в режиме реального времени SUBSCRIPTION_DEFERRED.

Истечение срока действия товара при отклонении платежа

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

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

Выбор периода восстановления

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

Активными считаются объекты, которые были активны при покупке подписки с дополнениями непосредственно перед попыткой продления. Исключаются любые недавно добавленные объекты (которые не будут доступны до восстановления) и любые объекты, которые больше не активны из-за удаления или отказа.

Применяется настройка временной блокировки аккаунта для элемента с минимальным льготным периодом. Если у нескольких элементов минимальный льготный период совпадает, а время временной блокировки аккаунта различается, то применяется самое большое значение.

Льготный период

Если платеж за продление подписки отклонен, для нее начинается льготный период. В течение льготного периода пользователь сохраняет доступ ко всем активным объектам из предыдущего периода продления. Если по истечении льготного периода способ оплаты не будет исправлен, подписка будет приостановлена. Если в течение льготного периода наступит дата продления других товаров, то после восстановления подписки будет инициирована новая попытка списания средств за эти товары.

Временная блокировка аккаунта

Пока покупка подписки находится в статусе временной блокировки аккаунта, доступ ко всем элементам подписки приостановлен до восстановления платежа.

Если подписка, которая была временно заблокирована, восстановлена, она продолжает действовать. Если подписка не восстановлена, срок действия товаров, за которые не удалось списать средства, истечет, а доступ к остальным товарам будет возобновлен на оставшуюся часть расчетного периода.

Пример:

  • У пользователя есть подписка Мой основной план, которая продлевается первого числа каждого месяца. 15 августа он добавляет Дополнительный план за 10 долларов США в месяц с семидневным бесплатным пробным периодом. Ни для одного из них не задан льготный период, а временная блокировка аккаунта составляет 30 дней.

  • 22 августа с пользователя списывается 2, 90 доллара США (10*9/31) за период до 31 августа, но срок действия способа оплаты истекает раньше, и 22 августа платеж отклоняется.

Когда подписка переходит в статус временной блокировки аккаунта из-за отклонения платежа, пользователь теряет доступ ко всем элементам подписки с дополнениями. Оставшееся время для объектов, которые не продлеваются, будет возвращено пользователям, когда подписка выйдет из режима временной блокировки аккаунта, поскольку платеж был восстановлен или отменен.

В предыдущем примере подписка переходит во временную блокировку аккаунта 22 августа.

  • Если аккаунт будет восстановлен 25 августа, то есть до даты продления 1 сентября, пользователь получит доступ к основному плану и дополнению в тот же день. Следующая дата выставления счета – 4 сентября.

  • Если аккаунт не будет восстановлен в течение 30 дней, подписка будет отменена 21 сентября. Пользователь потеряет доступ к дополнительному плану, но сможет пользоваться основным планом до 30 сентября.

В этом примере вам нужно получить обновленный expiryTime для ВСЕХ товаров в подписке с дополнениями, так как некоторые товары могут возобновить свое право на использование после льготного периода и временной блокировки аккаунта.

Финансовая отчетность и сверка

Используйте отчет о доходах, чтобы сопоставить активные подписки с транзакциями в Google Play. У каждой позиции транзакции есть идентификатор заказа. Если покупка включает несколько товаров, в отчетах о доходах и расчетном объеме продаж будут отдельные строки для каждой транзакции, например для цены, комиссии, налога и возврата средств за каждый товар.

Для панелей управления в Play Console:

  • Статистика доходов в разделе Финансовые отчеты Play Console разбита по товарам.

  • В разделе управления заказами отражается покупка подписки с дополнениями и показываются подробные списки приобретенных товаров. В разделе управления заказами вы можете отменить покупку или вернуть за нее средства.