[REF] Cleanup code to determine financial_type_id
[civicrm-core.git] / CRM / Financial / BAO / Order.php
index ffe8af8ff9737937e1ebfa2a6a836cb53a683db6..f1d0c771db3775be05406777876597fa5ebbc630 100644 (file)
@@ -15,11 +15,14 @@ use Civi\Api4\PriceField;
  *
  * @package CRM
  * @copyright CiviCRM LLC https://civicrm.org/licensing
+ *
  * Order class.
  *
  * This class is intended to become the object to manage orders, including via Order.api.
  *
  * As of writing it is in the process of having appropriate functions built up.
+ * It should **NOT** be accessed directly outside of tested core methods as it
+ * may change.
  */
 class CRM_Financial_BAO_Order {
 
@@ -75,6 +78,67 @@ class CRM_Financial_BAO_Order {
    */
   protected $priceFieldMetadata = [];
 
+  /**
+   * Metadata for price sets.
+   *
+   * @var array
+   */
+  protected $priceSetMetadata = [];
+
+  /**
+   * Get form object.
+   *
+   * @return \CRM_Core_Form|NULL
+   */
+  public function getForm(): ?CRM_Core_Form {
+    return $this->form;
+  }
+
+  /**
+   * Set form object.
+   *
+   * @param \CRM_Core_Form|NULL $form
+   */
+  public function setForm(?CRM_Core_Form $form): void {
+    $this->form = $form;
+  }
+
+  /**
+   * The serialize & unserialize functions are to prevent the form being serialized & stored.
+   *
+   * The form could be potentially large & circular.
+   *
+   * We simply serialize the values needed to re-serialize the form.
+   *
+   * @return array
+   */
+  public function _serialize(): array {
+    return [
+      'OverrideTotalAmount' => $this->getOverrideTotalAmount(),
+      'OverrideFinancialType' => $this->getOverrideFinancialTypeID(),
+      'PriceSelection' => $this->getPriceSelection(),
+    ];
+  }
+
+  /**
+   * Re-instantiate the the class with non-calculated variables.
+   *
+   * @param array $data
+   */
+  public function _unserialize(array $data): void {
+    foreach ($data as $key => $value) {
+      $fn = 'set' . $key;
+      $this->$fn($value);
+    }
+  }
+
+  /**
+   * Form object - if present the buildAmount hook will be called.
+   *
+   * @var \CRM_Member_Form_Membership|\CRM_Member_Form_MembershipRenewal
+   */
+  protected $form;
+
   /**
    * Get Set override for total amount of the order.
    *
@@ -92,7 +156,7 @@ class CRM_Financial_BAO_Order {
    *
    * @param float $overrideTotalAmount
    */
-  public function setOverrideTotalAmount(float $overrideTotalAmount) {
+  public function setOverrideTotalAmount(float $overrideTotalAmount): void {
     $this->overrideTotalAmount = $overrideTotalAmount;
   }
 
@@ -176,13 +240,50 @@ class CRM_Financial_BAO_Order {
    * @param int $id
    *
    * @return array
-   * @throws \CiviCRM_API3_Exception
    */
   public function getPriceFieldSpec(int $id) :array {
-    if (!isset($this->priceFieldMetadata[$id])) {
-      $this->priceFieldMetadata = CRM_Price_BAO_PriceSet::getCachedPriceSetDetail($this->getPriceSetID())['fields'];
+    return $this->getPriceFieldsMetadata()[$id];
+  }
+
+  /**
+   * Get the metadata for the fields in the price set.
+   *
+   * @return array
+   */
+  public function getPriceFieldsMetadata(): array {
+    if (empty($this->priceFieldMetadata)) {
+      $this->getPriceSetMetadata();
+      if ($this->getForm()) {
+        CRM_Utils_Hook::buildAmount($this->form->getFormContext(), $this->form, $this->priceFieldMetadata);
+      }
     }
-    return $this->priceFieldMetadata[$id];
+    return $this->priceFieldMetadata;
+  }
+
+  /**
+   * Get the metadata for the fields in the price set.
+   *
+   * @return array
+   */
+  public function getPriceSetMetadata(): array {
+    if (empty($this->priceSetMetadata)) {
+      $priceSetMetadata = CRM_Price_BAO_PriceSet::getCachedPriceSetDetail($this->getPriceSetID());
+      $this->priceFieldMetadata = $priceSetMetadata['fields'];
+      unset($priceSetMetadata['fields']);
+      $this->priceSetMetadata = $priceSetMetadata;
+    }
+    return $this->priceSetMetadata;
+  }
+
+  /**
+   * Get the financial type id for the order.
+   *
+   * This may differ to the line items....
+   *
+   * @return int
+   */
+  public function getFinancialTypeID(): int {
+    return (int) $this->getOverrideFinancialTypeID() ?: $this->getPriceSetMetadata()['financial_type_id'];
   }
 
   /**
@@ -193,7 +294,7 @@ class CRM_Financial_BAO_Order {
    *
    * @param array $input
    */
-  public function setPriceSelectionFromUnfilteredInput(array $input) {
+  public function setPriceSelectionFromUnfilteredInput(array $input): void {
     foreach ($input as $fieldName => $value) {
       if (strpos($fieldName, 'price_') === 0) {
         $fieldID = substr($fieldName, 6);