billwerk_subscriptions-1.x-dev/src/BillwerkDataObjectFactory.php

src/BillwerkDataObjectFactory.php
<?php

declare(strict_types=1);

namespace Drupal\billwerk_subscriptions;

use Drupal\billwerk_subscriptions\DataObject\BillwerkContract;
use Drupal\billwerk_subscriptions\DataObject\BillwerkContractComponentSubscription;
use Drupal\billwerk_subscriptions\DataObject\BillwerkContractSubscription;
use Drupal\billwerk_subscriptions\DataObject\BillwerkCustomer;
use Drupal\billwerk_subscriptions\Exception\CustomerExternalIdEmptyException;
use Drupal\billwerk_subscriptions\Exception\DataObjectException;

/**
 * Factory for the Billwerk data objects (DTO).
 *
 * Loads the data objects holding the relevant values from Billwerk.
 *
 * Typically you won't need to interact with this factory, but instead use the
 * Subscriber object.
 */
final class BillwerkDataObjectFactory {

  /**
   * Constructs a BillwerkDataObjectFactory object.
   */
  public function __construct(
    private readonly Api $api,
  ) {
  }

  /**
   * Factory to build the full BillwerkContract with all its parts.
   *
   * @param string $contractId
   *   The Billwerk Contract ID.
   *
   * @throws \Drupal\billwerk_subscriptions\Exception\DataObjectException.
   *
   * @return \Drupal\billwerk_subscriptions\DataObject\BillwerkContract
   *   The Billwerk Contract.
   */
  public function billwerkLoadBillwerkContract(string $contractId): BillwerkContract {
    $contractArray = $this->api->getContract($contractId);
    if (!empty($contractArray)) {
      if ($contractArray['Id'] !== $contractId) {
        throw new DataObjectException('Given contract ID did not match the returned result.');
      }

      if (empty($contractArray['CustomerId'])) {
        throw new DataObjectException('No CustomerId found for contract ID: "' . $contractId . '"');
      }

      // Build the BillwerkContract:
      $billwerkContract = new BillwerkContract(
      $contractArray['Id'],
      $contractArray['LifecycleStatus'],
      $this->billwerkLoadBillwerkCustomer($contractArray['CustomerId']),
      $this->billwerkLoadBillwerkContractSubscription($contractArray['Id']),
      );
      return $billwerkContract;
    }
    throw new DataObjectException('BillwerkContract could not be loaded for contract ID: "' . $contractId . '"');
  }

  /**
   * Factory to load the BillwerkCustomer by the given $customerId.
   *
   * Used internally to build the full BillwerkContract data object, but also
   * helpful standalone, if for example Billwerk only returns the CustomerId
   * without other details.
   *
   * @param string $customerId
   *   The Billwerk Customer ID.
   *
   * @throws \Drupal\billwerk_subscriptions\Exception\DataObjectException.
   *
   * @return \Drupal\billwerk_subscriptions\DataObject\BillwerkCustomer
   *   The Billwerk Customer.
   */
  public function billwerkLoadBillwerkCustomer(string $customerId): BillwerkCustomer {
    $customerArray = $this->api->getCustomer($customerId);
    if (!empty($customerArray)) {
      if ($customerArray['Id'] !== $customerId) {
        throw new DataObjectException('Given customer ID did not match the returned result.');
      }

      if (empty($customerArray['ExternalCustomerId'])) {
        throw new CustomerExternalIdEmptyException("The ExternalCustomerId of the Billwerk Customer ID #{$customerId} is empty. ExternalCustomerId always has to match the Drupal user id (UID)!");
      }

      // Build the BillwerkContract:
      $billwerkCustomer = new BillwerkCustomer(
      $customerArray['Id'],
      $customerArray['ExternalCustomerId'] ?? NULL,
      $customerArray['EmailAddress'] ?? NULL,
      $customerArray['Locale'] ?? NULL,
      $customerArray['IsDeletable'] ?? FALSE,
      $customerArray['IsLocked'] ?? FALSE,
      $customerArray['Hidden'] ?? FALSE,
      $customerArray['DeletedAt'] ?? NULL,
      );
      return $billwerkCustomer;
    }
    throw new DataObjectException('BillwerkCustomer by ID: "' . $customerId . '" did not return any data.');
  }

  /**
   * Load the BillwerkContractSubscription part of the BillwerkContract.
   *
   * @param string $contractId
   *   The Billwerk Contract ID.
   *
   * @throws \Drupal\billwerk_subscriptions\Exception\DataObjectException.
   *
   * @return \Drupal\billwerk_subscriptions\DataObject\BillwerkContractSubscription
   *   The Billwerk Contract Subscription.
   */
  protected function billwerkLoadBillwerkContractSubscription(string $contractId): BillwerkContractSubscription {
    $contractSubscriptionsArray = $this->api->getContractSubscriptions($contractId);
    if (!empty($contractSubscriptionsArray)) {
      if ($contractSubscriptionsArray['Id'] !== $contractId) {
        throw new DataObjectException('Given Contract ID did not match the returned result.');
      }

      if (empty($contractSubscriptionsArray['Phase'])) {
        throw new DataObjectException('No Phase information found for contract ID: "' . $contractId . '" subscriptions.');
      }

      if (empty($contractSubscriptionsArray['Phase']['PlanVariantId'])) {
        throw new DataObjectException("The given Billwerk Contract #{$contractId} has no (active) PlanVariantId. Billwerk Contracts may never be without a PlanVariantId.");
      }

      $componentSubscriptions = [];
      if (!empty($contractSubscriptionsArray['ComponentSubscriptions'])) {
        foreach ($contractSubscriptionsArray['ComponentSubscriptions'] as $componentSubscriptionArray) {
          if ($componentSubscriptionArray['ContractId'] !== $contractId) {
            throw new DataObjectException('Given Contract ID did not match the ContractId from the ComponentSubscription.');
          }
          $componentSubscriptions[$componentSubscriptionArray['Id']] = new BillwerkContractComponentSubscription(
          $componentSubscriptionArray['Id'],
          $componentSubscriptionArray['ComponentId'],
          $componentSubscriptionArray['Quantity'],
            $componentSubscriptionArray['StartDate'] ?? NULL,
            $componentSubscriptionArray['BilledUntil'] ?? NULL,
            $componentSubscriptionArray['EndDate'] ?? NULL,
          );
        }
      }
      // @codingStandardsIgnoreStart
      // This way we could also support DiscountSubscriptions if needed later:
      // $discountSubscriptions = [];
      // if(!empty($contractSubscriptionsArray['DiscountSubscriptions'])){
      //   foreach($contractSubscriptionsArray['DiscountSubscriptions'] as $discountSubscriptionArray){
      //     $discountSubscriptions[$discountSubscriptionArray['Id']] = ...;
      //   }
      // }.
      // @improve: We currently need an additional API call because Billwerk
      // does NOT provide the following standard values in the
      // https://sandbox.billwerk.com/api/v1/contracts/{id}/subscriptions
      // call!
      // @see https://billwerk.readme.io/reference/contracts_getsubscriptions_id_timestamp_get
      // @codingStandardsIgnoreEnd
      // We made a support request to add them, so maybe one day this additional
      // call can be removed and the values can just be retrieved from
      // $contractSubscriptionsArray!
      $contractDetailsArray = $this->api->getContract($contractId);

      // Build the BillwerkContract:
      $billwerkContract = new BillwerkContractSubscription(
      $contractSubscriptionsArray['Phase']['Type'],
      $contractSubscriptionsArray['Phase']['PlanVariantId'],
      $contractSubscriptionsArray['Phase']['PlanId'],
      $contractSubscriptionsArray['Phase']['Quantity'],
        $contractSubscriptionsArray['Phase']['StartDate'],
        $contractDetailsArray['EndDate'] ?? NULL,
        $contractDetailsArray['TrialEndDate'] ?? NULL,
        $contractDetailsArray['BilledUntil'] ?? NULL,
        $contractDetailsArray['LastBillingDate'] ?? NULL,
        $contractDetailsArray['NextBillingDate'] ?? NULL,
        $contractDetailsArray['Currency'] ?? NULL,
        $contractDetailsArray['Balance'] ?? NULL,
      $componentSubscriptions
      );
      return $billwerkContract;
    }
    throw new DataObjectException('BillwerkContract could not be loaded for contract ID: "' . $contractId . '"');
  }

}

Главная | Обратная связь

drupal hosting | друпал хостинг | it patrol .inc