<?php namespace QUI\ERP\Payments\Stripe\PaymentMethods\Recurring; use QUI; use QUI\ERP\Accounting\Invoice\Invoice; use QUI\ERP\Order\AbstractOrder; use QUI\ERP\Payments\Stripe\AbstractBasePayment; use Stripe\Exception\ApiErrorException; use Stripe\PaymentIntent as StripePaymentIntent; use QUI\ERP\Accounting\Payments\Types\RecurringPaymentInterface; use QUI\ERP\Payments\Stripe\Provider; use Stripe\Subscription as StripeSubscription; use QUI\ERP\Payments\Stripe\Utils; /** * Class BaseRecurringPayment * * Stripe payment for recurring payments */ abstract class AbstractBaseRecurringPayment extends AbstractBasePayment implements RecurringPaymentInterface { /** * Return attributes for creating a PaymentIntent * * @param AbstractOrder $Order * @param string $paymentMethodId - Stripe PaymentMethod ID * @return StripePaymentIntent * * @throws ApiErrorException * @throws QUI\Exception */ protected function createPaymentIntentForOrder(AbstractOrder $Order, $paymentMethodId) { return StripePaymentIntent::create([ 'payment_method' => $paymentMethodId, 'amount' => Utils::getCentAmount($Order), 'currency' => mb_strtolower($Order->getCurrency()->getCode()), 'confirmation_method' => 'manual', 'confirm' => true, 'setup_future_usage' => 'off_session', 'use_stripe_sdk' => true, 'description' => Utils::getPaymentDescriptionForOrder($Order) ]); } /** * Create a Scubscription from a (temporary) Order * * @param AbstractOrder $Order * @return string - Subscription ID * * @throws \Exception */ public function createSubscription(AbstractOrder $Order) { return Subscriptions::createSubscription($Order); } /** * Capture subscription amount based on an Invoice * * @param Invoice $Invoice * @return void * * @throws \Exception */ public function captureSubscription(Invoice $Invoice) { Subscriptions::billSubscriptionBalance($Invoice); } /** * Cancel a Subscription * * @param int|string $subscriptionId * @param string $reason (optional) - The reason why the subscription is cancelled * @return void * * @throws \Exception */ public function cancelSubscription($subscriptionId, $reason = '') { Subscriptions::cancelSubscription($subscriptionId, $reason); } /** * Sets a subscription as inactive (on the side of this QUIQQER system only!) * * IMPORTANT: This does NOT mean that the corresponding subscription at the payment provider * side is cancelled. If you want to do this please use cancelSubscription() ! * * @param $subscriptionId * @return void */ public function setSubscriptionAsInactive($subscriptionId) { Subscriptions::setSubscriptionAsInactive($subscriptionId); } /** * Can the Subscription of this payment method be edited * regarding essential data like invoice frequency, amount etc.? * * @return bool */ public function isSubscriptionEditable() { return false; } /** * Check if a Subscription is associated with an order and * return its ID (= identification at the payment method side; e.g. PayPal) * * @param AbstractOrder $Order * @return int|string|false - ID or false of no ID associated */ public function getSubscriptionIdByOrder(AbstractOrder $Order) { try { $result = QUI::getDataBase()->fetch([ 'select' => ['stripe_id'], 'from' => Provider::getStripeBillingSubscriptionsTable(), 'where' => [ 'global_process_id' => $Order->getHash() ] ]); } catch (\Exception $Exception) { QUI\System\Log::writeException($Exception); return false; } if (empty($result)) { return false; } return $result[0]['stripe_id']; } /** * Checks if the subscription is active at the payment provider side * * @param string|int $subscriptionId * @return bool */ public function isSubscriptionActiveAtPaymentProvider($subscriptionId) { try { $data = Subscriptions::getSubscriptionDetails($subscriptionId); } catch (\Exception $Exception) { QUI\System\Log::writeException($Exception); return true; } if (empty($data)) { QUI\System\Log::addError( 'Stripe subscription details are empty (ID #'.$subscriptionId.'). Please check manually.' ); return true; } return $data['status'] === StripeSubscription::STATUS_ACTIVE; } /** * Checks if the subscription is active at QUIQQER * * @param string|int $subscriptionId - Payment provider subscription ID * @return bool */ public function isSubscriptionActiveAtQuiqqer($subscriptionId) { try { $result = QUI::getDataBase()->fetch([ 'select' => ['active'], 'from' => Provider::getStripeBillingSubscriptionsTable(), 'where' => [ 'stripe_id' => $subscriptionId ] ]); } catch (\Exception $Exception) { QUI\System\Log::writeException($Exception); return true; } if (empty($result)) { return false; } return !empty($result[0]['active']); } /** * Get IDs of all subscriptions * * @param bool $includeInactive (optional) - Include inactive subscriptions [default: false] * @return int[] */ public function getSubscriptionIds($includeInactive = false) { $where = []; if (empty($includeInactive)) { $where['active'] = 1; } try { $result = QUI::getDataBase()->fetch([ 'select' => ['stripe_id'], 'from' => Provider::getStripeBillingSubscriptionsTable(), 'where' => $where ]); } catch (\Exception $Exception) { QUI\System\Log::writeException($Exception); return []; } return \array_column($result, 'stripe_id'); } /** * Get global processing ID of a subscription * * @param string|int $subscriptionId * @return string|false */ public function getSubscriptionGlobalProcessingId($subscriptionId) { try { $result = QUI::getDataBase()->fetch([ 'select' => ['global_process_id'], 'from' => Provider::getStripeBillingSubscriptionsTable(), 'where' => [ 'stripe_id' => $subscriptionId ] ]); } catch (\Exception $Exception) { QUI\System\Log::writeException($Exception); return false; } if (empty($result)) { return false; } return $result[0]['global_process_id']; } /** * If the Payment method is a payment gateway, it can return a gateway display * * @param AbstractOrder $Order * @param QUI\ERP\Order\Controls\OrderProcess\Processing $Step * @return string * * @throws QUI\Exception */ public function getGatewayDisplay(AbstractOrder $Order, $Step = null) { $type = $this->getPaymentMethodType(); $Control = new PaymentDisplay([ 'paymentMethod' => $type, 'infoText' => $this->getPaymentStepInfo() ]); $Control->setAttribute('Order', $Order); $stepTitle = $this->getPaymentStepTitle(); $Step->setTitle($stepTitle); $Engine = QUI::getTemplateManager()->getEngine(); $Engine->assign([ 'stepTitle' => $stepTitle ]); $Step->setContent($Engine->fetch(dirname(__FILE__, 3).'/PaymentDisplay.Header.html')); return $Control->create(); } /** * Does the payment ONLY support recurring payments (e.g. for subscriptions)? * * @return bool */ public function supportsRecurringPaymentsOnly() { return true; } }