Merge pull request #4296 from mrpaulc/CRM-14751
[civicrm-core.git] / CRM / Price / BAO / LineItem.php
index cb6e6f19e119dd2b5684b72d5311bac1bb157421..333685d6328ca7112ad4436bb2d2aa07a343b65b 100644 (file)
@@ -55,16 +55,31 @@ class CRM_Price_BAO_LineItem extends CRM_Price_DAO_LineItem {
    * @static
    */
   static function create(&$params) {
-    //create mode only as we don't support editing line items
+    $id = CRM_Utils_Array::value('id', $params);
+    if ($id) {
+      CRM_Utils_Hook::pre('edit', 'LineItem', $id, $params);
+    }
+    else {
+      CRM_Utils_Hook::pre('create', 'LineItem', $params['entity_id'], $params);
+    }
 
-    CRM_Utils_Hook::pre('create', 'LineItem', $params['entity_id'], $params);
+    // unset entity table and entity id in $params
+    // we never update the entity table and entity id during update mode
+    if ($id) {
+      unset($params['entity_id'], $params['entity_table']);
+    }
 
     $lineItemBAO = new CRM_Price_BAO_LineItem();
     $lineItemBAO->copyValues($params);
 
     $return = $lineItemBAO->save();
 
-    CRM_Utils_Hook::post('create', 'LineItem', $params['entity_id'], $params);
+    if ($id) {
+      CRM_Utils_Hook::post('edit', 'LineItem', $id, $params);
+    }
+    else {
+      CRM_Utils_Hook::post('create', 'LineItem', $params['entity_id'], $params);
+    }
 
     return $return;
   }
@@ -99,7 +114,7 @@ class CRM_Price_BAO_LineItem extends CRM_Price_DAO_LineItem {
    * @return null|string
    */
   static function getLineTotal($entityId, $entityTable) {
-    $sqlLineItemTotal = "SELECT SUM(li.line_total)
+    $sqlLineItemTotal = "SELECT SUM(li.line_total + COALESCE(li.tax_amount,0))
 FROM civicrm_line_item li
 WHERE li.entity_table = '{$entityTable}'
 AND li.entity_id = {$entityId}
@@ -108,6 +123,16 @@ AND li.entity_id = {$entityId}
     return $lineItemTotal;
   }
 
+  /**
+   * wrapper for line item retrieval when contribution ID is known
+   * @param $contributionID
+   *
+   * @return array
+   */
+  static function getLineItemsByContributionID($contributionID) {
+     return self::getLineItems($contributionID,'contribution', NULL, TRUE, TRUE, " WHERE contribution_id = " . (int) $contributionID);
+  }
+
   /**
    * Given a participant id/contribution id,
    * return contribution/fee line items
@@ -117,11 +142,16 @@ AND li.entity_id = {$entityId}
    *
    * @param null $isQuick
    * @param bool $isQtyZero
+   * @param bool $relatedEntity
+   *
+   * @param string $overrideWhereClause e.g "WHERE contribution id = 7 " per the getLineItemsByContributionID wrapper.
+   * this function precedes the convenience of the contribution id but since it does quite a bit more than just a db retrieval we need to be able to use it even
+   * when we don't want it's entity-id magix
    *
    * @return array of line items
    */
-  static function getLineItems($entityId, $entity = 'participant', $isQuick = NULL , $isQtyZero = TRUE) {
-    $selectClause = $whereClause = $fromClause = NULL;
+  static function getLineItems($entityId, $entity = 'participant', $isQuick = NULL , $isQtyZero = TRUE, $relatedEntity = FALSE, $overrideWhereClause = '') {
+    $whereClause = $fromClause = NULL;
     $selectClause = "
       SELECT    li.id,
       li.label,
@@ -129,6 +159,8 @@ AND li.entity_id = {$entityId}
       li.qty,
       li.unit_price,
       li.line_total,
+      li.entity_table,
+      li.entity_id,
       pf.label as field_title,
       pf.html_type,
       pfv.membership_type_id,
@@ -137,13 +169,17 @@ AND li.entity_id = {$entityId}
       li.participant_count,
       li.price_field_value_id,
       li.financial_type_id,
+      li.tax_amount,
       pfv.description";
 
+    $condition = "li.entity_id = %2.id AND li.entity_table = 'civicrm_%2'";
+    if ($relatedEntity) {
+      $condition = "li.contribution_id = %2.id ";
+    }
+
     $fromClause = "
       FROM      civicrm_%2 as %2
-      LEFT JOIN civicrm_line_item li ON (( li.entity_id = %2.id AND li.entity_table = 'civicrm_%2')
-        OR (li.contribution_id = %2.id AND li.entity_table = 'civicrm_membership')
-        OR (li.contribution_id = %2.id AND li.entity_table = 'civicrm_participant'))
+      LEFT JOIN civicrm_line_item li ON ({$condition})
       LEFT JOIN civicrm_price_field_value pfv ON ( pfv.id = li.price_field_value_id )
       LEFT JOIN civicrm_price_field pf ON (pf.id = li.price_field_id )";
     $whereClause = "
@@ -171,6 +207,13 @@ AND li.entity_id = {$entityId}
       2 => array($entity, 'Text'),
     );
 
+    $getTaxDetails = FALSE;
+    $invoiceSettings = CRM_Core_BAO_Setting::getItem(CRM_Core_BAO_Setting::CONTRIBUTE_PREFERENCES_NAME,'contribution_invoice_settings');
+    $invoicing = CRM_Utils_Array::value('invoicing', $invoiceSettings);
+    if ($overrideWhereClause) {
+      $whereClause = $overrideWhereClause;
+    }
+
     $dao = CRM_Core_DAO::executeQuery("$selectClause $fromClause $whereClause $orderByClause", $params);
     while ($dao->fetch()) {
       if (!$dao->id) {
@@ -187,12 +230,27 @@ AND li.entity_id = {$entityId}
         'field_title' => $dao->field_title,
         'html_type' => $dao->html_type,
         'description' => $dao->description,
-        'entity_id' => $entityId,
+        // the entity id seems prone to randomness but not sure if it has a reason - so if we are overriding the Where clause we assume
+        // we also JUST WANT TO KNOW the the entity_id in the DB
+        'entity_id' => empty($overrideWhereClause) ? $entityId : $dao->entity_id,
+        'entity_table' => $dao->entity_table,
         'contribution_id' => $dao->contribution_id,
         'financial_type_id' => $dao->financial_type_id,
         'membership_type_id' => $dao->membership_type_id,
         'membership_num_terms' => $dao->membership_num_terms,
+        'tax_amount' => $dao->tax_amount,
       );
+      $lineItems[$dao->id]['tax_rate'] = CRM_Price_BAO_LineItem::calculateTaxRate($lineItems[$dao->id]);
+      $lineItems[$dao->id]['subTotal'] = $lineItems[$dao->id]['qty'] * $lineItems[$dao->id]['unit_price'];
+      if ($lineItems[$dao->id]['tax_amount'] != '') {
+        $getTaxDetails = TRUE;
+      }
+    }
+    if ($invoicing) {
+      $taxTerm = CRM_Utils_Array::value('tax_term', $invoiceSettings);
+      $smarty = CRM_Core_Smarty::singleton();
+      $smarty->assign('taxTerm', $taxTerm);
+      $smarty->assign('getTaxDetails', $getTaxDetails);
     }
     return $lineItems;
   }
@@ -202,10 +260,10 @@ AND li.entity_id = {$entityId}
    * processAmount method
    *
    * @param  int   $fid       price set field id
-   * @param  array $params    referance to form values
-   * @param  array $fields    referance to array of fields belonging
+   * @param  array $params    reference to form values
+   * @param  array $fields    reference to array of fields belonging
    *                          to the price set used for particular event
-   * @param  array $values    referance to the values array(
+   * @param  array $values    reference to the values array(
      this is
    *                          lineItem array)
    *
@@ -258,6 +316,7 @@ AND li.entity_id = {$entityId}
         'auto_renew' => CRM_Utils_Array::value('auto_renew', $options[$oid]),
         'html_type' => $fields['html_type'],
         'financial_type_id' => CRM_Utils_Array::value('financial_type_id', $options[$oid]),
+        'tax_amount' => CRM_Utils_Array::value('tax_amount', $options[$oid]),
       );
 
       if ($values[$oid]['membership_type_id'] && empty($values[$oid]['auto_renew'])) {
@@ -320,19 +379,19 @@ AND li.entity_id = {$entityId}
 
       foreach ($values as $line) {
         $line['entity_table'] = $entityTable;
-        $line['entity_id'] = $entityId;
-        if(!empty($line['membership_type_id'])) {
-          $entityTable == 'civicrm_membership';
-          $line['contribution_id'] = $contributionDetails->id;
+        if (empty($line['entity_id'])) {
+          $line['entity_id'] = $entityId;
         }
-        if ($entityTable == 'civicrm_contribution') {
-          $line['contribution_id'] = $entityId;
+        if(!empty($line['membership_type_id'])) {
+          $line['entity_table'] = 'civicrm_membership';
         }
-        else {
-          if (!empty($contributionDetails->id)) {
-            $line['contribution_id'] = $contributionDetails->id;
+        if (!empty($contributionDetails->id)) {
+          $line['contribution_id'] = $contributionDetails->id;
+          if ($line['entity_table'] == 'civicrm_contribution') {
+            $line['entity_id'] = $contributionDetails->id;
           }
         }
+
         // if financial type is not set and if price field value is NOT NULL
         // get financial type id of price field value
         if (!empty($line['price_field_value_id']) && empty($line['financial_type_id'])) {
@@ -341,6 +400,9 @@ AND li.entity_id = {$entityId}
         $lineItems = CRM_Price_BAO_LineItem::create($line);
         if (!$update && $contributionDetails) {
           CRM_Financial_BAO_FinancialItem::add($lineItems, $contributionDetails);
+          if (isset($line['tax_amount'])) {
+            CRM_Financial_BAO_FinancialItem::add($lineItems, $contributionDetails, TRUE);
+          }
         }
       }
     }
@@ -412,27 +474,40 @@ AND li.entity_id = {$entityId}
    * @return void
    * @static
    */
-  static function getLineItemArray(&$params, $entityId = NULL, $entityTable = 'contribution') {
+  static function getLineItemArray(&$params, $entityId = NULL, $entityTable = 'contribution', $isRelatedID = FALSE) {
 
     if (!$entityId) {
-      $priceSetDetails = CRM_Price_BAO_PriceSet::getDefaultPriceSet();
+      $priceSetDetails = CRM_Price_BAO_PriceSet::getDefaultPriceSet($entityTable);
+      $totalAmount = CRM_Utils_Array::value('total_amount', $params);
+      $financialType = CRM_Utils_Array::value('financial_type_id', $params);
       foreach ($priceSetDetails as $values) {
+        if ($entityTable == 'membership') {
+          if ($isRelatedID != $values['membership_type_id']) {
+            continue;
+          }
+          if (!$totalAmount) {
+            $totalAmount = $values['amount'];
+          }
+          $financialType = $values['financial_type_id'];
+        }
         $params['line_item'][$values['setID']][$values['priceFieldID']] = array(
           'price_field_id' => $values['priceFieldID'],
           'price_field_value_id' => $values['priceFieldValueID'],
           'label' => $values['label'],
           'qty' => 1,
-          'unit_price' => $params['total_amount'],
-          'line_total' => $params['total_amount'],
-          'financial_type_id' => $params['financial_type_id']
+          'unit_price' => $totalAmount,
+          'line_total' => $totalAmount,
+          'financial_type_id' => $financialType,
+          'membership_type_id' => $values['membership_type_id']
         );
+        break;
       }
     }
     else {
       $setID = NULL;
       $totalEntityId = count($entityId);
       foreach ($entityId as $id) {
-        $lineItems = CRM_Price_BAO_LineItem::getLineItems($id, $entityTable);
+        $lineItems = CRM_Price_BAO_LineItem::getLineItems($id, $entityTable, NULL, TRUE, $isRelatedID);
         foreach ($lineItems as $key => $values) {
           if (!$setID && $values['price_field_id']) {
             $setID = CRM_Core_DAO::getFieldValue('CRM_Price_DAO_PriceField', $values['price_field_id'], 'price_set_id');
@@ -448,4 +523,24 @@ AND li.entity_id = {$entityId}
       }
     }
   }
+
+  /**
+   * Calculate tax rate in percentage
+   *
+   * @param $lineItemId an assoc array of lineItem
+   *
+   * @return tax rate
+   *
+   * @access public
+   * @static
+   */
+  public static function calculateTaxRate($lineItemId) {
+    if ($lineItemId['html_type'] == 'Text') {
+      $tax = $lineItemId['tax_amount']/($lineItemId['unit_price'] * $lineItemId['qty'])*100;
+    }
+    else {
+      $tax = ($lineItemId['tax_amount']/$lineItemId['unit_price']) * 100;
+    }
+    return $tax;
+  }
 }