CRM-13973 : post process handling
[civicrm-core.git] / CRM / Contribute / BAO / Contribution.php
index 86a4ca486d450c516eba8d478e94d51800a28fce..5c4588aa235acda78784ad9761a9af33a42df4b5 100644 (file)
@@ -124,10 +124,10 @@ class CRM_Contribute_BAO_Contribution extends CRM_Contribute_DAO_Contribution {
         $params[$field] = CRM_Utils_Rule::cleanMoney($params[$field]);
       }
     }
-    
+
     // CRM-13420, set payment instrument to default if payment_instrument_id is empty
     if (!$contributionID && !CRM_Utils_Array::value('payment_instrument_id', $params)) {
-      $params['payment_instrument_id'] = key(CRM_Core_OptionGroup::values('payment_instrument', 
+      $params['payment_instrument_id'] = key(CRM_Core_OptionGroup::values('payment_instrument',
         FALSE, FALSE, FALSE, 'AND is_default = 1'));
     }
 
@@ -144,13 +144,22 @@ class CRM_Contribute_BAO_Contribution extends CRM_Contribute_DAO_Contribution {
       $params['contribution_status_id'] = CRM_Core_OptionGroup::getValue('contribution_status', 'Completed', 'name');
     }
 
+    // CRM-13964 partial payment
+    if (empty($contributionID)) {
+      if (!empty($params['partial_payment_total']) && !empty($params['partial_amount_pay'])) {
+        $partialAmtTotal = $params['partial_payment_total'];
+        $partialAmtPay = $params['partial_amount_pay'];
+        $params['total_amount'] = $partialAmtTotal;
+        $params['contribution_status_id'] = CRM_Core_OptionGroup::getValue('contribution_status', 'Partially paid', 'name');
+      }
+    }
+
     if ($contributionID) {
       CRM_Utils_Hook::pre('edit', 'Contribution', $contributionID, $params);
     }
     else {
       CRM_Utils_Hook::pre('create', 'Contribution', NULL, $params);
     }
-
     $contribution = new CRM_Contribute_BAO_Contribution();
     $contribution->copyValues($params);
 
@@ -173,7 +182,7 @@ class CRM_Contribute_BAO_Contribution extends CRM_Contribute_DAO_Contribution {
 
     //add Account details
     $params['contribution'] = $contribution;
-    self::recordFinancialAccounts($params, $ids);
+    self::recordFinancialAccounts($params);
 
     // reset the group contact cache for this group
     CRM_Contact_BAO_GroupContactCache::remove();
@@ -324,6 +333,7 @@ class CRM_Contribute_BAO_Contribution extends CRM_Contribute_DAO_Contribution {
       $softParams['pcp_display_in_roll'] = CRM_Utils_Array::value('pcp_display_in_roll', $pcp);
       $softParams['pcp_roll_nickname'] = CRM_Utils_Array::value('pcp_roll_nickname', $pcp);
       $softParams['pcp_personal_note'] = CRM_Utils_Array::value('pcp_personal_note', $pcp);
+      $softParams['soft_credit_type_id'] = CRM_Core_OptionGroup::getValue('soft_credit_type', 'pcp', 'name');
       CRM_Contribute_BAO_ContributionSoft::add($softParams);
     }
     elseif (CRM_Utils_Array::value('soft_credit', $params)) {
@@ -341,10 +351,6 @@ class CRM_Contribute_BAO_Contribution extends CRM_Contribute_DAO_Contribution {
       foreach ($softParams as $softParam) {
         $softParam['contribution_id'] = $contribution->id;
         $softParam['currency'] = $contribution->currency;
-        $softParam['pcp_id'] = 'null';
-        $softParam['pcp_display_in_roll'] = 'null';
-        $softParam['pcp_roll_nickname'] = 'null';
-        $softParam['pcp_personal_note'] = 'NULL';
         CRM_Contribute_BAO_ContributionSoft::add($softParam);
       }
     }
@@ -581,12 +587,7 @@ class CRM_Contribute_BAO_Contribution extends CRM_Contribute_DAO_Contribution {
         ));
 
       $extraFields = array(
-        'contribution_campaign' =>
-        array(
-          'title' => ts('Campaign Title')
-        ),
-        'contribution_batch' =>
-        array(
+        'contribution_batch' => array(
           'title' => ts('Batch Name')
         )
       );
@@ -908,44 +909,6 @@ GROUP BY p.id
     }
   }
 
-  /**
-   * Function to create is honor of
-   *
-   * @param array $params  associated array of fields (by reference)
-   * @param int   $honorId honor Id
-   * @param array $honorParams any params that should be send to the create function
-   *
-   * @return contact id
-   */
-  static function createHonorContact(&$params, $honorId = NULL, $honorParams = array()) {
-    $honorParams = array_merge(
-      array(
-        'first_name' => $params['honor_first_name'],
-        'last_name' => $params['honor_last_name'],
-        'prefix_id' => $params['honor_prefix_id'],
-        'email-Primary' => $params['honor_email'],
-      ),
-      $honorParams
-    );
-    if (!$honorId) {
-      $honorParams['email'] = $params['honor_email'];
-
-      $dedupeParams = CRM_Dedupe_Finder::formatParams($honorParams, 'Individual');
-      $dedupeParams['check_permission'] = FALSE;
-      $ids = CRM_Dedupe_Finder::dupesByParams($dedupeParams, 'Individual');
-
-      // if we find more than one contact, use the first one
-      $honorId = CRM_Utils_Array::value(0, $ids);
-    }
-
-    $contactID = CRM_Contact_BAO_Contact::createProfileContact(
-      $honorParams,
-      CRM_Core_DAO::$_nullArray,
-      $honorId
-    );
-    return $contactID;
-  }
-
   /**
    * Function to get list of contribution In Honor of contact Ids
    *
@@ -1310,7 +1273,7 @@ LEFT JOIN  civicrm_contribution contribution ON ( componentPayment.contribution_
   /**
    * This function update contribution as well as related objects.
    */
-  function transitionComponents($params, $processContributionObject = FALSE) {
+  static function transitionComponents($params, $processContributionObject = FALSE) {
     // get minimum required values.
     $contactId = CRM_Utils_Array::value('contact_id', $params);
     $componentId = CRM_Utils_Array::value('component_id', $params);
@@ -1696,7 +1659,7 @@ LEFT JOIN  civicrm_contribution contribution ON ( componentPayment.contribution_
     return $componentDetails;
   }
 
-  static function contributionCount($contactId, $includeSoftCredit = TRUE, $includeHonoree = TRUE) {
+  static function contributionCount($contactId, $includeSoftCredit = TRUE) {
     if (!$contactId) {
       return 0;
     }
@@ -1706,11 +1669,6 @@ LEFT JOIN  civicrm_contribution contribution ON ( componentPayment.contribution_
       FROM civicrm_contribution contribution
       WHERE contribution.is_test = 0 AND contribution.contact_id = {$contactId} ";
 
-    $contactHonoreeContributionsSQL = "
-      SELECT contribution.id
-      FROM civicrm_contribution contribution
-      WHERE contribution.is_test = 0 AND contribution.honor_contact_id = {$contactId} ";
-
     $contactSoftCreditContributionsSQL = "
       SELECT contribution.id
       FROM civicrm_contribution contribution INNER JOIN civicrm_contribution_soft softContribution
@@ -1724,11 +1682,6 @@ LEFT JOIN  civicrm_contribution contribution ON ( componentPayment.contribution_
       $query .= $contactSoftCreditContributionsSQL;
     }
 
-    if ($includeHonoree) {
-      $query .= " UNION ";
-      $query .= $contactHonoreeContributionsSQL;
-    }
-
     $query .= ") x";
 
     return CRM_Core_DAO::singleValueQuery($query);
@@ -1743,7 +1696,7 @@ LEFT JOIN  civicrm_contribution contribution ON ( componentPayment.contribution_
    * @return array $ids containing organization id and individual id
    * @access public
    */
-  function getOnbehalfIds($contributionId, $contributorId = NULL) {
+  static function getOnbehalfIds($contributionId, $contributorId = NULL) {
 
     $ids = array();
 
@@ -2496,7 +2449,7 @@ WHERE  contribution_id = %1 ";
    * @access public
    * @static
    */
-  static function recordFinancialAccounts(&$params) {
+  static function recordFinancialAccounts(&$params, $financialTrxnVals = NULL) {
     $skipRecords = $update = FALSE;
     $additionalParticipantId = array();
     $contributionStatuses = CRM_Contribute_PseudoConstant::contributionStatus(NULL, 'name');
@@ -2523,6 +2476,42 @@ WHERE  contribution_id = %1 ";
       $update = TRUE;
     }
 
+    $statusId = $params['contribution']->contribution_status_id;
+    // CRM-13964 partial payment
+    if (CRM_Utils_Array::value('contribution_status_id', $params) == array_search('Partially paid', $contributionStatuses)
+      && !empty($params['partial_payment_total']) && !empty($params['partial_amount_pay'])) {
+      $partialAmtPay = $params['partial_amount_pay'];
+      $partialAmtTotal = $params['partial_payment_total'];
+
+      $relationTypeId = key(CRM_Core_PseudoConstant::accountOptionValues('account_relationship', NULL, " AND v.name LIKE 'Accounts Receivable Account is' "));
+      $fromFinancialAccountId = CRM_Contribute_PseudoConstant::financialAccountType($params['financial_type_id'], $relationTypeId);
+      $statusId = CRM_Core_OptionGroup::getValue('contribution_status', 'Completed', 'name');
+      $params['total_amount'] = $partialAmtPay;
+
+      $balanceTrxnInfo = CRM_Core_BAO_FinancialTrxn::getBalanceTrxnAmt($params['contribution']->id, $params['financial_type_id']);
+      if (empty($balanceTrxnInfo['trxn_id'])) {
+        // create new balance transaction record
+        $relationTypeId = key(CRM_Core_PseudoConstant::accountOptionValues('account_relationship', NULL, " AND v.name LIKE 'Accounts Receivable Account is' "));
+        $toFinancialAccount = CRM_Contribute_PseudoConstant::financialAccountType($params['financial_type_id'], $relationTypeId);
+
+        $balanceTrxnParams['total_amount'] = $partialAmtTotal;
+        $balanceTrxnParams['to_financial_account_id'] = $toFinancialAccount;
+        $balanceTrxnParams['contribution_id'] = $params['contribution']->id;
+        $balanceTrxnParams['trxn_date'] = date('YmdHis');
+        $balanceTrxnParams['fee_amount'] = CRM_Utils_Array::value('fee_amount', $params);
+        $balanceTrxnParams['net_amount'] = CRM_Utils_Array::value('net_amount', $params);
+        $balanceTrxnParams['currency'] = $params['contribution']->currency;
+        $balanceTrxnParams['trxn_id'] = $params['contribution']->trxn_id;
+        $balanceTrxnParams['status_id'] = $statusId;
+        $balanceTrxnParams['payment_instrument_id'] = $params['contribution']->payment_instrument_id;
+        $balanceTrxnParams['check_number'] = CRM_Utils_Array::value('check_number', $params);
+        if (CRM_Utils_Array::value('payment_processor', $params)) {
+          $balanceTrxnParams['payment_processor_id'] = $params['payment_processor'];
+        }
+        CRM_Core_BAO_FinancialTrxn::create($balanceTrxnParams);
+      }
+    }
+
     // build line item array if its not set in $params
     if (!CRM_Utils_Array::value('line_item', $params) || $additionalParticipantId) {
       CRM_Price_BAO_LineItem::getLineItemArray($params, $entityID, str_replace('civicrm_', '', $entityTable));
@@ -2551,6 +2540,7 @@ WHERE  contribution_id = %1 ";
       if (!isset($totalAmount) && CRM_Utils_Array::value('prevContribution', $params)) {
         $totalAmount = $params['total_amount'] = $params['prevContribution']->total_amount;
       }
+
       //build financial transaction params
       $trxnParams = array(
         'contribution_id' => $params['contribution']->id,
@@ -2561,7 +2551,7 @@ WHERE  contribution_id = %1 ";
         'net_amount' => CRM_Utils_Array::value('net_amount', $params),
         'currency' => $params['contribution']->currency,
         'trxn_id' => $params['contribution']->trxn_id,
-        'status_id' => $params['contribution']->contribution_status_id,
+        'status_id' => $statusId,
         'payment_instrument_id' => $params['contribution']->payment_instrument_id,
         'check_number' => CRM_Utils_Array::value('check_number', $params),
       );
@@ -2569,6 +2559,16 @@ WHERE  contribution_id = %1 ";
       if (CRM_Utils_Array::value('payment_processor', $params)) {
         $trxnParams['payment_processor_id'] = $params['payment_processor'];
       }
+
+      if (isset($fromFinancialAccountId)) {
+        $trxnParams['from_financial_account_id'] = $fromFinancialAccountId;
+      }
+
+      // consider external values passed for recording transaction entry
+      if (!empty($financialTrxnVals)) {
+        $trxnParams = array_merge($trxnParams, $financialTrxnVals);
+      }
+
       $params['trxnParams'] = $trxnParams;
 
       if (CRM_Utils_Array::value('prevContribution', $params)) {
@@ -2579,7 +2579,7 @@ WHERE  contribution_id = %1 ";
         $params['trxnParams']['status_id'] = $params['prevContribution']->contribution_status_id;
         $params['trxnParams']['payment_instrument_id'] = $params['prevContribution']->payment_instrument_id;
         $params['trxnParams']['check_number'] = $params['prevContribution']->check_number;
-        
+
         //if financial type is changed
         if (CRM_Utils_Array::value('financial_type_id', $params) &&
           $params['contribution']->financial_type_id != $params['prevContribution']->financial_type_id) {
@@ -2606,7 +2606,7 @@ WHERE  contribution_id = %1 ";
             $params['trxnParams']['to_financial_account_id'] = $trxnParams['to_financial_account_id'];
           }
         }
-        
+
         //Update contribution status
         $params['trxnParams']['status_id'] = $params['contribution']->contribution_status_id;
         if (CRM_Utils_Array::value('contribution_status_id', $params) &&
@@ -2654,7 +2654,7 @@ WHERE  contribution_id = %1 ";
             self::updateFinancialAccounts($params, 'changePaymentInstrument');
           }
         }
-        
+
         //if Change contribution amount
         $params['trxnParams']['fee_amount'] = CRM_Utils_Array::value('fee_amount', $params);
         $params['trxnParams']['net_amount'] = CRM_Utils_Array::value('net_amount', $params);
@@ -2702,6 +2702,10 @@ WHERE  contribution_id = %1 ";
       CRM_Event_BAO_Participant::createDiscountTrxn($eventID, $params, $feeLevel);
     }
     unset($params['line_item']);
+
+    if (!$update) {
+      return $financialTxn;
+    }
   }
 
   /**
@@ -2755,7 +2759,7 @@ WHERE  contribution_id = %1 ";
         if (CRM_Utils_Array::value('financialTrxnId', $lastFinancialTrxnId)) {
           $params['trxnParams']['to_financial_account_id'] = CRM_Core_DAO::getFieldValue('CRM_Financial_DAO_FinancialTrxn', $lastFinancialTrxnId['financialTrxnId'], 'to_financial_account_id');
           $params['trxnParams']['payment_instrument_id'] = $params['prevContribution']->payment_instrument_id;
-        } 
+        }
       }
       else {
         $params['trxnParams']['to_financial_account_id'] = $params['to_financial_account_id'];
@@ -2947,6 +2951,186 @@ WHERE  contribution_id = %1 ";
     }
     return FALSE;
   }
-}
 
+  static function recordAdditionPayment($contributionId, $trxnsData, $paymentType, $participantId = NULL) {
+    // FIXME : needs handling of partial payment validness checking, if its valid then only record new entries
+    $params = $ids = $defaults = array();
+    $getInfoOf['id'] = $contributionId;
+
+    // build params for recording financial trxn entry
+    $contributionDAO = CRM_Contribute_BAO_Contribution::retrieve($getInfoOf, $defaults, $ids);
+    $params['contribution'] = $contributionDAO;
+    $params = array_merge($defaults, $params);
+    $params['skipLineItem'] = TRUE;
+    $params['partial_payment_total'] = $contributionDAO->total_amount;
+    $params['partial_amount_pay'] = $trxnsData['total_amount'];
+    $trxnsData['trxn_date'] = !empty($trxnsData['trxn_date']) ? $trxnsData['trxn_date'] : date('YmdHis');
+
+    // record the entry
+    $financialTrxn = CRM_Contribute_BAO_Contribution::recordFinancialAccounts($params, $trxnsData);
+
+    $statusId = CRM_Core_OptionGroup::getValue('contribution_status', 'Completed', 'name');
+    $relationTypeId = key(CRM_Core_PseudoConstant::accountOptionValues('account_relationship', NULL, " AND v.name LIKE 'Accounts Receivable Account is' "));
+    $toFinancialAccount = CRM_Contribute_PseudoConstant::financialAccountType($contributionDAO->financial_type_id, $relationTypeId);
+
+    $trxnId = CRM_Core_BAO_FinancialTrxn::getBalanceTrxnAmt($contributionId, $contributionDAO->financial_type_id);
+    $trxnId = $trxnId['trxn_id'];
+
+    // update statuses
+    // criteria for updates contribution total_amount == financial_trxns of partial_payments
+    $sql = "SELECT SUM(ft.total_amount) as sum_of_payments
+FROM civicrm_financial_trxn ft
+LEFT JOIN civicrm_entity_financial_trxn eft
+  ON (ft.id = eft.financial_trxn_id)
+WHERE eft.entity_table = 'civicrm_contribution'
+  AND eft.entity_id = {$contributionId}
+  AND ft.to_financial_account_id != {$toFinancialAccount}
+  AND ft.status_id = {$statusId}
+";
+    $sumOfPayments = CRM_Core_DAO::singleValueQuery($sql);
+
+    // update statuses
+    if ($contributionDAO->total_amount == $sumOfPayments) {
+      // update contribution status
+      $contributionUpdate['id'] = $contributionId;
+      $contributionUpdate['contribution_status_id'] = $statusId;
+      $contributionUpdate['skipLineItem'] = TRUE;
+      // note : not using the self::add method,
+      // the reason because it performs 'status change' related code execution for financial records
+      // which in 'Partial Paid' => 'Completed' is not useful, instead specific financial record updates
+      // are coded below i.e. just updating financial_item status to 'Paid'
+      $contributionDetails = CRM_Core_DAO::setFieldValue('CRM_Contribute_BAO_Contribution', $contributionId, 'contribution_status_id', $statusId);
+
+      if ($participantId) {
+        // update participant status
+        $participantUpdate['id'] = $participantId;
+        $participantStatuses = CRM_Event_PseudoConstant::participantStatus();
+        $participantUpdate['status_id'] = array_search('Registered', $participantStatuses);
+        CRM_Event_BAO_Participant::add($participantUpdate);
+      }
+
+      // update financial item statuses
+      $financialItemStatus = CRM_Core_PseudoConstant::get('CRM_Financial_DAO_FinancialItem', 'status_id');
+      $paidStatus = array_search('Paid', $financialItemStatus);
+
+      $sqlFinancialItemUpdate = "
+UPDATE civicrm_financial_item fi
+  LEFT JOIN civicrm_entity_financial_trxn eft
+    ON (eft.entity_id = fi.id AND eft.entity_table = 'civicrm_financial_item')
+SET status_id = {$paidStatus}
+WHERE eft.financial_trxn_id = {$trxnId}
+";
+      CRM_Core_DAO::executeQuery($sqlFinancialItemUpdate);
+    }
+
+    if (!empty($financialTrxn)) {
+      if ($participantId) {
+        $inputParams['id'] = $participantId;
+        $values = array();
+        $ids = array();
+        $component = 'event';
+        $entityObj = CRM_Event_BAO_Participant::getValues($inputParams, $values, $ids);
+        $entityObj = $entityObj[$participantId];
+      }
+      $activityType = ($paymentType == 'refund') ? 'Refund' : 'Payment';
+
+      // creation of activity
+      $activity = new CRM_Activity_DAO_Activity();
+      $activity->source_record_id = $financialTrxn->id;
+      $activity->activity_type_id = CRM_Core_OptionGroup::getValue('activity_type',
+        $activityType,
+        'name'
+      );
+      if (!$activity->find(TRUE)) {
+        self::addActivityForPayment($entityObj, $financialTrxn, $activityType, $component);
+      }
+    }
+    return $financialTrxn;
+  }
+
+  static function addActivityForPayment($entityObj, $trxnObj, $activityType, $component) {
+    if ($component == 'event') {
+      $date = CRM_Utils_Date::isoToMysql($trxnObj->trxn_date);
+      $paymentAmount = CRM_Utils_Money::format($trxnObj->total_amount, $trxnObj->currency);
+      $eventTitle = CRM_Core_DAO::getFieldValue('CRM_Event_BAO_Event', $entityObj->event_id, 'title');
+      $subject = "{$paymentAmount} - Offline {$activityType} for {$eventTitle}";
+      $targetCid = $entityObj->contact_id;
+      $srcRecId = $trxnObj->id;
+    }
+
+    // activity params
+    $activityParams = array(
+      'source_contact_id' => $targetCid,
+      'source_record_id' => $srcRecId,
+      'activity_type_id' => CRM_Core_OptionGroup::getValue('activity_type',
+        $activityType,
+        'name'
+      ),
+      'subject' => $subject,
+      'activity_date_time' => $date,
+      'status_id' => CRM_Core_OptionGroup::getValue('activity_status',
+        'Completed',
+        'name'
+      ),
+      'skipRecentView' => TRUE,
+    );
+
+    // create activity with target contacts
+    $session = CRM_Core_Session::singleton();
+    $id = $session->get('userID');
+    if ($id) {
+      $activityParams['source_contact_id'] = $id;
+      $activityParams['target_contact_id'][] = $targetCid;
+    }
+    CRM_Activity_BAO_Activity::create($activityParams);
+  }
+
+  function getPaymentInfo($id, $component, $getTrxnInfo = FALSE) {
+    if ($component == 'event') {
+      $entity = 'participant';
+      $contributionId = CRM_Core_DAO::getFieldValue('CRM_Event_BAO_ParticipantPayment', $id, 'contribution_id', 'participant_id');
+    }
+    $total = CRM_Core_BAO_FinancialTrxn::getBalanceTrxnAmt($contributionId);
+    $baseTrxnId = NULL;
+    if (empty($total)) {
+      $total = CRM_Price_BAO_LineItem::getLineTotal($id, 'civicrm_participant');
+    }
+    else {
+      $baseTrxnId = $total['trxn_id'];
+      $total = $total['total_amount'];
+    }
+    $paymentBalance = CRM_Core_BAO_FinancialTrxn::getPartialPaymentWithType($id, $entity, FALSE, $total);
+    $info['total'] = $total;
+    $info['paid'] = $total - $paymentBalance;
+    $info['balance'] = $paymentBalance;
+    $info['id'] = $id;
+    $info['component'] = $component;
+    $rows = array();
+    if ($getTrxnInfo && $baseTrxnId) {
+      $sql = "
+SELECT ft.total_amount, con.financial_type_id, ft.payment_instrument_id, ft.trxn_date, ft.trxn_id, ft.status_id
+FROM civicrm_contribution con
+  LEFT JOIN civicrm_entity_financial_trxn eft ON (eft.entity_id = con.id AND eft.entity_table = 'civicrm_contribution')
+  LEFT JOIN civicrm_financial_trxn ft ON ft.id = eft.financial_trxn_id
+WHERE ft.id != {$baseTrxnId} AND con.id = {$contributionId}
+";
+      $resultDAO = CRM_Core_DAO::executeQuery($sql);
 
+      while($resultDAO->fetch()) {
+        $paymentInstrument = CRM_Contribute_PseudoConstant::paymentInstrument();
+        $statuses = CRM_Contribute_PseudoConstant::contributionStatus();
+        $financialTypes = CRM_Contribute_PseudoConstant::financialType();
+        $rows[] = array(
+          'total_amount' => $resultDAO->total_amount,
+          'financial_type' => $financialTypes[$resultDAO->financial_type_id],
+          'payment_instrument' => $paymentInstrument[$resultDAO->payment_instrument_id],
+          'receive_date' => $resultDAO->trxn_date,
+          'trxn_id' => $resultDAO->trxn_id,
+          'status' => $statuses[$resultDAO->status_id],
+        );
+      }
+      $info['transaction'] = $rows;
+    }
+    return $info;
+  }
+}