Suscripciones con Stripe para PrestaShop

Hooks y API de Suscripciones con Stripe para PrestaShop

Para desarrolladores de módulos que necesitan enterarse de lo que pasa con una suscripción (dar o quitar un servicio, avisar a un sistema externo) o suscribir a un cliente desde fuera de la ficha del producto. El uso del módulo desde el back office está en el manual.

Las clases de esta página son estáticas y no cambian de firma una vez publicadas. Antes de usarlas, carga el módulo con Module::getInstanceByName('bksubscriptions') y comprueba que está activo.

La suscripción que reciben los hooks

Todos los hooks de acción reciben subscription: la fila de la suscripción en la tienda, con sus líneas en lines. Los campos que más se usan son id_bk_subscription, id_customer, id_shop, status, currency, link_module y link_ref (el objeto de otro módulo al que está enlazada, si lo está).

actor, en los hooks que lo llevan, dice quién hizo el cambio: customer, merchant, stripe o system.

Hooks de acción

Hook Cuándo Además de subscription
actionBkSubscriptionCreated Alta o vuelta pagada id_order, reactivated, id_reactivated_from, backfill_periods
actionBkSubscriptionRenewed Renovación cobrada id_order, stripe_invoice, amount, period_end
actionBkSubscriptionPaymentFailed Cobro rechazado stripe_invoice, attempt_count, next_attempt (vacío: Stripe ya no reintenta), amount, error
actionBkSubscriptionCanceled Terminada: no se volverá a cobrar reason
actionBkSubscriptionPaused Pausa o entrega saltada periods, resumes_at (primer cobro tras la pausa), actor
actionBkSubscriptionResumed Fin de la pausa pedido por alguien actor
actionBkSubscriptionAddressChanged Dirección de envío o de facturación, o transportista type (delivery, invoice, carrier), old, new, actor

Los hooks se dan de alta al instalar y al actualizar el módulo, así que tu módulo puede registrarse en ellos aunque todavía no se hayan disparado.

public function hookActionBkSubscriptionRenewed(array $params)
{
    $subscription = $params['subscription'];
    if ($subscription['link_module'] === $this->name) {
        // Alarga el servicio del objeto enlazado hasta $params['period_end']
    }
}

Hooks que preguntan

Se llaman con Hook::exec(..., $arrayReturn = true) y solo cuenta la respuesta del módulo al que se pregunta.

actionBkSubscriptionLinkCheck

Antes de poner en el carrito una suscripción enlazada a un objeto de tu módulo. Recibe id_customer, id_product, id_product_attribute, link_module y link_ref. Contesta:

Clave Qué es
ok true si el cliente puede suscribirse a ese objeto
title El texto que verá el cliente bajo el nombre del producto (lo que lo distingue: su tienda, su dominio…)
backfill_periods Periodos atrasados que se cobran hoy (como mucho los del plan)
paid_until Opcional, AAAA-MM-DD: el objeto ya está pagado hasta ese día; hoy no se cobra y el primer cobro es ese día
returning Opcional: es una vuelta, y lleva la cuota de vuelta del plan
message El motivo, si ok es false

actionBkSubscriptionPresent

Para añadir filas a la tarjeta de la suscripción en «Mis suscripciones» y en su ficha del back office. Recibe subscription y back_office. Contesta una lista de filas ['label' => …, 'value' => …, 'url' => …]; con back_office el enlace debe llevar a la pantalla del comerciante.

Suscribir a un cliente desde fuera de la ficha

Con un formulario: un POST a module-bksubscriptions-subscribe con token (el del cliente), id_product, id_product_attribute y, opcionales, link_module, link_ref, back (la URL de la tienda a la que volver si no se puede) y renew (0: se paga el periodo y termina sola). El módulo pone la línea en el carrito y lleva al checkout; si no puede, vuelve a back con el motivo. Para pintarlo:

$form = Module::getInstanceByName('bksubscriptions')
    ->subscribeForm($idProduct, $idProductAttribute, $this->name, $ref, $backUrl);
// ['action' => url, 'fields' => [nombre => valor, …]]

Por PHP: BkSubscriptionsCart::subscribe(Cart $cart, $idProduct, $idProductAttribute, $linkModule, $linkRef, $renews = true) devuelve ['ok' => bool, 'error' => not_subscription|already_active|link_refused|cart, 'message' => string].

  • Con enlace, pregunta antes a tu módulo por actionBkSubscriptionLinkCheck.
  • Cada objeto enlazado es una sola línea del carrito con una unidad y su propio precio de hoy (los atrasados al precio de renovación y la cuota de vuelta si vuelve). Volver a pedir el mismo objeto sustituye su línea.
  • Un objeto con una suscripción que da servicio no admite otra.
  • Al pagarse, la suscripción nace con link_module y link_ref, y los hooks los llevan.

Otras piezas para montar la compra:

  • BkSubscriptionsCart::customerCart(Context $context): el carrito en curso del cliente, o uno nuevo.
  • BkSubscriptionsCart::reactivate(Cart $cart, BkSubscriptionsSubscription $old): pone en el carrito la vuelta a una suscripción terminada; BkSubscriptionsCart::returnQuote($old, $idCurrency) dice lo que costará hoy (today, backfill, return_fee).
  • BkSubscriptionsCart::saveLink($idCart, $idProduct, $idProductAttribute, $fields): liga una línea del carrito como complemento de otra (parent_product, parent_product_attribute) o a un objeto (link_module, link_ref, link_title, backfill_periods), con lo ya pagado (prepaid_periods, paid_until, renews).
  • BkSubscriptionsBilling::link($subscription, $linkModule, $linkRef): enlaza a un objeto tuyo una suscripción que nació sin enlace (por ejemplo, desde actionBkSubscriptionCreated).

Cambiar de plan

BkSubscriptionsBilling::changeLine($subscription, $idLine, $idProduct, $idProductAttribute, $actor) cambia una línea de una suscripción que da servicio por otro producto o combinación con plan del mismo periodo (más unidades, otro nivel), desde el próximo cobro y sin prorrateo. Lanza PrestaShopException con no_plan o line_not_found.

Leer

Método Devuelve
BkSubscriptionsSubscription::forLink($module, $ref) La suscripción que da servicio a ese objeto o, si no hay, la última
BkSubscriptionsSubscription::forOrder($idOrder) [['subscription', 'period', 'kind' => new\|renewal\|reactivate]]
BkSubscriptionsSubscription::recurringLinesOf($idOrder) Las líneas del pedido que se renuevan, [[id_product, id_product_attribute]]
BkSubscriptionsCart::checkoutRow($idCart)['kind'] Si el pedido de ese carrito es un alta (new) o una renovación (renewal); existe antes de validar el pedido
(new BkSubscriptionsPresenter($module, $context))->present($subscription, false) La suscripción redactada como la ve el cliente: estado, lo siguiente, importe por periodo

Planes

  • BkSubscriptionsPlan::upsertFor($idProduct, $idProductAttribute, $idShop, array $data, $managedBy = ''): crea o pone al día el plan de un producto o combinación (interval_unit, interval_count, trial_days, min_periods, total_periods, pause_max_periods, backfill_max, shipping_mode, addon_only, active, separate y prices por moneda con renewal_price, setup_fee y return_fee). Los campos que no pases se conservan. Con $managedBy, el plan queda a nombre de tu módulo y la ficha del producto lo enseña en solo lectura.
  • BkSubscriptionsPlan::removeFor($idProduct, $idProductAttribute, $idShop, $managedBy): borra solo un plan de ese dueño.
  • BkSubscriptionsPlan::exportFor($idProduct, $idProductAttribute, $idShop): el plan como array, o null.
  • BkSubscriptionsPlan::addonsFor($idProduct, $idProductAttribute, $idShop) y setAddonsFor($idProduct, $idShop, $addons): los complementos recurrentes de un producto.

Acciones del cliente desde otro módulo

Mantener una baja, pausar o volver los hace el cliente en «Mis suscripciones» (ancla #bksub-<id>). Tu módulo puede pintar el botón con un POST a module-bksubscriptions-account (bksub_action = keep, id_subscription, token), que hace la acción y vuelve a la tarjeta con su mensaje. Para la tarjeta de pago, un enlace a module-bksubscriptions-account#bksub-payment.

Para los temas

$modules.bksubscriptions.account_link (url, title, active) permite a un tema pintar el enlace a «Mis suscripciones» donde quiera; en ese caso llama al hook de la cuenta con bksub_in_theme=true para que el módulo no lo repita. El color de acento de «Mis suscripciones» es la variable CSS --bksub-accent.

Cuéntanos qué necesita tu negocio

Un módulo, una app, un servidor que da guerra o algo urgente. Te respondemos en menos de 24 horas, con un presupuesto cerrado con precio y fecha.