Beispiel #1
0
 /**
  * @param $input
  * @param $ids
  * @param $objects
  * @param $first
  *
  * @return bool
  */
 public function recur(&$input, &$ids, &$objects, $first)
 {
     if (!isset($input['txnType'])) {
         CRM_Core_Error::debug_log_message("Could not find txn_type in input request");
         echo "Failure: Invalid parameters<p>";
         return FALSE;
     }
     if ($input['txnType'] == 'subscr_payment' && $input['paymentStatus'] != 'Completed') {
         CRM_Core_Error::debug_log_message("Ignore all IPN payments that are not completed");
         echo "Failure: Invalid parameters<p>";
         return FALSE;
     }
     $recur =& $objects['contributionRecur'];
     // make sure the invoice ids match
     // make sure the invoice is valid and matches what we have in the contribution record
     if ($recur->invoice_id != $input['invoice']) {
         CRM_Core_Error::debug_log_message("Invoice values dont match between database and IPN request");
         echo "Failure: Invoice values dont match between database and IPN request<p>";
         return FALSE;
     }
     $now = date('YmdHis');
     // fix dates that already exist
     $dates = array('create', 'start', 'end', 'cancel', 'modified');
     foreach ($dates as $date) {
         $name = "{$date}_date";
         if ($recur->{$name}) {
             $recur->{$name} = CRM_Utils_Date::isoToMysql($recur->{$name});
         }
     }
     $sendNotification = FALSE;
     $subscriptionPaymentStatus = NULL;
     //set transaction type
     $txnType = $_POST['txn_type'];
     switch ($txnType) {
         case 'subscr_signup':
             $recur->create_date = $now;
             //some times subscr_signup response come after the
             //subscr_payment and set to pending mode.
             $statusID = CRM_Core_DAO::getFieldValue('CRM_Contribute_DAO_ContributionRecur', $recur->id, 'contribution_status_id');
             if ($statusID != 5) {
                 $recur->contribution_status_id = 2;
             }
             $recur->processor_id = $_POST['subscr_id'];
             $recur->trxn_id = $recur->processor_id;
             $sendNotification = TRUE;
             $subscriptionPaymentStatus = CRM_Core_Payment::RECURRING_PAYMENT_START;
             break;
         case 'subscr_eot':
             if ($recur->contribution_status_id != 3) {
                 $recur->contribution_status_id = 1;
             }
             $recur->end_date = $now;
             $sendNotification = TRUE;
             $subscriptionPaymentStatus = CRM_Core_Payment::RECURRING_PAYMENT_END;
             break;
         case 'subscr_cancel':
             $recur->contribution_status_id = 3;
             $recur->cancel_date = $now;
             break;
         case 'subscr_failed':
             $recur->contribution_status_id = 4;
             $recur->modified_date = $now;
             break;
         case 'subscr_modify':
             CRM_Core_Error::debug_log_message("We do not handle modifications to subscriptions right now");
             echo "Failure: We do not handle modifications to subscriptions right now<p>";
             return FALSE;
         case 'subscr_payment':
             if ($first) {
                 $recur->start_date = $now;
             } else {
                 $recur->modified_date = $now;
             }
             // make sure the contribution status is not done
             // since order of ipn's is unknown
             if ($recur->contribution_status_id != 1) {
                 $recur->contribution_status_id = 5;
             }
             break;
     }
     $recur->save();
     if ($sendNotification) {
         $autoRenewMembership = FALSE;
         if ($recur->id && isset($ids['membership']) && $ids['membership']) {
             $autoRenewMembership = TRUE;
         }
         //send recurring Notification email for user
         CRM_Contribute_BAO_ContributionPage::recurringNotify($subscriptionPaymentStatus, $ids['contact'], $ids['contributionPage'], $recur, $autoRenewMembership);
     }
     if ($txnType != 'subscr_payment') {
         return;
     }
     if (!$first) {
         //check if this contribution transaction is already processed
         //if not create a contribution and then get it processed
         $contribution = new CRM_Contribute_BAO_Contribution();
         $contribution->trxn_id = $input['trxn_id'];
         if ($contribution->trxn_id && $contribution->find()) {
             CRM_Core_Error::debug_log_message("returning since contribution has already been handled");
             echo "Success: Contribution has already been handled<p>";
             return TRUE;
         }
         $contribution->contact_id = $ids['contact'];
         $contribution->financial_type_id = $objects['contributionType']->id;
         $contribution->contribution_page_id = $ids['contributionPage'];
         $contribution->contribution_recur_id = $ids['contributionRecur'];
         $contribution->receive_date = $now;
         $contribution->currency = $objects['contribution']->currency;
         $contribution->payment_instrument_id = $objects['contribution']->payment_instrument_id;
         $contribution->amount_level = $objects['contribution']->amount_level;
         $contribution->campaign_id = $objects['contribution']->campaign_id;
         $objects['contribution'] =& $contribution;
     }
     $this->single($input, $ids, $objects, TRUE, $first);
 }
Beispiel #2
0
 /**
  * Given the list of params in the params array, fetch the object
  * and store the values in the values array
  *
  * @param array $params
  *   Input parameters to find object.
  * @param array $values
  *   Output values of the object.
  * @param array $ids
  *   The array that holds all the db ids.
  *
  * @return CRM_Contribute_BAO_Contribution|null
  *   The found object or null
  */
 public static function getValues($params, &$values, &$ids)
 {
     if (empty($params)) {
         return NULL;
     }
     $contribution = new CRM_Contribute_BAO_Contribution();
     $contribution->copyValues($params);
     if ($contribution->find(TRUE)) {
         $ids['contribution'] = $contribution->id;
         CRM_Core_DAO::storeValues($contribution, $values);
         return $contribution;
     }
     $null = NULL;
     // return by reference
     return $null;
 }
 /**
  * Process failed transaction - would be nice to do this through api too but for now lets put in
  * here - this is a copy & paste of the completetransaction api
  * @param unknown $contributionID
  */
 function processFailedTransaction($contributionID)
 {
     $input = $ids = array();
     $contribution = new CRM_Contribute_BAO_Contribution();
     $contribution->id = $contributionID;
     $contribution->find(TRUE);
     if (!$contribution->id == $contributionID) {
         throw new Exception('A valid contribution ID is required', 'invalid_data');
     }
     try {
         if (!$contribution->loadRelatedObjects($input, $ids, FALSE, TRUE)) {
             throw new Exception('failed to load related objects');
         }
         $objects = $contribution->_relatedObjects;
         $objects['contribution'] =& $contribution;
         $input['component'] = $contribution->_component;
         $input['is_test'] = $contribution->is_test;
         $input['amount'] = $contribution->total_amount;
         // @todo required for base ipn but problematic as api layer handles this
         $transaction = new CRM_Core_Transaction();
         $ipn = new CRM_Core_Payment_BaseIPN();
         $ipn->failed($objects, $transaction, $input);
     } catch (Exception $e) {
     }
 }
/**
 * Complete an existing (pending) transaction.
 *
 * This will update related entities (participant, membership, pledge etc)
 * and take any complete actions from the contribution page (e.g. send receipt).
 *
 * @todo - most of this should live in the BAO layer but as we want it to be an addition
 * to 4.3 which is already stable we should add it to the api layer & re-factor into the BAO layer later
 *
 * @param array $params
 *   Input parameters.
 *
 * @throws API_Exception
 *   Api result array.
 */
function civicrm_api3_contribution_repeattransaction(&$params)
{
    $input = $ids = array();
    civicrm_api3_verify_one_mandatory($params, NULL, array('contribution_recur_id', 'original_contribution_id'));
    if (empty($params['original_contribution_id'])) {
        $params['original_contribution_id'] = civicrm_api3('contribution', 'getvalue', array('return' => 'id', 'contribution_recur_id' => $params['contribution_recur_id'], 'options' => array('limit' => 1, 'sort' => 'id DESC')));
    }
    $contribution = new CRM_Contribute_BAO_Contribution();
    $contribution->id = $params['original_contribution_id'];
    if (!$contribution->find(TRUE)) {
        throw new API_Exception('A valid original contribution ID is required', 'invalid_data');
    }
    $original_contribution = clone $contribution;
    try {
        if (!$contribution->loadRelatedObjects($input, $ids, TRUE)) {
            throw new API_Exception('failed to load related objects');
        }
        unset($contribution->id, $contribution->receive_date, $contribution->invoice_id);
        $contribution->receive_date = $params['receive_date'];
        $passThroughParams = array('trxn_id', 'total_amount', 'campaign_id', 'fee_amount', 'financial_type_id', 'contribution_status_id');
        $input = array_intersect_key($params, array_fill_keys($passThroughParams, NULL));
        $params = _ipn_process_transaction($params, $contribution, $input, $ids, $original_contribution);
    } catch (Exception $e) {
        throw new API_Exception('failed to load related objects' . $e->getMessage() . "\n" . $e->getTraceAsString());
    }
}
 /**
  * The function gets called when the state(CHARGED, CANCELLED..) changes for an order
  *
  * @param string $status      status of the transaction send by google
  * @param array  $privateData contains the name value pair of <merchant-private-data>
  *
  * @return void
  *
  */
 function orderStateChange($status, $dataRoot, $privateData, $component)
 {
     $input = $objects = $ids = array();
     $input['component'] = strtolower($component);
     $ids['contributionRecur'] = self::retrieve('contributionRecurID', 'Integer', $privateData, FALSE);
     $serial = $dataRoot['serial-number'];
     $orderNo = $dataRoot['google-order-number']['VALUE'];
     $contribution = new CRM_Contribute_BAO_Contribution();
     $contribution->invoice_id = $orderNo;
     if (!$contribution->find(TRUE)) {
         CRM_Core_Error::debug_log_message("orderStateChange: Could not find contribution record with invoice id: {$serial}");
         return;
     }
     // Google sends the charged notification twice.
     // So to make sure, code is not executed again.
     if ($contribution->contribution_status_id == 1) {
         CRM_Core_Error::debug_log_message("Contribution already handled (ContributionID = {$contribution->id}).");
         return;
     }
     // make sure invoice is set to serial no for recurring payments, to avoid violating uniqueness
     $contribution->invoice_id = $ids['contributionRecur'] ? $serial : $orderNo;
     $objects['contribution'] =& $contribution;
     $ids['contribution'] = $contribution->id;
     $ids['contact'] = $contribution->contact_id;
     $ids['event'] = $ids['participant'] = $ids['membership'] = NULL;
     $ids['contributionPage'] = NULL;
     if ($input['component'] == "event") {
         list($ids['event'], $ids['participant']) = explode(CRM_Core_DAO::VALUE_SEPARATOR, $contribution->trxn_id);
     } else {
         $ids['related_contact'] = NULL;
         $ids['onbehalf_dupe_alert'] = NULL;
         if ($contribution->trxn_id) {
             list($ids['membership'], $ids['related_contact'], $ids['onbehalf_dupe_alert']) = explode(CRM_Core_DAO::VALUE_SEPARATOR, $contribution->trxn_id);
         }
         foreach (array('membership', 'related_contact', 'onbehalf_dupe_alert') as $fld) {
             if (!is_numeric($ids[$fld])) {
                 unset($ids[$fld]);
             }
         }
     }
     $paymentProcessorID = CRM_Core_DAO::getFieldValue('CRM_Core_DAO_PaymentProcessorType', 'Google_Checkout', 'id', 'payment_processor_type');
     $this->loadObjects($input, $ids, $objects, TRUE, $paymentProcessorID);
     $transaction = new CRM_Core_Transaction();
     // CRM_Core_Error::debug_var( 'c', $contribution );
     if ($status == 'PAYMENT_DECLINED' || $status == 'CANCELLED_BY_GOOGLE' || $status == 'CANCELLED') {
         return $this->failed($objects, $transaction);
     }
     $input['amount'] = $contribution->total_amount;
     $input['fee_amount'] = NULL;
     $input['net_amount'] = NULL;
     $input['trxn_id'] = $ids['contributionRecur'] ? $serial : $dataRoot['google-order-number']['VALUE'];
     $input['is_test'] = $contribution->is_test;
     $recur = NULL;
     if ($ids['contributionRecur']) {
         $recur = $objects['contributionRecur'];
     }
     $this->completeTransaction($input, $ids, $objects, $transaction, $recur);
     $this->completeRecur($input, $ids, $objects);
 }
 /**
  * Load objects related to contribution.
  *
  * @input array information from Payment processor
  * @param array $ids
  * @param array $objects
  * @param boolean $required
  * @param integer $paymentProcessorID
  * @param array $error_handling
  * @return multitype:number NULL |boolean
  */
 function loadObjects(&$input, &$ids, &$objects, $required, $paymentProcessorID, $error_handling = NULL)
 {
     if (empty($error_handling)) {
         // default options are that we log an error & echo it out
         // note that we should refactor this error handling into error code @ some point
         // but for now setting up enough separation so we can do unit tests
         $error_handling = array('log_error' => 1, 'echo_error' => 1);
     }
     $ids['paymentProcessor'] = $paymentProcessorID;
     if (is_a($objects['contribution'], 'CRM_Contribute_BAO_Contribution')) {
         $contribution =& $objects['contribution'];
     } else {
         //legacy support - functions are 'used' to be able to pass in a DAO
         $contribution = new CRM_Contribute_BAO_Contribution();
         $contribution->id = CRM_Utils_Array::value('contribution', $ids);
         $contribution->find(TRUE);
         $objects['contribution'] =& $contribution;
     }
     try {
         $success = $contribution->loadRelatedObjects($input, $ids, $required);
     } catch (Exception $e) {
         $success = FALSE;
         if (CRM_Utils_Array::value('log_error', $error_handling)) {
             CRM_Core_Error::debug_log_message($e->getMessage());
         }
         if (CRM_Utils_Array::value('echo_error', $error_handling)) {
             echo $e->getMessage();
         }
         if (CRM_Utils_Array::value('return_error', $error_handling)) {
             return array('is_error' => 1, 'error_message' => $e->getMessage());
         }
     }
     $objects = array_merge($objects, $contribution->_relatedObjects);
     return $success;
 }
Beispiel #7
0
 public function handlePaymentNotification()
 {
     $errors = array("101" => "Tarjeta caducada", "102" => "Tarjeta en excepción transitoria o bajo sospecha de fraude", "106" => "Intentos de PIN excedidos", "125" => "Tarjeta no efectiva", "129" => "Código de seguridad (CVV2/CVC2) incorrecto", "180" => "Tarjeta ajena al servicio", "184" => "Error en la autenticación del titular", "190" => "Denegación del emisor sin especificar motivo", "191" => "Fecha de caducidad errónea", "202" => "Tarjeta en excepción transitoria o bajo sospecha de fraude con retirada de tarjeta", "904" => "Comercio no registrado en FUC", "909" => "Error de sistema", "913" => "Pedido repetido", "944" => "Sesión Incorrecta", "950" => "Operación de devolución no permitida", "912" => "Emisor no disponible", "9912" => "Emisor no disponible", "9064" => "Número de posiciones de la tarjeta incorrecto", "9078" => "Tipo de operación no permitida para esa tarjeta", "9093" => "Tarjeta no existente", "9094" => "Rechazo servidores internacionales", "9104" => "Comercio con “titular seguro” y titular sin clave de compra segura", "9218" => "El comercio no permite op. seguras por entrada /operaciones", "9253" => "Tarjeta no cumple el check-digit", "9256" => "El comercio no puede realizar preautorizaciones", "9257" => "Esta tarjeta no permite operativa de preautorizaciones", "9261" => "Operación detenida por superar el control de restricciones en la entrada al SIS", "9915" => "A petición del usuario se ha cancelado el pago", "9929" => "Anulación de autorización en diferido realizada por el comercio", "9997" => "Se está procesando otra transacción en SIS con la misma tarjeta", "9998" => "Operación en proceso de solicitud de datos de tarjeta", "9999" => "Operación que ha sido redirigida al emisor a autenticar");
     $module = self::retrieve('md', 'String', 'GET', false);
     $qfKey = self::retrieve('qfKey', 'String', 'GET', false);
     $miObj = new RedsysAPI();
     $response = array();
     $response["version"] = $_POST["Ds_SignatureVersion"];
     $response["parameters"] = $_POST["Ds_MerchantParameters"];
     $response["signature"] = $_POST["Ds_Signature"];
     $decodecResponseJson = $miObj->decodeMerchantParameters($response["parameters"]);
     $decodecResponse = json_decode($decodecResponseJson);
     $firma = $miObj->createMerchantSignatureNotif($this->_paymentProcessor["password"], $response["parameters"]);
     // Validations
     if ($decodecResponse->Ds_MerchantCode != $this->_paymentProcessor["user_name"]) {
         CRM_Core_Error::debug_log_message("Redsys Response param Ds_MerchantCode incorrect");
         return false;
     }
     // Contribution exists and is valid
     $contribution = new CRM_Contribute_BAO_Contribution();
     $contribution->id = self::trimAmount($decodecResponse->Ds_Order);
     if (!$contribution->find(TRUE)) {
         CRM_Core_Error::debug_log_message("Could not find contribution record: {$contribution->id} in IPN request: " . print_r($params, TRUE));
         echo "Failure: Could not find contribution record for {$contribution->id}<p>";
         return FALSE;
     }
     if ($firma === $response["signature"]) {
         switch ($module) {
             case 'contribute':
                 if ($decodecResponse->Ds_Response == self::REDSYS_RESPONSE_CODE_ACCEPTED) {
                     $query = "UPDATE civicrm_contribution SET trxn_id='" . $decodecResponse->Ds_AuthorisationCode . "', contribution_status_id=1 where id='" . self::trimAmount($decodecResponse->Ds_Order) . "'";
                     CRM_Core_DAO::executeQuery($query);
                 } else {
                     $error = self::trimAmount($decodecResponse->Ds_Response);
                     if (array_key_exists($error, $errors)) {
                         $error = $errors[$error];
                     }
                     $cancel_date = CRM_Utils_Date::currentDBDate();
                     $query = "UPDATE civicrm_contribution SET contribution_status_id=3, cancel_reason = '" . $error . "' , cancel_date = '" . $cancel_date . "' where id='" . self::trimAmount($decodecResponse->Ds_Order) . "'";
                     CRM_Core_DAO::executeQuery($query);
                 }
                 break;
             case 'event':
                 if ($decodecResponse->Ds_Response == self::REDSYS_RESPONSE_CODE_ACCEPTED) {
                     $query = "UPDATE civicrm_contribution SET trxn_id='" . $decodecResponse->Ds_AuthorisationCode . "', contribution_status_id=1 where id='" . self::trimAmount($decodecResponse->Ds_Order) . "'";
                     CRM_Core_DAO::executeQuery($query);
                 } else {
                     $error = self::trimAmount($decodecResponse->Ds_Response);
                     if (array_key_exists($error, $errors)) {
                         $error = $errors[$error];
                     }
                     $cancel_date = CRM_Utils_Date::currentDBDate();
                     $query = "UPDATE civicrm_contribution SET contribution_status_id=3, cancel_reason = '" . $error . "' , cancel_date = '" . $cancel_date . "' where id='" . self::trimAmount($decodecResponse->Ds_Order) . "'";
                     CRM_Core_DAO::executeQuery($query);
                 }
                 break;
             default:
                 require_once 'CRM/Core/Error.php';
                 CRM_Core_Error::debug_log_message("Could not get module name from request url");
         }
     }
 }
/**
 * Update the recurring contribution.
 *
 * @param object $current_recur
 *   The ID of the recurring contribution
 *
 * @return object
 *   The recurring contribution object.
 */
function update_recurring_contribution($current_recur)
{
    /*
     * Creating a new recurrence object as the DAO had problems saving unless all the dates were overwritten. Seems easier to create a new object and only update the fields that are needed @todo - switching to using the api would solve the DAO dates problem & api accepts 'In Progress' so no need to resolve it first.
     */
    $updated_recur = $current_recur;
    $updated_recur->id = $current_recur->id;
    $updated_recur->modified_date = CRM_Utils_Date::isoToMysql(date('Y-m-d H:i:s'));
    $updated_recur->failure_count = $current_recur->failure_count;
    /*
     * Update the next date to schedule a contribution. If all installments complete, mark the recurring contribution as complete
     */
    if (_versionAtLeast(4.4)) {
        $updated_recur->next_sched_contribution_date = CRM_Utils_Date::isoToMysql(date('Y-m-d 00:00:00', strtotime('+' . $current_recur->frequency_interval . ' ' . $current_recur->frequency_unit)));
    } else {
        $updated_recur->next_sched_contribution = CRM_Utils_Date::isoToMysql(date('Y-m-d 00:00:00', strtotime('+' . $current_recur->frequency_interval . ' ' . $current_recur->frequency_unit)));
    }
    if (isset($current_recur->installments) && $current_recur->installments > 0) {
        $contributions = new CRM_Contribute_BAO_Contribution();
        $contributions->whereAdd("`contribution_recur_id` = " . $current_recur->id);
        $contributions->find();
        if ($contributions->N >= $current_recur->installments) {
            if (_versionAtLeast(4.4)) {
                $updated_recur->next_sched_contribution_date = NULL;
            } else {
                $updated_recur->next_sched_contribution = NULL;
            }
            $updated_recur->contribution_status_id = _eway_recurring_get_contribution_status_id('Completed');
            $updated_recur->end_date = CRM_Utils_Date::isoToMysql(date('Y-m-d 00:00:00'));
        }
    }
    return $updated_recur->save();
}
 protected function validateValue($rec, $field, $validType, $exceptionCode = 0, $import_type = 'JG')
 {
     if (!array_key_exists($field, $rec)) {
         throw new Exception("Not in record '{$field}'");
     }
     $value = $origValue = $rec[$field];
     switch ($validType) {
         //===== general types ====
         case 'money':
             //matusz: filter out all which does not make a money value invalid
             $value = str_replace('£', '', $value);
             $value = str_replace(',', '', $value);
             $value = trim($value);
             if (strlen($value) == 0) {
                 // Null entry
                 //                    throw new CRM_Finance_BAO_Import_ValidateException(
                 //                            "Can't be empty",
                 //                            $exceptionCode,
                 //                            $value);
                 $value = 0;
             }
             if (!is_numeric($value)) {
                 throw new CRM_Finance_BAO_Import_ValidateException("Invalid number", $exceptionCode, $value);
             }
             $value = floatval($value);
             //mzeman: we take negative values also as per discussion with psaleh
             //                if ($value < 0) {
             //                    throw new CRM_Finance_BAO_Import_ValidateException(
             //                            "Value is zero or less",
             //                            $exceptionCode,
             //                            $value);
             //                }
             break;
         case 'contactId':
             if (empty($value)) {
                 throw new CRM_Finance_BAO_Import_ValidateException("Contact id is empty", self::VALIDATE_ERR_NO_CONTACT, $value);
             }
             // Check if the contact exists
             require_once 'CRM/Contact/DAO/Contact.php';
             $contact = new CRM_Contact_DAO_Contact();
             $contact->id = $value;
             $contact->find();
             if (!$contact->fetch()) {
                 throw new CRM_Finance_BAO_Import_ValidateException("Can't find contact for this id", self::VALIDATE_ERR_NO_CONTACT, $value);
             }
             break;
             //===== specific types =====
         //===== specific types =====
         case 'VARef':
             $value = trim($value);
             if (empty($value)) {
                 throw new CRM_Finance_BAO_Import_ValidateException("VARef is empty", self::VALIDATE_ERR_REF_EMPTY, $value);
             }
             // Check if the contact exists
             require_once 'CRM/Contact/DAO/Contact.php';
             $contact = new CRM_Contact_DAO_Contact();
             $contact->external_identifier = $value;
             $contact->find();
             if (!$contact->fetch()) {
                 throw new CRM_Finance_BAO_Import_ValidateException("Can't find contact for this VAReference", self::VALIDATE_ERR_REF_NO_CONTACT, $value);
             }
             return array($field => $value, 'contact_id' => $contact->id, 'contact_display_name' => $contact->display_name);
             break;
         case 'campaignCode':
             $value = trim($value);
             if (empty($value)) {
                 throw new CRM_Finance_BAO_Import_ValidateException("Code invalid", self::VALIDATE_ERR_CAMPAIGN_CODE, $value);
             }
             // Check if the contact exists
             require_once 'CRM/Campaign/BAO/Campaign.php';
             $ret = civicrm_api('Campaign', 'GET', array('external_identifier' => $value, 'version' => 3));
             if ($ret['is_error'] || $ret['count'] == 0) {
                 throw new CRM_Finance_BAO_Import_ValidateException("Can't find campaign for this code", self::VALIDATE_ERR_CAMPAIGN_CODE, $value);
             }
             $id = $ret['id'];
             $contId = $this->getContributionTypeIdByCampaignId($id);
             //matusz: TODO check issue here also if its available and assigned to charity
             return array($field => $value, 'campaign_id' => $id, 'contribution_type_id' => $contId);
             break;
             // PS 03/10/2012
             // New case to deal with Campaign ID now being passed in by External Sources
         // PS 03/10/2012
         // New case to deal with Campaign ID now being passed in by External Sources
         case 'campaignID':
             $value = trim($value);
             if (empty($value)) {
                 throw new CRM_Finance_BAO_Import_ValidateException("ID invalid", self::VALIDATE_ERR_CAMPAIGN_ID, $value);
             }
             // Check if the contact exists
             require_once 'CRM/Campaign/BAO/Campaign.php';
             $ret = civicrm_api('Campaign', 'GET', array('id' => $value, 'version' => 3));
             if ($ret['is_error'] || $ret['count'] == 0) {
                 throw new CRM_Finance_BAO_Import_ValidateException("Can't find campaign for this id", self::VALIDATE_ERR_CAMPAIGN_ID, $value);
             }
             $id = $ret['id'];
             $contId = $this->getContributionTypeIdByCampaignId($id);
             //matusz: TODO check issue here also if its available and assigned to charity
             return array($field => $value, 'campaign_id' => $id, 'contribution_type_id' => $contId);
             break;
         case 'grossAmount':
             return $this->validateValue($rec, $field, 'money', self::VALIDATE_ERR_GROSSAMOUNT_INVALID);
             break;
         case 'netAmount':
             return $this->validateValue($rec, $field, 'money', self::VALIDATE_ERR_NETAMOUNT_INVALID);
             break;
         case 'feeAmount':
             try {
                 return $this->validateValue($rec, $field, 'money', self::VALIDATE_ERR_FEE_AMOUNT_INVALID);
             } catch (CRM_Finance_BAO_Import_ValidateException $e) {
                 $rec[$field] = $rec['gross_amount'] - $rec['net_amount'];
                 return $this->validateValue($rec, $field, 'money', self::VALIDATE_ERR_FEE_AMOUNT_INVALID);
             }
             break;
         case 'debit':
             $debit = $this->validateValue($rec, $field, 'money', self::VALIDATE_ERR_DEBIT_INVALID);
             return $debit;
             break;
         case 'credit':
             $credit = $this->validateValue($rec, $field, 'money', self::VALIDATE_ERR_CREDIT_INVALID);
             return array($field => $credit, 'net_amount' => $credit);
             break;
         case 'transactionId':
             require_once 'CRM/Contribute/BAO/Contribution.php';
             $contribution = new CRM_Contribute_BAO_Contribution();
             $contribution->trxn_id = $value;
             $found = $contribution->find(true);
             if ($found) {
                 //mzeman: TODO XXX DEBUG if exists delete so it's valid
                 //$contribution->delete();
                 //return array();
                 throw new CRM_Finance_BAO_Import_ValidateException("Transaction ID exists already", self::VALIDATE_ERR_TRANSACTION_EXISTS, $value);
             }
             break;
         case 'donationDate':
             if (empty($value)) {
                 throw new CRM_Finance_BAO_Import_ValidateException("donationDate is empty", self::VALIDATE_ERR_DONATIONDATE_EMPTY, $value);
             }
             $date = DateTime::createFromFormat('Y-m-d', $value);
             if ($date === false) {
                 throw new CRM_Finance_BAO_Import_ValidateException("donationDate is not in valid format YYYY-MM-DD", self::VALIDATE_ERR_DONATIONDATE_INVALID_FORMAT, $value);
             }
             break;
         case 'paidToCharityDate':
             if (empty($value)) {
                 throw new CRM_Finance_BAO_Import_ValidateException("paidToCharityDate is empty", self::VALIDATE_ERR_PAIDTOCHARITYDATE_EMPTY, $value);
             }
             $date = DateTime::createFromFormat('Y-m-d', $value);
             if ($date === false) {
                 throw new CRM_Finance_BAO_Import_ValidateException("donationDate is not in valid format YYYY-MM-DD", self::VALIDATE_ERR_PAIDTOCHARITYDATE_INVALID, $value);
             }
             break;
         case 'directDebitRef':
             return $this->validateDirectTransferRef('DIRECTDEBIT', $value, self::VALIDATE_ERR_DIRECT_DEBIT_REF);
             break;
         case 'payrollCTCRef':
             return $this->validateDirectTransferRef('PAYROLLCTC', $value, self::VALIDATE_ERR_DIRECT_DEBIT_REF);
             break;
         case 'financialImportReference':
             return $this->validateDirectTransferRef($this->directTransferCode, $value, self::VALIDATE_ERR_DIRECT_DEBIT_REF);
             break;
         default:
             throw new Exception("N/I validType: '{$validType}'");
     }
     if ($value !== $origValue) {
         return array($field => $value);
     }
     return array();
 }
 /**
  * Send receipt from contribution.
  *
  * Do not call this directly - it is being refactored. use contribution.sendmessage api call.
  *
  * Note that the compose message part has been moved to contribution
  * In general LoadObjects is called first to get the objects but the composeMessageArray function now calls it.
  *
  * @param array $input
  *   Incoming data from Payment processor.
  * @param array $ids
  *   Related object IDs.
  * @param int $contributionID
  * @param array $values
  *   Values related to objects that have already been loaded.
  * @param bool $recur
  *   Is it part of a recurring contribution.
  * @param bool $returnMessageText
  *   Should text be returned instead of sent. This.
  *   is because the function is also used to generate pdfs
  *
  * @return array
  * @throws \CRM_Core_Exception
  * @throws \CiviCRM_API3_Exception
  */
 public static function sendMail(&$input, &$ids, $contributionID, &$values, $recur = FALSE, $returnMessageText = FALSE)
 {
     $input['is_recur'] = $recur;
     $contribution = new CRM_Contribute_BAO_Contribution();
     $contribution->id = $contributionID;
     if (!$contribution->find(TRUE)) {
         throw new CRM_Core_Exception('Contribution does not exist');
     }
     $contribution->loadRelatedObjects($input, $ids, TRUE);
     // set receipt from e-mail and name in value
     if (!$returnMessageText) {
         $session = CRM_Core_Session::singleton();
         $userID = $session->get('userID');
         if (!empty($userID)) {
             list($userName, $userEmail) = CRM_Contact_BAO_Contact_Location::getEmailDetails($userID);
             $values['receipt_from_email'] = CRM_Utils_Array::value('receipt_from_email', $input, $userEmail);
             $values['receipt_from_name'] = CRM_Utils_Array::value('receipt_from_name', $input, $userName);
         }
     }
     $return = $contribution->composeMessageArray($input, $ids, $values, $recur, $returnMessageText);
     // Contribution ID should really always be set. But ?
     if (!$returnMessageText && (!isset($input['receipt_update']) || $input['receipt_update']) && empty($contribution->receipt_date)) {
         civicrm_api3('Contribution', 'create', array('receipt_date' => 'now', 'id' => $contribution->id));
     }
     return $return;
 }
 /**
  * Set up participant requirements for test.
  */
 public function _setUpParticipantObjects()
 {
     $event = $this->eventCreate(array('is_email_confirm' => 1));
     $this->assertAPISuccess($event, 'line ' . __LINE__ . ' set-up of event');
     $this->_eventId = $event['id'];
     $this->_participantId = $this->participantCreate(array('event_id' => $this->_eventId, 'contact_id' => $this->_contactId));
     //we'll create membership payment here because to make setup more re-usable
     $participantPayment = civicrm_api('participant_payment', 'create', array('version' => 3, 'contribution_id' => $this->_contributionId, 'participant_id' => $this->_participantId));
     $this->assertAPISuccess($participantPayment, 'line ' . __LINE__ . ' set-up of event');
     $contribution = new CRM_Contribute_BAO_Contribution();
     $contribution->id = $this->_contributionId;
     $contribution->find();
     $this->objects['contribution'] = $contribution;
     $this->input = array('component' => 'event', 'total_amount' => 150.0, 'invoiceID' => "c8acb91e080ad7bd8a2adc119c192885", 'contactID' => $this->_contactId, 'contributionID' => $contribution->id, 'participantID' => $this->_participantId);
     $this->ids['participant'] = $this->_participantId;
     $this->ids['event'] = $this->_eventId;
 }
Beispiel #12
0
 /**
  * Set up participant requirements for test.
  */
 public function _setUpParticipantObjects()
 {
     $event = $this->eventCreate(array('is_email_confirm' => 1));
     $this->_eventId = $event['id'];
     $this->_participantId = $this->participantCreate(array('event_id' => $this->_eventId, 'contact_id' => $this->_contactId));
     $this->callAPISuccess('participant_payment', 'create', array('contribution_id' => $this->_contributionId, 'participant_id' => $this->_participantId));
     $contribution = new CRM_Contribute_BAO_Contribution();
     $contribution->id = $this->_contributionId;
     $contribution->find();
     $this->objects['contribution'] = $contribution;
     $this->input = array('component' => 'event', 'total_amount' => 150.0, 'invoiceID' => "c8acb91e080ad7bd8a2adc119c192885", 'contactID' => $this->_contactId, 'contributionID' => $contribution->id, 'participantID' => $this->_participantId);
     $this->ids['participant'] = $this->_participantId;
     $this->ids['event'] = $this->_eventId;
 }
/**
 * Complete an existing (pending) transaction, updating related entities (participant, membership, pledge etc)
 * and taking any complete actions from the contribution page (e.g. send receipt)
 *
 * @todo - most of this should live in the BAO layer but as we want it to be an addition
 * to 4.3 which is already stable we should add it to the api layer & re-factor into the BAO layer later
 *
 * @param array $params input parameters
 * {@getfields Contribution_completetransaction}
 * @return array  Api result array
 * @static void
 * @access public
 *
 */
function civicrm_api3_contribution_completetransaction(&$params)
{
    $input = $ids = array();
    $contribution = new CRM_Contribute_BAO_Contribution();
    $contribution->id = $params['id'];
    $contribution->find(TRUE);
    if (!$contribution->id == $params['id']) {
        throw new API_Exception('A valid contribution ID is required', 'invalid_data');
    }
    try {
        if (!$contribution->loadRelatedObjects($input, $ids, FALSE, TRUE)) {
            throw new API_Exception('failed to load related objects');
        }
        $objects = $contribution->_relatedObjects;
        $objects['contribution'] =& $contribution;
        $input['component'] = $contribution->_component;
        $input['is_test'] = $contribution->is_test;
        $input['trxn_id'] = $contribution->trxn_id;
        $input['amount'] = $contribution->total_amount;
        if (isset($params['is_email_receipt'])) {
            $input['is_email_receipt'] = $params['is_email_receipt'];
        }
        // @todo required for base ipn but problematic as api layer handles this
        $transaction = new CRM_Core_Transaction();
        $ipn = new CRM_Core_Payment_BaseIPN();
        $ipn->completeTransaction($input, $ids, $objects, $transaction);
    } catch (Exception $e) {
        throw new API_Exception('failed to load related objects' . $e->getMessage() . "\n" . $e->getTraceAsString());
    }
}
Beispiel #14
0
 /**
  * Function to process the form
  *
  * @access public
  * @return None
  */
 public function postProcess()
 {
     require_once 'CRM/Member/BAO/Membership.php';
     require_once 'CRM/Member/BAO/MembershipType.php';
     require_once 'CRM/Member/BAO/MembershipStatus.php';
     if ($this->_action & CRM_Core_Action::DELETE) {
         CRM_Member_BAO_Membership::deleteRelatedMemberships($this->_id);
         CRM_Member_BAO_Membership::deleteMembership($this->_id);
         return;
     }
     $config =& CRM_Core_Config::singleton();
     // get the submitted form values.
     $this->_params = $formValues = $this->controller->exportValues($this->_name);
     $params = array();
     $ids = array();
     // set the contact, when contact is selected
     if (CRM_Utils_Array::value('contact_select_id', $formValues)) {
         $this->_contactID = CRM_Utils_Array::value('contact_select_id', $formValues);
     }
     $params['contact_id'] = $this->_contactID;
     // we need to retrieve email address
     if ($this->_context == 'standalone' && CRM_Utils_Array::value('send_receipt', $formValues)) {
         require_once 'CRM/Contact/BAO/Contact/Location.php';
         list($this->_contributorDisplayName, $this->_contributorEmail) = CRM_Contact_BAO_Contact_Location::getEmailDetails($this->_contactID);
     }
     $fields = array('status_id', 'source', 'is_override');
     foreach ($fields as $f) {
         $params[$f] = CRM_Utils_Array::value($f, $formValues);
     }
     // fix for CRM-3724
     // when is_override false ignore is_admin statuses during membership
     // status calculation. similarly we did fix for import in CRM-3570.
     if (!CRM_Utils_Array::value('is_override', $params)) {
         $params['exclude_is_admin'] = true;
     }
     $params['membership_type_id'] = $formValues['membership_type_id'][1];
     $joinDate = CRM_Utils_Date::processDate($formValues['join_date']);
     $startDate = CRM_Utils_Date::processDate($formValues['start_date']);
     $endDate = CRM_Utils_Date::processDate($formValues['end_date']);
     $calcDates = CRM_Member_BAO_MembershipType::getDatesForMembershipType($params['membership_type_id'], $joinDate, $startDate, $endDate);
     $dates = array('join_date', 'start_date', 'end_date', 'reminder_date', 'receive_date');
     $currentTime = getDate();
     foreach ($dates as $d) {
         if (isset($formValues[$d]) && !CRM_Utils_System::isNull($formValues[$d])) {
             $params[$d] = CRM_Utils_Date::processDate($formValues[$d]);
         } else {
             if (isset($calcDates[$d])) {
                 $params[$d] = CRM_Utils_Date::processDate($calcDates[$d]);
             }
         }
     }
     if ($this->_id) {
         $ids['membership'] = $params['id'] = $this->_id;
     }
     $session = CRM_Core_Session::singleton();
     $ids['userId'] = $session->get('userID');
     // membership type custom data
     $customFields = CRM_Core_BAO_CustomField::getFields('Membership', false, false, CRM_Utils_Array::value('membership_type_id', $params));
     $customFields = CRM_Utils_Array::crmArrayMerge($customFields, CRM_Core_BAO_CustomField::getFields('Membership', false, false, null, null, true));
     $params['custom'] = CRM_Core_BAO_CustomField::postProcess($formValues, $customFields, $this->_id, 'Membership');
     // Retrieve the name and email of the current user - this will be the FROM for the receipt email
     require_once 'CRM/Contact/BAO/Contact/Location.php';
     list($userName, $userEmail) = CRM_Contact_BAO_Contact_Location::getEmailDetails($ids['userId']);
     if (CRM_Utils_Array::value('record_contribution', $formValues)) {
         $recordContribution = array('total_amount', 'contribution_type_id', 'payment_instrument_id', 'trxn_id', 'contribution_status_id', 'check_number');
         foreach ($recordContribution as $f) {
             $params[$f] = CRM_Utils_Array::value($f, $formValues);
         }
         $membershipType = CRM_Core_DAO::getFieldValue('CRM_Member_DAO_MembershipType', $formValues['membership_type_id'][1]);
         if (!$this->_onlinePendingContributionId) {
             $params['contribution_source'] = "{$membershipType} Membership: Offline membership signup (by {$userName})";
         }
         if ($formValues['send_receipt']) {
             $params['receipt_date'] = $params['receive_date'];
         }
         //insert contribution type name in receipt.
         $formValues['contributionType_name'] = CRM_Core_DAO::getFieldValue('CRM_Contribute_DAO_ContributionType', $formValues['contribution_type_id']);
     }
     if ($this->_mode) {
         $params['total_amount'] = $formValues['total_amount'] = CRM_Core_DAO::getFieldValue('CRM_Member_DAO_MembershipType', $params['membership_type_id'], 'minimum_fee');
         $params['contribution_type_id'] = CRM_Core_DAO::getFieldValue('CRM_Member_DAO_MembershipType', $params['membership_type_id'], 'contribution_type_id');
         require_once 'CRM/Core/BAO/PaymentProcessor.php';
         $this->_paymentProcessor = CRM_Core_BAO_PaymentProcessor::getPayment($formValues['payment_processor_id'], $this->_mode);
         require_once "CRM/Contact/BAO/Contact.php";
         $now = date('YmdHis');
         $fields = array();
         // set email for primary location.
         $fields["email-Primary"] = 1;
         $formValues["email-5"] = $formValues["email-Primary"] = $this->_contributorEmail;
         $params['register_date'] = $now;
         // now set the values for the billing location.
         foreach ($this->_fields as $name => $dontCare) {
             $fields[$name] = 1;
         }
         // also add location name to the array
         $formValues["address_name-{$this->_bltID}"] = CRM_Utils_Array::value('billing_first_name', $formValues) . ' ' . CRM_Utils_Array::value('billing_middle_name', $formValues) . ' ' . CRM_Utils_Array::value('billing_last_name', $formValues);
         $formValues["address_name-{$this->_bltID}"] = trim($formValues["address_name-{$this->_bltID}"]);
         $fields["address_name-{$this->_bltID}"] = 1;
         $fields["email-{$this->_bltID}"] = 1;
         $ctype = CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_Contact', $this->_contactID, 'contact_type');
         $nameFields = array('first_name', 'middle_name', 'last_name');
         foreach ($nameFields as $name) {
             $fields[$name] = 1;
             if (array_key_exists("billing_{$name}", $formValues)) {
                 $formValues[$name] = $formValues["billing_{$name}"];
                 $formValues['preserveDBName'] = true;
             }
         }
         $contactID = CRM_Contact_BAO_Contact::createProfileContact($formValues, $fields, $this->_contactID, null, null, $ctype);
         // add all the additioanl payment params we need
         $this->_params["state_province-{$this->_bltID}"] = $this->_params["billing_state_province-{$this->_bltID}"] = CRM_Core_PseudoConstant::stateProvinceAbbreviation($this->_params["billing_state_province_id-{$this->_bltID}"]);
         $this->_params["country-{$this->_bltID}"] = $this->_params["billing_country-{$this->_bltID}"] = CRM_Core_PseudoConstant::countryIsoCode($this->_params["billing_country_id-{$this->_bltID}"]);
         $this->_params['year'] = $this->_params['credit_card_exp_date']['Y'];
         $this->_params['month'] = $this->_params['credit_card_exp_date']['M'];
         $this->_params['ip_address'] = CRM_Utils_System::ipAddress();
         $this->_params['amount'] = $params['total_amount'];
         $this->_params['currencyID'] = $config->defaultCurrency;
         $this->_params['payment_action'] = 'Sale';
         $this->_params['invoiceID'] = md5(uniqid(rand(), true));
         // at this point we've created a contact and stored its address etc
         // all the payment processors expect the name and address to be in the
         // so we copy stuff over to first_name etc.
         $paymentParams = $this->_params;
         if (CRM_Utils_Array::value('send_receipt', $this->_params)) {
             $paymentParams['email'] = $this->_contributorEmail;
         }
         require_once 'CRM/Core/Payment/Form.php';
         CRM_Core_Payment_Form::mapParams($this->_bltID, $this->_params, $paymentParams, true);
         $payment =& CRM_Core_Payment::singleton($this->_mode, 'Contribute', $this->_paymentProcessor, $this);
         $result =& $payment->doDirectPayment($paymentParams);
         if (is_a($result, 'CRM_Core_Error')) {
             CRM_Core_Error::displaySessionError($result);
             CRM_Utils_System::redirect(CRM_Utils_System::url('civicrm/contact/view/membership', "reset=1&action=add&cid={$this->_contactID}&context=&mode={$this->_mode}"));
         }
         if ($result) {
             $this->_params = array_merge($this->_params, $result);
         }
         $params['contribution_status_id'] = 1;
         $params['receive_date'] = $now;
         $params['invoice_id'] = $this->_params['invoiceID'];
         $params['contribution_source'] = ts('Online Membership: Admin Interface');
         $params['source'] = $formValues['source'] ? $formValues['source'] : $params['contribution_source'];
         $params['trxn_id'] = $result['trxn_id'];
         $params['payment_instrument_id'] = 1;
         $params['is_test'] = $this->_mode == 'live' ? 0 : 1;
         if (CRM_Utils_Array::value('send_receipt', $this->_params)) {
             $params['receipt_date'] = $now;
         } else {
             $params['receipt_date'] = null;
         }
         $this->set('params', $this->_params);
         $this->assign('trxn_id', $result['trxn_id']);
         $this->assign('receive_date', CRM_Utils_Date::mysqlToIso($params['receive_date']));
         // required for creating membership for related contacts
         $params['action'] = $this->_action;
         $membership =& CRM_Member_BAO_Membership::create($params, $ids);
         $contribution = new CRM_Contribute_BAO_Contribution();
         $contribution->trxn_id = $result['trxn_id'];
         if ($contribution->find(true)) {
             // next create the transaction record
             $trxnParams = array('contribution_id' => $contribution->id, 'trxn_date' => $now, 'trxn_type' => 'Debit', 'total_amount' => $params['total_amount'], 'fee_amount' => CRM_Utils_Array::value('fee_amount', $result), 'net_amount' => CRM_Utils_Array::value('net_amount', $result, $params['total_amount']), 'currency' => $config->defaultCurrency, 'payment_processor' => $this->_paymentProcessor['payment_processor_type'], 'trxn_id' => $result['trxn_id']);
             require_once 'CRM/Contribute/BAO/FinancialTrxn.php';
             $trxn =& CRM_Contribute_BAO_FinancialTrxn::create($trxnParams);
         }
     } else {
         $params['action'] = $this->_action;
         if ($this->_onlinePendingContributionId && CRM_Utils_Array::value('record_contribution', $formValues)) {
             // update membership as well as contribution object, CRM-4395
             require_once 'CRM/Contribute/Form/Contribution.php';
             $params['contribution_id'] = $this->_onlinePendingContributionId;
             $params['componentId'] = $params['id'];
             $params['componentName'] = 'contribute';
             $result = CRM_Contribute_BAO_Contribution::transitionComponents($params, true);
             //carry updated membership object.
             $membership =& new CRM_Member_DAO_Membership();
             $membership->id = $this->_id;
             $membership->find(true);
             $cancelled = true;
             if ($membership->end_date) {
                 //display end date w/ status message.
                 $endDate = $membership->end_date;
                 require_once 'CRM/Member/PseudoConstant.php';
                 $membershipStatues = CRM_Member_PseudoConstant::membershipStatus();
                 if (!in_array($membership->status_id, array(array_search('Cancelled', $membershipStatues), array_search('Expired', $membershipStatues)))) {
                     $cancelled = false;
                 }
             }
             // suppress form values in template.
             $this->assign('cancelled', $cancelled);
         } else {
             $membership =& CRM_Member_BAO_Membership::create($params, $ids);
         }
     }
     if (CRM_Utils_Array::value('send_receipt', $formValues)) {
         require_once 'CRM/Core/DAO.php';
         CRM_Core_DAO::setFieldValue('CRM_Member_DAO_MembershipType', $params['membership_type_id'], 'receipt_text_signup', $formValues['receipt_text_signup']);
     }
     $receiptSend = false;
     if (CRM_Utils_Array::value('send_receipt', $formValues)) {
         $receiptSend = true;
         $receiptFrom = "{$userName} <{$userEmail}>";
         if (CRM_Utils_Array::value('payment_instrument_id', $formValues)) {
             $paymentInstrument = CRM_Contribute_PseudoConstant::paymentInstrument();
             $formValues['paidBy'] = $paymentInstrument[$formValues['payment_instrument_id']];
         }
         // retrieve custom data
         require_once "CRM/Core/BAO/UFGroup.php";
         $customFields = $customValues = array();
         foreach ($this->_groupTree as $groupID => $group) {
             if ($groupID == 'info') {
                 continue;
             }
             foreach ($group['fields'] as $k => $field) {
                 $field['title'] = $field['label'];
                 $customFields["custom_{$k}"] = $field;
             }
         }
         $members = array(array('member_id', '=', $membership->id, 0, 0));
         // check whether its a test drive
         if ($this->_mode) {
             $members[] = array('member_test', '=', 1, 0, 0);
         }
         CRM_Core_BAO_UFGroup::getValues($this->_contactID, $customFields, $customValues, false, $members);
         if ($this->_mode) {
             if (CRM_Utils_Array::value('billing_first_name', $this->_params)) {
                 $name = $this->_params['billing_first_name'];
             }
             if (CRM_Utils_Array::value('billing_middle_name', $this->_params)) {
                 $name .= " {$this->_params['billing_middle_name']}";
             }
             if (CRM_Utils_Array::value('billing_last_name', $this->_params)) {
                 $name .= " {$this->_params['billing_last_name']}";
             }
             $this->assign('billingName', $name);
             // assign the address formatted up for display
             $addressParts = array("street_address-{$this->_bltID}", "city-{$this->_bltID}", "postal_code-{$this->_bltID}", "state_province-{$this->_bltID}", "country-{$this->_bltID}");
             $addressFields = array();
             foreach ($addressParts as $part) {
                 list($n, $id) = explode('-', $part);
                 if (isset($this->_params['billing_' . $part])) {
                     $addressFields[$n] = $this->_params['billing_' . $part];
                 }
             }
             require_once 'CRM/Utils/Address.php';
             $this->assign('address', CRM_Utils_Address::format($addressFields));
             $date = CRM_Utils_Date::format($this->_params['credit_card_exp_date']);
             $date = CRM_Utils_Date::mysqlToIso($date);
             $this->assign('credit_card_exp_date', $date);
             $this->assign('credit_card_number', CRM_Utils_System::mungeCreditCard($this->_params['credit_card_number']));
             $this->assign('credit_card_type', $this->_params['credit_card_type']);
             $this->assign('contributeMode', 'direct');
             $this->assign('isAmountzero', 0);
             $this->assign('is_pay_later', 0);
             $this->assign('isPrimary', 1);
         }
         $this->assign('module', 'Membership');
         $this->assign('contactID', $this->_contactID);
         $this->assign('membershipID', $params['membership_id']);
         $this->assign('receiptType', 'membership signup');
         $this->assign('receive_date', $params['receive_date']);
         $this->assign('formValues', $formValues);
         $this->assign('mem_start_date', CRM_Utils_Date::customFormat($calcDates['start_date']));
         $this->assign('mem_end_date', CRM_Utils_Date::customFormat($calcDates['end_date']));
         $this->assign('membership_name', CRM_Core_DAO::getFieldValue('CRM_Member_DAO_MembershipType', $formValues['membership_type_id'][1]));
         $this->assign('customValues', $customValues);
         require_once 'CRM/Core/BAO/MessageTemplates.php';
         list($mailSend, $subject, $message, $html) = CRM_Core_BAO_MessageTemplates::sendTemplate(array('groupName' => 'msg_tpl_workflow_contribution', 'valueName' => 'contribution_offline_receipt', 'contactId' => $this->_contactID, 'from' => $receiptFrom, 'toName' => $this->_contributorDisplayName, 'toEmail' => $this->_contributorEmail, 'isTest' => (bool) ($this->_action & CRM_Core_Action::PREVIEW)));
     }
     if ($this->_action & CRM_Core_Action::UPDATE) {
         $statusMsg = ts('Membership for %1 has been updated.', array(1 => $this->_contributorDisplayName));
         if ($endDate) {
             $endDate = CRM_Utils_Date::customFormat($endDate);
             $statusMsg .= ' ' . ts('The membership End Date is %1.', array(1 => $endDate));
         }
         if ($receiptSend) {
             $statusMsg .= ' ' . ts('A confirmation and receipt has been sent to %1.', array(1 => $this->_contributorEmail));
         }
     } elseif ($this->_action & CRM_Core_Action::ADD) {
         require_once 'CRM/Core/DAO.php';
         $memType = CRM_Core_DAO::getFieldValue('CRM_Member_DAO_MembershipType', $params['membership_type_id']);
         $statusMsg = ts('%1 membership for %2 has been added.', array(1 => $memType, 2 => $this->_contributorDisplayName));
         //get the end date from calculated dates.
         $endDate = $endDate ? $endDate : CRM_Utils_Array::value('end_date', $calcDates);
         if ($endDate) {
             $endDate = CRM_Utils_Date::customFormat($endDate);
             $statusMsg .= ' ' . ts('The new membership End Date is %1.', array(1 => $endDate));
         }
         if ($receiptSend && $mailSend) {
             $statusMsg .= ' ' . ts('A membership confirmation and receipt has been sent to %1.', array(1 => $this->_contributorEmail));
         }
     }
     CRM_Core_Session::setStatus($statusMsg);
     $buttonName = $this->controller->getButtonName();
     if ($this->_context == 'standalone') {
         if ($buttonName == $this->getButtonName('upload', 'new')) {
             $session->replaceUserContext(CRM_Utils_System::url('civicrm/member/add', 'reset=1&action=add&context=standalone'));
         } else {
             $session->replaceUserContext(CRM_Utils_System::url('civicrm/contact/view', "reset=1&cid={$this->_contactID}&selectedChild=member"));
         }
     } else {
         if ($buttonName == $this->getButtonName('upload', 'new')) {
             $session->replaceUserContext(CRM_Utils_System::url('civicrm/contact/view/membership', "reset=1&action=add&context=membership&cid={$this->_contactID}"));
         }
     }
 }
Beispiel #15
0
 /**
  * Process the form submission.
  *
  *
  * @return void
  */
 public function postProcess()
 {
     if ($this->_action & CRM_Core_Action::DELETE) {
         CRM_Member_BAO_Membership::del($this->_id);
         return;
     }
     $allMemberStatus = CRM_Member_PseudoConstant::membershipStatus();
     $allContributionStatus = CRM_Contribute_PseudoConstant::contributionStatus();
     $isTest = $this->_mode == 'test' ? 1 : 0;
     $lineItems = NULL;
     if (!empty($this->_lineItem)) {
         $lineItems = $this->_lineItem;
     }
     $config = CRM_Core_Config::singleton();
     // get the submitted form values.
     $this->_params = $formValues = $this->controller->exportValues($this->_name);
     $this->convertDateFieldsToMySQL($formValues);
     $params = $softParams = $ids = array();
     $membershipTypeValues = array();
     foreach ($this->_memTypeSelected as $memType) {
         $membershipTypeValues[$memType]['membership_type_id'] = $memType;
     }
     //take the required membership recur values.
     if ($this->_mode && !empty($this->_params['auto_renew'])) {
         $params['is_recur'] = $this->_params['is_recur'] = $formValues['is_recur'] = TRUE;
         $mapping = array('frequency_interval' => 'duration_interval', 'frequency_unit' => 'duration_unit');
         $count = 0;
         foreach ($this->_memTypeSelected as $memType) {
             $recurMembershipTypeValues = CRM_Utils_Array::value($memType, $this->_recurMembershipTypes, array());
             foreach ($mapping as $mapVal => $mapParam) {
                 $membershipTypeValues[$memType][$mapVal] = CRM_Utils_Array::value($mapParam, $recurMembershipTypeValues);
                 if (!$count) {
                     $this->_params[$mapVal] = $formValues[$mapVal] = CRM_Utils_Array::value($mapParam, $recurMembershipTypeValues);
                 }
             }
             $count++;
         }
     }
     // process price set and get total amount and line items.
     $lineItem = array();
     $priceSetId = NULL;
     if (!($priceSetId = CRM_Utils_Array::value('price_set_id', $formValues))) {
         CRM_Member_BAO_Membership::createLineItems($this, $formValues['membership_type_id'], $priceSetId);
     }
     $isQuickConfig = 0;
     if ($this->_priceSetId && CRM_Core_DAO::getFieldValue('CRM_Price_DAO_PriceSet', $this->_priceSetId, 'is_quick_config')) {
         $isQuickConfig = 1;
     }
     $termsByType = array();
     if ($priceSetId) {
         CRM_Price_BAO_PriceSet::processAmount($this->_priceSet['fields'], $this->_params, $lineItem[$priceSetId]);
         if (CRM_Utils_Array::value('tax_amount', $this->_params)) {
             $params['tax_amount'] = $this->_params['tax_amount'];
         }
         $params['total_amount'] = CRM_Utils_Array::value('amount', $this->_params);
         $submittedFinancialType = CRM_Utils_Array::value('financial_type_id', $formValues);
         if (!empty($lineItem[$priceSetId])) {
             foreach ($lineItem[$priceSetId] as &$li) {
                 if (!empty($li['membership_type_id'])) {
                     if (!empty($li['membership_num_terms'])) {
                         $termsByType[$li['membership_type_id']] = $li['membership_num_terms'];
                     }
                 }
                 ///CRM-11529 for quick config backoffice transactions
                 //when financial_type_id is passed in form, update the
                 //lineitems with the financial type selected in form
                 if ($isQuickConfig && $submittedFinancialType) {
                     $li['financial_type_id'] = $submittedFinancialType;
                 }
             }
         }
     }
     $this->storeContactFields($formValues);
     $params['contact_id'] = $this->_contactID;
     $fields = array('status_id', 'source', 'is_override', 'campaign_id');
     foreach ($fields as $f) {
         $params[$f] = CRM_Utils_Array::value($f, $formValues);
     }
     // fix for CRM-3724
     // when is_override false ignore is_admin statuses during membership
     // status calculation. similarly we did fix for import in CRM-3570.
     if (empty($params['is_override'])) {
         $params['exclude_is_admin'] = TRUE;
     }
     // process date params to mysql date format.
     $dateTypes = array('join_date' => 'joinDate', 'start_date' => 'startDate', 'end_date' => 'endDate');
     foreach ($dateTypes as $dateField => $dateVariable) {
         ${$dateVariable} = CRM_Utils_Date::processDate($formValues[$dateField]);
     }
     $memTypeNumTerms = empty($termsByType) ? CRM_Utils_Array::value('num_terms', $formValues) : NULL;
     $calcDates = array();
     foreach ($this->_memTypeSelected as $memType) {
         if (empty($memTypeNumTerms)) {
             $memTypeNumTerms = CRM_Utils_Array::value($memType, $termsByType, 1);
         }
         $calcDates[$memType] = CRM_Member_BAO_MembershipType::getDatesForMembershipType($memType, $joinDate, $startDate, $endDate, $memTypeNumTerms);
     }
     foreach ($calcDates as $memType => $calcDate) {
         foreach (array_keys($dateTypes) as $d) {
             //first give priority to form values then calDates.
             $date = CRM_Utils_Array::value($d, $formValues);
             if (!$date) {
                 $date = CRM_Utils_Array::value($d, $calcDate);
             }
             $membershipTypeValues[$memType][$d] = CRM_Utils_Date::processDate($date);
             //$params[$d] = CRM_Utils_Date::processDate( $date );
         }
     }
     // max related memberships - take from form or inherit from membership type
     foreach ($this->_memTypeSelected as $memType) {
         if (array_key_exists('max_related', $formValues)) {
             $membershipTypeValues[$memType]['max_related'] = CRM_Utils_Array::value('max_related', $formValues);
         }
     }
     if ($this->_id) {
         $ids['membership'] = $params['id'] = $this->_id;
     }
     $session = CRM_Core_Session::singleton();
     $ids['userId'] = $session->get('userID');
     // membership type custom data
     foreach ($this->_memTypeSelected as $memType) {
         $customFields = CRM_Core_BAO_CustomField::getFields('Membership', FALSE, FALSE, $memType);
         $customFields = CRM_Utils_Array::crmArrayMerge($customFields, CRM_Core_BAO_CustomField::getFields('Membership', FALSE, FALSE, NULL, NULL, TRUE));
         $membershipTypeValues[$memType]['custom'] = CRM_Core_BAO_CustomField::postProcess($formValues, $customFields, $this->_id, 'Membership');
     }
     foreach ($this->_memTypeSelected as $memType) {
         $membershipTypes[$memType] = CRM_Core_DAO::getFieldValue('CRM_Member_DAO_MembershipType', $memType);
     }
     $membershipType = implode(', ', $membershipTypes);
     // Retrieve the name and email of the current user - this will be the FROM for the receipt email
     list($userName, $userEmail) = CRM_Contact_BAO_Contact_Location::getEmailDetails($ids['userId']);
     //CRM-13981, allow different person as a soft-contributor of chosen type
     if ($this->_contributorContactID != $this->_contactID) {
         $params['contribution_contact_id'] = $this->_contributorContactID;
         if (!empty($this->_params['soft_credit_type_id'])) {
             $softParams['soft_credit_type_id'] = $this->_params['soft_credit_type_id'];
             $softParams['contact_id'] = $this->_contactID;
         }
     }
     if (!empty($formValues['record_contribution'])) {
         $recordContribution = array('total_amount', 'financial_type_id', 'payment_instrument_id', 'trxn_id', 'contribution_status_id', 'check_number', 'campaign_id', 'receive_date');
         foreach ($recordContribution as $f) {
             $params[$f] = CRM_Utils_Array::value($f, $formValues);
         }
         if (!$this->_onlinePendingContributionId) {
             if (empty($formValues['source'])) {
                 $params['contribution_source'] = ts('%1 Membership: Offline signup (by %2)', array(1 => $membershipType, 2 => $userName));
             } else {
                 $params['contribution_source'] = $formValues['source'];
             }
         }
         if (empty($params['is_override']) && CRM_Utils_Array::value('contribution_status_id', $params) == array_search('Pending', CRM_Contribute_PseudoConstant::contributionStatus(NULL, 'name'))) {
             $params['status_id'] = array_search('Pending', $allMemberStatus);
             $params['skipStatusCal'] = TRUE;
             $params['is_pay_later'] = 1;
             $this->assign('is_pay_later', 1);
         }
         if (!empty($formValues['send_receipt'])) {
             $params['receipt_date'] = CRM_Utils_Array::value('receive_date', $formValues);
         }
         //insert financial type name in receipt.
         $formValues['contributionType_name'] = CRM_Core_DAO::getFieldValue('CRM_Financial_DAO_FinancialType', $formValues['financial_type_id']);
     }
     // process line items, until no previous line items.
     if (!empty($lineItem)) {
         $params['lineItems'] = $lineItem;
         $params['processPriceSet'] = TRUE;
     }
     $createdMemberships = array();
     if ($this->_mode) {
         if (empty($formValues['total_amount']) && !$priceSetId) {
             // if total amount not provided minimum for membership type is used
             $params['total_amount'] = $formValues['total_amount'] = CRM_Core_DAO::getFieldValue('CRM_Member_DAO_MembershipType', $formValues['membership_type_id'][1], 'minimum_fee');
         } else {
             $params['total_amount'] = CRM_Utils_Array::value('total_amount', $formValues, 0);
         }
         if ($priceSetId && !$isQuickConfig) {
             $params['financial_type_id'] = CRM_Core_DAO::getFieldValue('CRM_Price_DAO_PriceSet', $priceSetId, 'financial_type_id');
         } else {
             $params['financial_type_id'] = CRM_Utils_Array::value('financial_type_id', $formValues);
         }
         $this->_paymentProcessor = CRM_Financial_BAO_PaymentProcessor::getPayment($formValues['payment_processor_id'], $this->_mode);
         //get the payment processor id as per mode.
         $params['payment_processor_id'] = $this->_params['payment_processor_id'] = $formValues['payment_processor_id'] = $this->_paymentProcessor['id'];
         $now = date('YmdHis');
         $fields = array();
         // set email for primary location.
         $fields['email-Primary'] = 1;
         $formValues['email-5'] = $formValues['email-Primary'] = $this->_memberEmail;
         $params['register_date'] = $now;
         // now set the values for the billing location.
         foreach ($this->_fields as $name => $dontCare) {
             $fields[$name] = 1;
         }
         // also add location name to the array
         $formValues["address_name-{$this->_bltID}"] = CRM_Utils_Array::value('billing_first_name', $formValues) . ' ' . CRM_Utils_Array::value('billing_middle_name', $formValues) . ' ' . CRM_Utils_Array::value('billing_last_name', $formValues);
         $formValues["address_name-{$this->_bltID}"] = trim($formValues["address_name-{$this->_bltID}"]);
         $fields["address_name-{$this->_bltID}"] = 1;
         //ensure we don't over-write the payer's email with the member's email
         if ($this->_contributorContactID == $this->_contactID) {
             $fields["email-{$this->_bltID}"] = 1;
         }
         $ctype = CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_Contact', $this->_contactID, 'contact_type');
         $nameFields = array('first_name', 'middle_name', 'last_name');
         foreach ($nameFields as $name) {
             $fields[$name] = 1;
             if (array_key_exists("billing_{$name}", $formValues)) {
                 $formValues[$name] = $formValues["billing_{$name}"];
                 $formValues['preserveDBName'] = TRUE;
             }
         }
         if ($this->_contributorContactID == $this->_contactID) {
             //see CRM-12869 for discussion of why we don't do this for separate payee payments
             CRM_Contact_BAO_Contact::createProfileContact($formValues, $fields, $this->_contributorContactID, NULL, NULL, $ctype);
         }
         // add all the additional payment params we need
         $this->_params["state_province-{$this->_bltID}"] = $this->_params["billing_state_province-{$this->_bltID}"] = CRM_Core_PseudoConstant::stateProvinceAbbreviation($this->_params["billing_state_province_id-{$this->_bltID}"]);
         $this->_params["country-{$this->_bltID}"] = $this->_params["billing_country-{$this->_bltID}"] = CRM_Core_PseudoConstant::countryIsoCode($this->_params["billing_country_id-{$this->_bltID}"]);
         $this->_params['year'] = CRM_Core_Payment_Form::getCreditCardExpirationYear($this->_params);
         $this->_params['month'] = CRM_Core_Payment_Form::getCreditCardExpirationMonth($this->_params);
         $this->_params['ip_address'] = CRM_Utils_System::ipAddress();
         $this->_params['amount'] = $params['total_amount'];
         $this->_params['currencyID'] = $config->defaultCurrency;
         $this->_params['description'] = ts('Office Credit Card Membership Signup Contribution');
         $this->_params['payment_action'] = 'Sale';
         $this->_params['invoiceID'] = md5(uniqid(rand(), TRUE));
         $this->_params['financial_type_id'] = $params['financial_type_id'];
         // at this point we've created a contact and stored its address etc
         // all the payment processors expect the name and address to be in the
         // so we copy stuff over to first_name etc.
         $paymentParams = $this->_params;
         $paymentParams['contactID'] = $this->_contributorContactID;
         //CRM-10377 if payment is by an alternate contact then we need to set that person
         // as the contact in the payment params
         if ($this->_contributorContactID != $this->_contactID) {
             if (!empty($this->_params['soft_credit_type_id'])) {
                 $softParams['contact_id'] = $params['contact_id'];
                 $softParams['soft_credit_type_id'] = $this->_params['soft_credit_type_id'];
             }
         }
         if (!empty($this->_params['send_receipt'])) {
             $paymentParams['email'] = $this->_contributorEmail;
         }
         CRM_Core_Payment_Form::mapParams($this->_bltID, $this->_params, $paymentParams, TRUE);
         // CRM-7137 -for recurring membership,
         // we do need contribution and recuring records.
         $result = NULL;
         if (!empty($paymentParams['is_recur'])) {
             $contributionType = new CRM_Financial_DAO_FinancialType();
             $contributionType->id = $params['financial_type_id'];
             if (!$contributionType->find(TRUE)) {
                 CRM_Core_Error::fatal('Could not find a system table');
             }
             $contribution = CRM_Contribute_Form_Contribution_Confirm::processContribution($this, $paymentParams, $result, $this->_contributorContactID, $contributionType, TRUE, FALSE, $isTest, $lineItems);
             //create new soft-credit record, CRM-13981
             if ($softParams) {
                 $softParams['contribution_id'] = $contribution->id;
                 $softParams['currency'] = $contribution->currency;
                 $softParams['amount'] = $contribution->total_amount;
                 CRM_Contribute_BAO_ContributionSoft::add($softParams);
             }
             $paymentParams['contactID'] = $this->_contactID;
             $paymentParams['contributionID'] = $contribution->id;
             $paymentParams['contributionTypeID'] = $contribution->financial_type_id;
             $paymentParams['contributionPageID'] = $contribution->contribution_page_id;
             $paymentParams['contributionRecurID'] = $contribution->contribution_recur_id;
             $ids['contribution'] = $contribution->id;
             $params['contribution_recur_id'] = $paymentParams['contributionRecurID'];
         }
         if ($params['total_amount'] > 0.0) {
             $payment = CRM_Core_Payment::singleton($this->_mode, $this->_paymentProcessor, $this);
             $result = $payment->doDirectPayment($paymentParams);
         }
         if (is_a($result, 'CRM_Core_Error')) {
             //make sure to cleanup db for recurring case.
             if (!empty($paymentParams['contributionID'])) {
                 CRM_Contribute_BAO_Contribution::deleteContribution($paymentParams['contributionID']);
             }
             if (!empty($paymentParams['contributionRecurID'])) {
                 CRM_Contribute_BAO_ContributionRecur::deleteRecurContribution($paymentParams['contributionRecurID']);
             }
             CRM_Core_Error::displaySessionError($result);
             CRM_Utils_System::redirect(CRM_Utils_System::url('civicrm/contact/view/membership', "reset=1&action=add&cid={$this->_contactID}&context=&mode={$this->_mode}"));
         }
         if ($result) {
             $this->_params = array_merge($this->_params, $result);
             //assign amount to template if payment was successful
             $this->assign('amount', $params['total_amount']);
         }
         // if the payment processor returns a contribution_status_id -> use it!
         if (isset($result['contribution_status_id'])) {
             $result['payment_status_id'] = $result['contribution_status_id'];
         }
         if (isset($result['payment_status_id'])) {
             // CRM-16737 $result['contribution_status_id'] is deprecated in favour
             // of payment_status_id as the payment processor only knows whether the payment is complete
             // not whether payment completes the contribution
             $params['contribution_status_id'] = $result['payment_status_id'];
         } else {
             $params['contribution_status_id'] = !empty($paymentParams['is_recur']) ? 2 : 1;
         }
         if ($params['contribution_status_id'] != array_search('Completed', $allContributionStatus)) {
             $params['status_id'] = array_search('Pending', $allMemberStatus);
             $params['skipStatusCal'] = TRUE;
             // unset send-receipt option, since receipt will be sent when ipn is received.
             unset($this->_params['send_receipt'], $formValues['send_receipt']);
             //as membership is pending set dates to null.
             $memberDates = array('join_date' => 'joinDate', 'start_date' => 'startDate', 'end_date' => 'endDate');
             foreach ($memberDates as $dp => $dv) {
                 ${$dv} = NULL;
                 foreach ($this->_memTypeSelected as $memType) {
                     $membershipTypeValues[$memType][$dv] = NULL;
                 }
             }
         }
         $params['receive_date'] = $now;
         $params['invoice_id'] = $this->_params['invoiceID'];
         $params['contribution_source'] = ts('%1 Membership Signup: Credit card or direct debit (by %2)', array(1 => $membershipType, 2 => $userName));
         $params['source'] = $formValues['source'] ? $formValues['source'] : $params['contribution_source'];
         $params['trxn_id'] = CRM_Utils_Array::value('trxn_id', $result);
         $params['payment_instrument_id'] = 1;
         $params['is_test'] = $this->_mode == 'live' ? 0 : 1;
         if (!empty($this->_params['send_receipt'])) {
             $params['receipt_date'] = $now;
         } else {
             $params['receipt_date'] = NULL;
         }
         $this->set('params', $this->_params);
         $this->assign('trxn_id', CRM_Utils_Array::value('trxn_id', $result));
         $this->assign('receive_date', CRM_Utils_Date::mysqlToIso($params['receive_date']));
         // required for creating membership for related contacts
         $params['action'] = $this->_action;
         //create membership record.
         $count = 0;
         foreach ($this->_memTypeSelected as $memType) {
             if ($count && ($relateContribution = CRM_Member_BAO_Membership::getMembershipContributionId($membership->id))) {
                 $membershipTypeValues[$memType]['relate_contribution_id'] = $relateContribution;
             }
             $membershipParams = array_merge($membershipTypeValues[$memType], $params);
             //CRM-15366
             if (!empty($softParams) && empty($paymentParams['is_recur'])) {
                 $membershipParams['soft_credit'] = $softParams;
             }
             if (!empty($paymentParams['is_recur']) && CRM_Utils_Array::value('payment_status_id', $result) == 1) {
                 // CRM-16993 we have a situation where line items have already been created.
                 unset($membershipParams['lineItems']);
             }
             $membership = CRM_Member_BAO_Membership::create($membershipParams, $ids);
             $params['contribution'] = CRM_Utils_Array::value('contribution', $membershipParams);
             unset($params['lineItems']);
             $this->_membershipIDs[] = $membership->id;
             $createdMemberships[$memType] = $membership;
             $count++;
         }
     } else {
         $params['action'] = $this->_action;
         if ($this->_onlinePendingContributionId && !empty($formValues['record_contribution'])) {
             // update membership as well as contribution object, CRM-4395
             $params['contribution_id'] = $this->_onlinePendingContributionId;
             $params['componentId'] = $params['id'];
             $params['componentName'] = 'contribute';
             $result = CRM_Contribute_BAO_Contribution::transitionComponents($params, TRUE);
             if (!empty($result) && !empty($params['contribution_id'])) {
                 $lineItem = array();
                 $lineItems = CRM_Price_BAO_LineItem::getLineItems($params['contribution_id'], 'contribution', NULL, TRUE, TRUE);
                 $itemId = key($lineItems);
                 $priceSetId = CRM_Core_DAO::getFieldValue('CRM_Price_DAO_PriceField', $lineItems[$itemId]['price_field_id'], 'price_set_id');
                 $fieldType = NULL;
                 if ($itemId && !empty($lineItems[$itemId]['price_field_id'])) {
                     $fieldType = CRM_Core_DAO::getFieldValue('CRM_Price_DAO_PriceField', $lineItems[$itemId]['price_field_id'], 'html_type');
                 }
                 $lineItems[$itemId]['unit_price'] = $params['total_amount'];
                 $lineItems[$itemId]['line_total'] = $params['total_amount'];
                 $lineItems[$itemId]['id'] = $itemId;
                 $lineItem[$priceSetId] = $lineItems;
                 $contributionBAO = new CRM_Contribute_BAO_Contribution();
                 $contributionBAO->id = $params['contribution_id'];
                 $contributionBAO->contact_id = $params['contact_id'];
                 $contributionBAO->find();
                 CRM_Price_BAO_LineItem::processPriceSet($params['contribution_id'], $lineItem, $contributionBAO, 'civicrm_membership');
                 //create new soft-credit record, CRM-13981
                 if ($softParams) {
                     $softParams['contribution_id'] = $params['contribution_id'];
                     while ($contributionBAO->fetch()) {
                         $softParams['currency'] = $contributionBAO->currency;
                         $softParams['amount'] = $contributionBAO->total_amount;
                     }
                     CRM_Contribute_BAO_ContributionSoft::add($softParams);
                 }
             }
             //carry updated membership object.
             $membership = new CRM_Member_DAO_Membership();
             $membership->id = $this->_id;
             $membership->find(TRUE);
             $cancelled = TRUE;
             if ($membership->end_date) {
                 //display end date w/ status message.
                 $endDate = $membership->end_date;
                 if (!in_array($membership->status_id, array(array_search('Cancelled', CRM_Member_PseudoConstant::membershipStatus(NULL, " name = 'Cancelled' ", 'name', FALSE, TRUE)), array_search('Expired', CRM_Member_PseudoConstant::membershipStatus())))) {
                     $cancelled = FALSE;
                 }
             }
             // suppress form values in template.
             $this->assign('cancelled', $cancelled);
             // FIX ME: need to recheck this
             // here we might updated dates, so get from object.
             foreach ($calcDates[$membership->membership_type_id] as $date => &$val) {
                 if ($membership->{$date}) {
                     $val = $membership->{$date};
                 }
             }
             $createdMemberships[] = $membership;
         } else {
             $count = 0;
             foreach ($this->_memTypeSelected as $memType) {
                 if ($count && !empty($formValues['record_contribution']) && ($relateContribution = CRM_Member_BAO_Membership::getMembershipContributionId($membership->id))) {
                     $membershipTypeValues[$memType]['relate_contribution_id'] = $relateContribution;
                 }
                 $membershipParams = array_merge($params, $membershipTypeValues[$memType]);
                 if (!empty($formValues['int_amount'])) {
                     $init_amount = array();
                     foreach ($formValues as $key => $value) {
                         if (strstr($key, 'txt-price')) {
                             $init_amount[$key] = $value;
                         }
                     }
                     $membershipParams['init_amount'] = $init_amount;
                 }
                 if (!empty($softParams)) {
                     $membershipParams['soft_credit'] = $softParams;
                 }
                 $membership = CRM_Member_BAO_Membership::create($membershipParams, $ids);
                 $params['contribution'] = CRM_Utils_Array::value('contribution', $membershipParams);
                 unset($params['lineItems']);
                 $this->_membershipIDs[] = $membership->id;
                 $createdMemberships[$memType] = $membership;
                 $count++;
             }
         }
     }
     if (!empty($lineItem[$priceSetId])) {
         $invoiceSettings = CRM_Core_BAO_Setting::getItem(CRM_Core_BAO_Setting::CONTRIBUTE_PREFERENCES_NAME, 'contribution_invoice_settings');
         $invoicing = CRM_Utils_Array::value('invoicing', $invoiceSettings);
         $taxAmount = FALSE;
         $totalTaxAmount = 0;
         foreach ($lineItem[$priceSetId] as &$priceFieldOp) {
             if (!empty($priceFieldOp['membership_type_id'])) {
                 $priceFieldOp['start_date'] = $membershipTypeValues[$priceFieldOp['membership_type_id']]['start_date'] ? CRM_Utils_Date::customFormat($membershipTypeValues[$priceFieldOp['membership_type_id']]['start_date'], '%B %E%f, %Y') : '-';
                 $priceFieldOp['end_date'] = $membershipTypeValues[$priceFieldOp['membership_type_id']]['end_date'] ? CRM_Utils_Date::customFormat($membershipTypeValues[$priceFieldOp['membership_type_id']]['end_date'], '%B %E%f, %Y') : '-';
             } else {
                 $priceFieldOp['start_date'] = $priceFieldOp['end_date'] = 'N/A';
             }
             if ($invoicing && isset($priceFieldOp['tax_amount'])) {
                 $taxAmount = TRUE;
                 $totalTaxAmount += $priceFieldOp['tax_amount'];
             }
         }
         if ($invoicing) {
             $dataArray = array();
             foreach ($lineItem[$priceSetId] as $key => $value) {
                 if (isset($value['tax_amount']) && isset($value['tax_rate'])) {
                     if (isset($dataArray[$value['tax_rate']])) {
                         $dataArray[$value['tax_rate']] = $dataArray[$value['tax_rate']] + CRM_Utils_Array::value('tax_amount', $value);
                     } else {
                         $dataArray[$value['tax_rate']] = CRM_Utils_Array::value('tax_amount', $value);
                     }
                 }
             }
             if ($taxAmount) {
                 $this->assign('totalTaxAmount', $totalTaxAmount);
                 $this->assign('taxTerm', CRM_Utils_Array::value('tax_term', $invoiceSettings));
             }
             $this->assign('dataArray', $dataArray);
         }
     }
     $this->assign('lineItem', !empty($lineItem) && !$isQuickConfig ? $lineItem : FALSE);
     $receiptSend = FALSE;
     $contributionId = CRM_Member_BAO_Membership::getMembershipContributionId($membership->id);
     $membershipIds = $this->_membershipIDs;
     if ($contributionId && !empty($membershipIds)) {
         $contributionDetails = CRM_Contribute_BAO_Contribution::getContributionDetails(CRM_Export_Form_Select::MEMBER_EXPORT, $this->_membershipIDs);
         if ($contributionDetails[$membership->id]['contribution_status'] == 'Completed') {
             $receiptSend = TRUE;
         }
     }
     if (!empty($formValues['send_receipt']) && $receiptSend) {
         $formValues['contact_id'] = $this->_contactID;
         $formValues['contribution_id'] = $contributionId;
         // send email receipt
         $mailSend = self::emailReceipt($this, $formValues, $membership);
     }
     if ($this->_action & CRM_Core_Action::UPDATE) {
         //end date can be modified by hooks, so if end date is set then use it.
         $endDate = $membership->end_date ? $membership->end_date : $endDate;
         $statusMsg = ts('Membership for %1 has been updated.', array(1 => $this->_memberDisplayName));
         if ($endDate && $endDate !== 'null') {
             $endDate = CRM_Utils_Date::customFormat($endDate);
             $statusMsg .= ' ' . ts('The membership End Date is %1.', array(1 => $endDate));
         }
         if ($receiptSend) {
             $statusMsg .= ' ' . ts('A confirmation and receipt has been sent to %1.', array(1 => $this->_contributorEmail));
         }
     } elseif ($this->_action & CRM_Core_Action::ADD) {
         // FIX ME: fix status messages
         $statusMsg = array();
         foreach ($membershipTypes as $memType => $membershipType) {
             $statusMsg[$memType] = ts('%1 membership for %2 has been added.', array(1 => $membershipType, 2 => $this->_memberDisplayName));
             $membership = $createdMemberships[$memType];
             $memEndDate = $membership->end_date ? $membership->end_date : $endDate;
             //get the end date from calculated dates.
             if (!$memEndDate && empty($params['is_recur'])) {
                 $memEndDate = CRM_Utils_Array::value('end_date', $calcDates[$memType]);
             }
             if ($memEndDate && $memEndDate !== 'null') {
                 $memEndDate = CRM_Utils_Date::customFormat($memEndDate);
                 $statusMsg[$memType] .= ' ' . ts('The new membership End Date is %1.', array(1 => $memEndDate));
             }
         }
         $statusMsg = implode('<br/>', $statusMsg);
         if ($receiptSend && !empty($mailSend)) {
             $statusMsg .= ' ' . ts('A membership confirmation and receipt has been sent to %1.', array(1 => $this->_contributorEmail));
         }
     }
     // finally set membership id if already not set
     if (!$this->_id) {
         $this->_id = $membership->id;
     }
     CRM_Core_Session::setStatus($statusMsg, ts('Complete'), 'success');
     $buttonName = $this->controller->getButtonName();
     if ($this->_context == 'standalone') {
         if ($buttonName == $this->getButtonName('upload', 'new')) {
             $session->replaceUserContext(CRM_Utils_System::url('civicrm/member/add', 'reset=1&action=add&context=standalone'));
         } else {
             $session->replaceUserContext(CRM_Utils_System::url('civicrm/contact/view', "reset=1&cid={$this->_contactID}&selectedChild=member"));
         }
     } elseif ($buttonName == $this->getButtonName('upload', 'new')) {
         $session->replaceUserContext(CRM_Utils_System::url('civicrm/contact/view/membership', "reset=1&action=add&context=membership&cid={$this->_contactID}"));
     }
 }
 /**
  * Submit function.
  *
  * This is also accessed by unit tests.
  *
  * @param array $formValues
  *
  * @return array
  */
 public function submit($formValues)
 {
     $isTest = $this->_mode == 'test' ? 1 : 0;
     $joinDate = $startDate = $endDate = NULL;
     $membershipTypes = $membership = $calcDate = array();
     $membershipType = NULL;
     $mailSend = FALSE;
     $formValues = $this->setPriceSetParameters($formValues);
     $params = $softParams = $ids = array();
     $allMemberStatus = CRM_Member_PseudoConstant::membershipStatus();
     $allContributionStatus = CRM_Contribute_PseudoConstant::contributionStatus();
     if ($this->_id) {
         $ids['membership'] = $params['id'] = $this->_id;
     }
     $ids['userId'] = CRM_Core_Session::singleton()->get('userID');
     // Set variables that we normally get from context.
     // In form mode these are set in preProcess.
     //TODO: set memberships, fixme
     $this->setContextVariables($formValues);
     $this->_memTypeSelected = self::getSelectedMemberships($this->_priceSet, $formValues);
     if (empty($formValues['financial_type_id'])) {
         $formValues['financial_type_id'] = $this->_priceSet['financial_type_id'];
     }
     $config = CRM_Core_Config::singleton();
     $this->convertDateFieldsToMySQL($formValues);
     $membershipTypeValues = array();
     foreach ($this->_memTypeSelected as $memType) {
         $membershipTypeValues[$memType]['membership_type_id'] = $memType;
     }
     //take the required membership recur values.
     if ($this->_mode && !empty($formValues['auto_renew'])) {
         $params['is_recur'] = $formValues['is_recur'] = TRUE;
         $mapping = array('frequency_interval' => 'duration_interval', 'frequency_unit' => 'duration_unit');
         $count = 0;
         foreach ($this->_memTypeSelected as $memType) {
             $recurMembershipTypeValues = CRM_Utils_Array::value($memType, $this->_recurMembershipTypes, array());
             foreach ($mapping as $mapVal => $mapParam) {
                 $membershipTypeValues[$memType][$mapVal] = CRM_Utils_Array::value($mapParam, $recurMembershipTypeValues);
                 if (!$count) {
                     $formValues[$mapVal] = CRM_Utils_Array::value($mapParam, $recurMembershipTypeValues);
                 }
             }
             $count++;
         }
     }
     $isQuickConfig = $this->_priceSet['is_quick_config'];
     $termsByType = array();
     $lineItem = array($this->_priceSetId => array());
     CRM_Price_BAO_PriceSet::processAmount($this->_priceSet['fields'], $formValues, $lineItem[$this->_priceSetId]);
     if (CRM_Utils_Array::value('tax_amount', $formValues)) {
         $params['tax_amount'] = $formValues['tax_amount'];
     }
     $params['total_amount'] = CRM_Utils_Array::value('amount', $formValues);
     $submittedFinancialType = CRM_Utils_Array::value('financial_type_id', $formValues);
     if (!empty($lineItem[$this->_priceSetId])) {
         foreach ($lineItem[$this->_priceSetId] as &$li) {
             if (!empty($li['membership_type_id'])) {
                 if (!empty($li['membership_num_terms'])) {
                     $termsByType[$li['membership_type_id']] = $li['membership_num_terms'];
                 }
             }
             ///CRM-11529 for quick config backoffice transactions
             //when financial_type_id is passed in form, update the
             //lineitems with the financial type selected in form
             if ($isQuickConfig && $submittedFinancialType) {
                 $li['financial_type_id'] = $submittedFinancialType;
             }
         }
     }
     $this->storeContactFields($formValues);
     $params['contact_id'] = $this->_contactID;
     $fields = array('status_id', 'source', 'is_override', 'campaign_id');
     foreach ($fields as $f) {
         $params[$f] = CRM_Utils_Array::value($f, $formValues);
     }
     // fix for CRM-3724
     // when is_override false ignore is_admin statuses during membership
     // status calculation. similarly we did fix for import in CRM-3570.
     if (empty($params['is_override'])) {
         $params['exclude_is_admin'] = TRUE;
     }
     // process date params to mysql date format.
     $dateTypes = array('join_date' => 'joinDate', 'start_date' => 'startDate', 'end_date' => 'endDate');
     foreach ($dateTypes as $dateField => $dateVariable) {
         ${$dateVariable} = CRM_Utils_Date::processDate($formValues[$dateField]);
     }
     $memTypeNumTerms = empty($termsByType) ? CRM_Utils_Array::value('num_terms', $formValues) : NULL;
     $calcDates = array();
     foreach ($this->_memTypeSelected as $memType) {
         if (empty($memTypeNumTerms)) {
             $memTypeNumTerms = CRM_Utils_Array::value($memType, $termsByType, 1);
         }
         $calcDates[$memType] = CRM_Member_BAO_MembershipType::getDatesForMembershipType($memType, $joinDate, $startDate, $endDate, $memTypeNumTerms);
     }
     foreach ($calcDates as $memType => $calcDate) {
         foreach (array_keys($dateTypes) as $d) {
             //first give priority to form values then calDates.
             $date = CRM_Utils_Array::value($d, $formValues);
             if (!$date) {
                 $date = CRM_Utils_Array::value($d, $calcDate);
             }
             $membershipTypeValues[$memType][$d] = CRM_Utils_Date::processDate($date);
         }
     }
     // max related memberships - take from form or inherit from membership type
     foreach ($this->_memTypeSelected as $memType) {
         if (array_key_exists('max_related', $formValues)) {
             $membershipTypeValues[$memType]['max_related'] = CRM_Utils_Array::value('max_related', $formValues);
         }
         $membershipTypeValues[$memType]['custom'] = CRM_Core_BAO_CustomField::postProcess($formValues, $this->_id, 'Membership');
         $membershipTypes[$memType] = CRM_Core_DAO::getFieldValue('CRM_Member_DAO_MembershipType', $memType);
     }
     $membershipType = implode(', ', $membershipTypes);
     // Retrieve the name and email of the current user - this will be the FROM for the receipt email
     list($userName) = CRM_Contact_BAO_Contact_Location::getEmailDetails($ids['userId']);
     //CRM-13981, allow different person as a soft-contributor of chosen type
     if ($this->_contributorContactID != $this->_contactID) {
         $params['contribution_contact_id'] = $this->_contributorContactID;
         if (!empty($formValues['soft_credit_type_id'])) {
             $softParams['soft_credit_type_id'] = $formValues['soft_credit_type_id'];
             $softParams['contact_id'] = $this->_contactID;
         }
     }
     if (!empty($formValues['record_contribution'])) {
         $recordContribution = array('total_amount', 'financial_type_id', 'payment_instrument_id', 'trxn_id', 'contribution_status_id', 'check_number', 'campaign_id', 'receive_date');
         foreach ($recordContribution as $f) {
             $params[$f] = CRM_Utils_Array::value($f, $formValues);
         }
         if (!$this->_onlinePendingContributionId) {
             if (empty($formValues['source'])) {
                 $params['contribution_source'] = ts('%1 Membership: Offline signup (by %2)', array(1 => $membershipType, 2 => $userName));
             } else {
                 $params['contribution_source'] = $formValues['source'];
             }
         }
         if (empty($params['is_override']) && CRM_Utils_Array::value('contribution_status_id', $params) == array_search('Pending', CRM_Contribute_PseudoConstant::contributionStatus(NULL, 'name'))) {
             $params['status_id'] = array_search('Pending', $allMemberStatus);
             $params['skipStatusCal'] = TRUE;
             $params['is_pay_later'] = 1;
             $this->assign('is_pay_later', 1);
         }
         if (!empty($formValues['send_receipt'])) {
             $params['receipt_date'] = CRM_Utils_Array::value('receive_date', $formValues);
         }
         //insert financial type name in receipt.
         $formValues['contributionType_name'] = CRM_Core_DAO::getFieldValue('CRM_Financial_DAO_FinancialType', $formValues['financial_type_id']);
     }
     // process line items, until no previous line items.
     if (!empty($lineItem)) {
         $params['lineItems'] = $lineItem;
         $params['processPriceSet'] = TRUE;
     }
     $createdMemberships = array();
     if ($this->_mode) {
         $params['total_amount'] = CRM_Utils_Array::value('total_amount', $formValues, 0);
         if (!$isQuickConfig) {
             $params['financial_type_id'] = CRM_Core_DAO::getFieldValue('CRM_Price_DAO_PriceSet', $this->_priceSetId, 'financial_type_id');
         } else {
             $params['financial_type_id'] = CRM_Utils_Array::value('financial_type_id', $formValues);
         }
         $this->_paymentProcessor = CRM_Financial_BAO_PaymentProcessor::getPayment($formValues['payment_processor_id'], $this->_mode);
         //get the payment processor id as per mode.
         $params['payment_processor_id'] = $formValues['payment_processor_id'] = $this->_paymentProcessor['id'];
         $now = date('YmdHis');
         $fields = array();
         // set email for primary location.
         $fields['email-Primary'] = 1;
         $formValues['email-5'] = $formValues['email-Primary'] = $this->_memberEmail;
         $params['register_date'] = $now;
         // now set the values for the billing location.
         foreach ($this->_fields as $name => $dontCare) {
             $fields[$name] = 1;
         }
         // also add location name to the array
         $formValues["address_name-{$this->_bltID}"] = CRM_Utils_Array::value('billing_first_name', $formValues) . ' ' . CRM_Utils_Array::value('billing_middle_name', $formValues) . ' ' . CRM_Utils_Array::value('billing_last_name', $formValues);
         $formValues["address_name-{$this->_bltID}"] = trim($formValues["address_name-{$this->_bltID}"]);
         $fields["address_name-{$this->_bltID}"] = 1;
         //ensure we don't over-write the payer's email with the member's email
         if ($this->_contributorContactID == $this->_contactID) {
             $fields["email-{$this->_bltID}"] = 1;
         }
         $nameFields = array('first_name', 'middle_name', 'last_name');
         foreach ($nameFields as $name) {
             $fields[$name] = 1;
             if (array_key_exists("billing_{$name}", $formValues)) {
                 $formValues[$name] = $formValues["billing_{$name}"];
                 $formValues['preserveDBName'] = TRUE;
             }
         }
         if ($this->_contributorContactID == $this->_contactID) {
             //see CRM-12869 for discussion of why we don't do this for separate payee payments
             CRM_Contact_BAO_Contact::createProfileContact($formValues, $fields, $this->_contributorContactID, NULL, NULL, CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_Contact', $this->_contactID, 'contact_type'));
         }
         // add all the additional payment params we need
         $formValues["state_province-{$this->_bltID}"] = $formValues["billing_state_province-{$this->_bltID}"] = CRM_Core_PseudoConstant::stateProvinceAbbreviation($formValues["billing_state_province_id-{$this->_bltID}"]);
         $formValues["country-{$this->_bltID}"] = $formValues["billing_country-{$this->_bltID}"] = CRM_Core_PseudoConstant::countryIsoCode($formValues["billing_country_id-{$this->_bltID}"]);
         $formValues['year'] = CRM_Core_Payment_Form::getCreditCardExpirationYear($formValues);
         $formValues['month'] = CRM_Core_Payment_Form::getCreditCardExpirationMonth($formValues);
         $formValues['ip_address'] = CRM_Utils_System::ipAddress();
         $formValues['amount'] = $params['total_amount'];
         $formValues['currencyID'] = $config->defaultCurrency;
         $formValues['description'] = ts("Contribution submitted by a staff person using member's credit card for signup");
         $formValues['invoiceID'] = md5(uniqid(rand(), TRUE));
         $formValues['financial_type_id'] = $params['financial_type_id'];
         // at this point we've created a contact and stored its address etc
         // all the payment processors expect the name and address to be in the
         // so we copy stuff over to first_name etc.
         $paymentParams = $formValues;
         $paymentParams['contactID'] = $this->_contributorContactID;
         //CRM-10377 if payment is by an alternate contact then we need to set that person
         // as the contact in the payment params
         if ($this->_contributorContactID != $this->_contactID) {
             if (!empty($formValues['soft_credit_type_id'])) {
                 $softParams['contact_id'] = $params['contact_id'];
                 $softParams['soft_credit_type_id'] = $formValues['soft_credit_type_id'];
             }
         }
         if (!empty($formValues['send_receipt'])) {
             $paymentParams['email'] = $this->_contributorEmail;
         }
         CRM_Core_Payment_Form::mapParams($this->_bltID, $formValues, $paymentParams, TRUE);
         // CRM-7137 -for recurring membership,
         // we do need contribution and recurring records.
         $result = NULL;
         if (!empty($paymentParams['is_recur'])) {
             $financialType = new CRM_Financial_DAO_FinancialType();
             $financialType->id = $params['financial_type_id'];
             $financialType->find(TRUE);
             $this->_params = $formValues;
             $contribution = CRM_Contribute_Form_Contribution_Confirm::processFormContribution($this, $paymentParams, NULL, array('contact_id' => $this->_contributorContactID, 'line_item' => $lineItem, 'is_test' => $isTest, 'campaign_id' => CRM_Utils_Array::value('campaign_id', $paymentParams), 'contribution_page_id' => CRM_Utils_Array::value('contribution_page_id', $formValues), 'source' => CRM_Utils_Array::value('source', $paymentParams, CRM_Utils_Array::value('description', $paymentParams)), 'thankyou_date' => CRM_Utils_Array::value('thankyou_date', $paymentParams), 'payment_instrument_id' => $this->_paymentProcessor['payment_instrument_id']), $financialType, TRUE, FALSE, $this->_bltID);
             //create new soft-credit record, CRM-13981
             if ($softParams) {
                 $softParams['contribution_id'] = $contribution->id;
                 $softParams['currency'] = $contribution->currency;
                 $softParams['amount'] = $contribution->total_amount;
                 CRM_Contribute_BAO_ContributionSoft::add($softParams);
             }
             $paymentParams['contactID'] = $this->_contactID;
             $paymentParams['contributionID'] = $contribution->id;
             $paymentParams['contributionTypeID'] = $contribution->financial_type_id;
             $paymentParams['contributionPageID'] = $contribution->contribution_page_id;
             $paymentParams['contributionRecurID'] = $contribution->contribution_recur_id;
             $ids['contribution'] = $contribution->id;
             $params['contribution_recur_id'] = $paymentParams['contributionRecurID'];
         }
         if ($params['total_amount'] > 0.0) {
             $payment = $this->_paymentProcessor['object'];
             try {
                 $result = $payment->doPayment($paymentParams);
                 $formValues = array_merge($formValues, $result);
                 // Assign amount to template if payment was successful.
                 $this->assign('amount', $params['total_amount']);
             } catch (PaymentProcessorException $e) {
                 if (!empty($paymentParams['contributionID'])) {
                     CRM_Contribute_BAO_Contribution::failPayment($paymentParams['contributionID'], $this->_contactID, $e->getMessage());
                 }
                 if (!empty($paymentParams['contributionRecurID'])) {
                     CRM_Contribute_BAO_ContributionRecur::deleteRecurContribution($paymentParams['contributionRecurID']);
                 }
                 CRM_Core_Error::displaySessionError($result);
                 CRM_Utils_System::redirect(CRM_Utils_System::url('civicrm/contact/view/membership', "reset=1&action=add&cid={$this->_contactID}&context=&mode={$this->_mode}"));
             }
         }
         if ($formValues['payment_status_id'] != array_search('Completed', $allContributionStatus)) {
             $params['status_id'] = array_search('Pending', $allMemberStatus);
             $params['skipStatusCal'] = TRUE;
             // unset send-receipt option, since receipt will be sent when ipn is received.
             unset($formValues['send_receipt'], $formValues['send_receipt']);
             //as membership is pending set dates to null.
             $memberDates = array('join_date' => 'joinDate', 'start_date' => 'startDate', 'end_date' => 'endDate');
             foreach ($memberDates as $dv) {
                 ${$dv} = NULL;
                 foreach ($this->_memTypeSelected as $memType) {
                     $membershipTypeValues[$memType][$dv] = NULL;
                 }
             }
         }
         $params['receive_date'] = $now;
         $params['invoice_id'] = $formValues['invoiceID'];
         $params['contribution_source'] = ts('%1 Membership Signup: Credit card or direct debit (by %2)', array(1 => $membershipType, 2 => $userName));
         $params['source'] = $formValues['source'] ? $formValues['source'] : $params['contribution_source'];
         $params['trxn_id'] = CRM_Utils_Array::value('trxn_id', $result);
         $params['payment_instrument_id'] = 1;
         $params['is_test'] = $this->_mode == 'live' ? 0 : 1;
         if (!empty($formValues['send_receipt'])) {
             $params['receipt_date'] = $now;
         } else {
             $params['receipt_date'] = NULL;
         }
         $this->set('params', $formValues);
         $this->assign('trxn_id', CRM_Utils_Array::value('trxn_id', $result));
         $this->assign('receive_date', CRM_Utils_Date::mysqlToIso($params['receive_date']));
         // required for creating membership for related contacts
         $params['action'] = $this->_action;
         //create membership record.
         $count = 0;
         foreach ($this->_memTypeSelected as $memType) {
             if ($count && ($relateContribution = CRM_Member_BAO_Membership::getMembershipContributionId($membership->id))) {
                 $membershipTypeValues[$memType]['relate_contribution_id'] = $relateContribution;
             }
             $membershipParams = array_merge($membershipTypeValues[$memType], $params);
             //CRM-15366
             if (!empty($softParams) && empty($paymentParams['is_recur'])) {
                 $membershipParams['soft_credit'] = $softParams;
             }
             // This is required to trigger the recording of the membership contribution in the
             // CRM_Member_BAO_Membership::Create function.
             // @todo stop setting this & 'teach' the create function to respond to something
             // appropriate as part of our 2-step always create the pending contribution & then finally add the payment
             // process -
             // @see http://wiki.civicrm.org/confluence/pages/viewpage.action?pageId=261062657#Payments&AccountsRoadmap-Movetowardsalwaysusinga2-steppaymentprocess
             $membershipParams['contribution_status_id'] = CRM_Utils_Array::value('payment_status_id', $result);
             if (!empty($paymentParams['is_recur'])) {
                 // The earlier process created the line items (although we want to get rid of the earlier one in favour
                 // of a single path!
                 unset($membershipParams['lineItems']);
             }
             $membership = CRM_Member_BAO_Membership::create($membershipParams, $ids);
             $params['contribution'] = CRM_Utils_Array::value('contribution', $membershipParams);
             unset($params['lineItems']);
             $this->_membershipIDs[] = $membership->id;
             $createdMemberships[$memType] = $membership;
             $count++;
         }
     } else {
         $params['action'] = $this->_action;
         if ($this->_onlinePendingContributionId && !empty($formValues['record_contribution'])) {
             // update membership as well as contribution object, CRM-4395
             $params['contribution_id'] = $this->_onlinePendingContributionId;
             $params['componentId'] = $params['id'];
             $params['componentName'] = 'contribute';
             $result = CRM_Contribute_BAO_Contribution::transitionComponents($params, TRUE);
             if (!empty($result) && !empty($params['contribution_id'])) {
                 $lineItem = array();
                 $lineItems = CRM_Price_BAO_LineItem::getLineItems($params['contribution_id'], 'contribution', NULL, TRUE, TRUE);
                 $itemId = key($lineItems);
                 $priceSetId = CRM_Core_DAO::getFieldValue('CRM_Price_DAO_PriceField', $lineItems[$itemId]['price_field_id'], 'price_set_id');
                 $lineItems[$itemId]['unit_price'] = $params['total_amount'];
                 $lineItems[$itemId]['line_total'] = $params['total_amount'];
                 $lineItems[$itemId]['id'] = $itemId;
                 $lineItem[$priceSetId] = $lineItems;
                 $contributionBAO = new CRM_Contribute_BAO_Contribution();
                 $contributionBAO->id = $params['contribution_id'];
                 $contributionBAO->contact_id = $params['contact_id'];
                 $contributionBAO->find();
                 CRM_Price_BAO_LineItem::processPriceSet($params['contribution_id'], $lineItem, $contributionBAO, 'civicrm_membership');
                 //create new soft-credit record, CRM-13981
                 if ($softParams) {
                     $softParams['contribution_id'] = $params['contribution_id'];
                     while ($contributionBAO->fetch()) {
                         $softParams['currency'] = $contributionBAO->currency;
                         $softParams['amount'] = $contributionBAO->total_amount;
                     }
                     CRM_Contribute_BAO_ContributionSoft::add($softParams);
                 }
             }
             //carry updated membership object.
             $membership = new CRM_Member_DAO_Membership();
             $membership->id = $this->_id;
             $membership->find(TRUE);
             $cancelled = TRUE;
             if ($membership->end_date) {
                 //display end date w/ status message.
                 $endDate = $membership->end_date;
                 if (!in_array($membership->status_id, array(array_search('Cancelled', CRM_Member_PseudoConstant::membershipStatus(NULL, " name = 'Cancelled' ", 'name', FALSE, TRUE)), array_search('Expired', CRM_Member_PseudoConstant::membershipStatus())))) {
                     $cancelled = FALSE;
                 }
             }
             // suppress form values in template.
             $this->assign('cancelled', $cancelled);
             $createdMemberships[] = $membership;
         } else {
             $count = 0;
             foreach ($this->_memTypeSelected as $memType) {
                 if ($count && !empty($formValues['record_contribution']) && ($relateContribution = CRM_Member_BAO_Membership::getMembershipContributionId($membership->id))) {
                     $membershipTypeValues[$memType]['relate_contribution_id'] = $relateContribution;
                 }
                 $membershipParams = array_merge($params, $membershipTypeValues[$memType]);
                 if (!empty($formValues['int_amount'])) {
                     $init_amount = array();
                     foreach ($formValues as $key => $value) {
                         if (strstr($key, 'txt-price')) {
                             $init_amount[$key] = $value;
                         }
                     }
                     $membershipParams['init_amount'] = $init_amount;
                 }
                 if (!empty($softParams)) {
                     $membershipParams['soft_credit'] = $softParams;
                 }
                 $membership = CRM_Member_BAO_Membership::create($membershipParams, $ids);
                 $params['contribution'] = CRM_Utils_Array::value('contribution', $membershipParams);
                 unset($params['lineItems']);
                 $this->_membershipIDs[] = $membership->id;
                 $createdMemberships[$memType] = $membership;
                 $count++;
             }
         }
     }
     if (!empty($lineItem[$this->_priceSetId])) {
         $invoiceSettings = CRM_Core_BAO_Setting::getItem(CRM_Core_BAO_Setting::CONTRIBUTE_PREFERENCES_NAME, 'contribution_invoice_settings');
         $invoicing = CRM_Utils_Array::value('invoicing', $invoiceSettings);
         $taxAmount = FALSE;
         $totalTaxAmount = 0;
         foreach ($lineItem[$this->_priceSetId] as &$priceFieldOp) {
             if (!empty($priceFieldOp['membership_type_id'])) {
                 $priceFieldOp['start_date'] = $membershipTypeValues[$priceFieldOp['membership_type_id']]['start_date'] ? CRM_Utils_Date::customFormat($membershipTypeValues[$priceFieldOp['membership_type_id']]['start_date'], '%B %E%f, %Y') : '-';
                 $priceFieldOp['end_date'] = $membershipTypeValues[$priceFieldOp['membership_type_id']]['end_date'] ? CRM_Utils_Date::customFormat($membershipTypeValues[$priceFieldOp['membership_type_id']]['end_date'], '%B %E%f, %Y') : '-';
             } else {
                 $priceFieldOp['start_date'] = $priceFieldOp['end_date'] = 'N/A';
             }
             if ($invoicing && isset($priceFieldOp['tax_amount'])) {
                 $taxAmount = TRUE;
                 $totalTaxAmount += $priceFieldOp['tax_amount'];
             }
         }
         if ($invoicing) {
             $dataArray = array();
             foreach ($lineItem[$this->_priceSetId] as $key => $value) {
                 if (isset($value['tax_amount']) && isset($value['tax_rate'])) {
                     if (isset($dataArray[$value['tax_rate']])) {
                         $dataArray[$value['tax_rate']] = $dataArray[$value['tax_rate']] + CRM_Utils_Array::value('tax_amount', $value);
                     } else {
                         $dataArray[$value['tax_rate']] = CRM_Utils_Array::value('tax_amount', $value);
                     }
                 }
             }
             if ($taxAmount) {
                 $this->assign('totalTaxAmount', $totalTaxAmount);
                 $this->assign('taxTerm', CRM_Utils_Array::value('tax_term', $invoiceSettings));
             }
             $this->assign('dataArray', $dataArray);
         }
     }
     $this->assign('lineItem', !empty($lineItem) && !$isQuickConfig ? $lineItem : FALSE);
     $receiptSend = FALSE;
     $contributionId = CRM_Member_BAO_Membership::getMembershipContributionId($membership->id);
     $membershipIds = $this->_membershipIDs;
     if ($contributionId && !empty($membershipIds)) {
         $contributionDetails = CRM_Contribute_BAO_Contribution::getContributionDetails(CRM_Export_Form_Select::MEMBER_EXPORT, $this->_membershipIDs);
         if ($contributionDetails[$membership->id]['contribution_status'] == 'Completed') {
             $receiptSend = TRUE;
         }
     }
     if (!empty($formValues['send_receipt']) && $receiptSend) {
         $formValues['contact_id'] = $this->_contactID;
         $formValues['contribution_id'] = $contributionId;
         // We really don't need a distinct receipt_text_signup vs receipt_text_renewal as they are
         // handled in the receipt. But by setting one we avoid breaking templates for now
         // although at some point we should switch in the templates.
         $formValues['receipt_text_signup'] = $formValues['receipt_text'];
         // send email receipt
         $mailSend = self::emailReceipt($this, $formValues, $membership);
     }
     // finally set membership id if already not set
     if (!$this->_id) {
         $this->_id = $membership->id;
     }
     $isRecur = CRM_Utils_Array::value('is_recur', $params);
     $this->setStatusMessage($membership, $endDate, $receiptSend, $membershipTypes, $createdMemberships, $isRecur, $calcDates, $mailSend);
     return $createdMemberships;
 }
 /**
  * Given the list of params in the params array, fetch the object
  * and store the values in the values array
  *
  * @param array $params input parameters to find object
  * @param array $values output values of the object
  * @param array $ids    the array that holds all the db ids
  *
  * @return CRM_Contribute_BAO_Contribution|null the found object or null
  * @access public
  * @static
  */
 static function &getValues(&$params, &$values, &$ids)
 {
     if (empty($params)) {
         return null;
     }
     $contribution = new CRM_Contribute_BAO_Contribution();
     $contribution->copyValues($params);
     if ($contribution->find(true)) {
         $ids['contribution'] = $contribution->id;
         CRM_Core_DAO::storeValues($contribution, $values);
         return $contribution;
     }
     return null;
 }
/**
 * Complete an existing (pending) transaction.
 *
 * This will update related entities (participant, membership, pledge etc)
 * and take any complete actions from the contribution page (e.g. send receipt).
 *
 * @todo - most of this should live in the BAO layer but as we want it to be an addition
 * to 4.3 which is already stable we should add it to the api layer & re-factor into the BAO layer later
 *
 * @param array $params
 *   Input parameters.
 *
 * @throws API_Exception
 *   Api result array.
 */
function civicrm_api3_contribution_repeattransaction(&$params)
{
    $input = $ids = array();
    $contribution = new CRM_Contribute_BAO_Contribution();
    $contribution->id = $params['original_contribution_id'];
    if (!$contribution->find(TRUE)) {
        throw new API_Exception('A valid original contribution ID is required', 'invalid_data');
    }
    $original_contribution = clone $contribution;
    try {
        if (!$contribution->loadRelatedObjects($input, $ids, TRUE)) {
            throw new API_Exception('failed to load related objects');
        }
        unset($contribution->id, $contribution->receive_date, $contribution->invoice_id);
        $contribution->contribution_status_id = $params['contribution_status_id'];
        $contribution->receive_date = $params['receive_date'];
        $passThroughParams = array('trxn_id', 'total_amount', 'campaign_id', 'fee_amount');
        $input = array_intersect_key($params, array_fill_keys($passThroughParams, NULL));
        $params = _ipn_process_transaction($params, $contribution, $input, $ids, $original_contribution);
    } catch (Exception $e) {
        throw new API_Exception('failed to load related objects' . $e->getMessage() . "\n" . $e->getTraceAsString());
    }
}
 /**
  * Process recurring contributions
  * @param array $input
  * @param array $ids
  * @param array $objects
  * @param boolean $first
  * @return void|boolean
  */
 function recur(&$input, &$ids, &$objects, $first)
 {
     if (!isset($input['txnType'])) {
         CRM_Core_Error::debug_log_message("Could not find txn_type in input request");
         echo "Failure: Invalid parameters<p>";
         return FALSE;
     }
     if ($input['txnType'] == 'recurring_payment' && $input['paymentStatus'] != 'Completed') {
         CRM_Core_Error::debug_log_message("Ignore all IPN payments that are not completed");
         echo "Failure: Invalid parameters<p>";
         return FALSE;
     }
     $recur =& $objects['contributionRecur'];
     // make sure the invoice ids match
     // make sure the invoice is valid and matches what we have in
     // the contribution record
     if ($recur->invoice_id != $input['invoice']) {
         CRM_Core_Error::debug_log_message("Invoice values dont match between database and IPN request recur is " . $recur->invoice_id . " input is " . $input['invoice']);
         echo "Failure: Invoice values dont match between database and IPN request recur is " . $recur->invoice_id . " input is " . $input['invoice'];
         return FALSE;
     }
     $now = date('YmdHis');
     // fix dates that already exist
     $dates = array('create', 'start', 'end', 'cancel', 'modified');
     foreach ($dates as $date) {
         $name = "{$date}_date";
         if ($recur->{$name}) {
             $recur->{$name} = CRM_Utils_Date::isoToMysql($recur->{$name});
         }
     }
     $sendNotification = FALSE;
     $subscriptionPaymentStatus = NULL;
     //List of Transaction Type
     /*
      recurring_payment_profile_created          RP Profile Created
      recurring_payment           RP Sucessful Payment
      recurring_payment_failed                               RP Failed Payment
      recurring_payment_profile_cancel           RP Profile Cancelled
      recurring_payment_expired         RP Profile Expired
      recurring_payment_skipped        RP Profile Skipped
      recurring_payment_outstanding_payment      RP Sucessful Outstanding Payment
      recurring_payment_outstanding_payment_failed          RP Failed Outstanding Payment
      recurring_payment_suspended        RP Profile Suspended
      recurring_payment_suspended_due_to_max_failed_payment  RP Profile Suspended due to Max Failed Payment
     */
     //set transaction type
     $txnType = $this->retrieve('txn_type', 'String');
     //Changes for paypal pro recurring payment
     $contributionStatuses = civicrm_api3('contribution', 'getoptions', array('field' => 'contribution_status_id'));
     $contributionStatuses = $contributionStatuses['values'];
     switch ($txnType) {
         case 'recurring_payment_profile_created':
             if (in_array($recur->contribution_status_id, array(array_search('Pending', $contributionStatuses), array_search('In Progress', $contributionStatuses))) && !empty($recur->processor_id)) {
                 echo "already handled";
                 return;
             }
             $recur->create_date = $now;
             $recur->contribution_status_id = 2;
             $recur->processor_id = $this->retrieve('recurring_payment_id', 'String');
             $recur->trxn_id = $recur->processor_id;
             $subscriptionPaymentStatus = CRM_Core_Payment::RECURRING_PAYMENT_START;
             $sendNotification = TRUE;
             break;
         case 'recurring_payment':
             if ($first) {
                 $recur->start_date = $now;
             } else {
                 $recur->modified_date = $now;
             }
             //contribution installment is completed
             if ($this->retrieve('profile_status', 'String') == 'Expired') {
                 if (!empty($recur->end_date)) {
                     echo "already handled";
                     return;
                 }
                 $recur->contribution_status_id = 1;
                 $recur->end_date = $now;
                 $sendNotification = TRUE;
                 $subscriptionPaymentStatus = CRM_Core_Payment::RECURRING_PAYMENT_END;
             }
             // make sure the contribution status is not done
             // since order of ipn's is unknown
             if ($recur->contribution_status_id != 1) {
                 $recur->contribution_status_id = 5;
             }
             break;
     }
     $recur->save();
     if ($sendNotification) {
         $autoRenewMembership = FALSE;
         if ($recur->id && isset($ids['membership']) && $ids['membership']) {
             $autoRenewMembership = TRUE;
         }
         //send recurring Notification email for user
         CRM_Contribute_BAO_ContributionPage::recurringNotify($subscriptionPaymentStatus, $ids['contact'], $ids['contributionPage'], $recur, $autoRenewMembership);
     }
     if ($txnType != 'recurring_payment') {
         return;
     }
     if (!$first) {
         //check if this contribution transaction is already processed
         //if not create a contribution and then get it processed
         $contribution = new CRM_Contribute_BAO_Contribution();
         $contribution->trxn_id = $input['trxn_id'];
         if ($contribution->trxn_id && $contribution->find()) {
             CRM_Core_Error::debug_log_message("returning since contribution has already been handled");
             echo "Success: Contribution has already been handled<p>";
             return TRUE;
         }
         $contribution->contact_id = $recur->contact_id;
         $contribution->financial_type_id = $objects['contributionType']->id;
         $contribution->contribution_page_id = $ids['contributionPage'];
         $contribution->contribution_recur_id = $ids['contributionRecur'];
         $contribution->currency = $objects['contribution']->currency;
         $contribution->payment_instrument_id = $objects['contribution']->payment_instrument_id;
         $contribution->amount_level = $objects['contribution']->amount_level;
         $contribution->campaign_id = $objects['contribution']->campaign_id;
         $objects['contribution'] =& $contribution;
     }
     // CRM-13737 - am not aware of any reason why payment_date would not be set - this if is a belt & braces
     $objects['contribution']->receive_date = !empty($input['payment_date']) ? date('YmdHis', strtotime($input['payment_date'])) : $now;
     $this->single($input, $ids, $objects, TRUE, $first);
 }
/**
 * This function ensures that we have the right input contribution parameters
 *
 * We also need to make sure we run all the form rules on the params list
 * to ensure that the params are valid
 *
 * @param array  $params       Associative array of property name/value
 *                             pairs to insert in new contribution.
 *
 * @return bool|CRM_Utils_Error
 * @access private
 */
function _civicrm_contribute_check_params(&$params)
{
    static $required = array('contact_id' => NULL, 'total_amount' => NULL, 'contribution_type_id' => 'contribution_type');
    // params should be an array
    if (!is_array($params)) {
        return civicrm_create_error(ts('Input parameters is not an array'));
    }
    // cannot create a contribution with empty params
    if (empty($params)) {
        return civicrm_create_error('Input Parameters empty');
    }
    $valid = TRUE;
    $error = '';
    // check params for contribution id during update
    if (CRM_Utils_Array::value('id', $params)) {
        require_once 'CRM/Contribute/BAO/Contribution.php';
        $contributor = new CRM_Contribute_BAO_Contribution();
        $contributor->id = $params['id'];
        if (!$contributor->find(TRUE)) {
            return civicrm_create_error(ts('Contribution id is not valid'));
        }
        // do not check other field during update
        return array();
    }
    foreach ($required as $field => $eitherField) {
        if (!CRM_Utils_Array::value($field, $params)) {
            if ($eitherField && CRM_Utils_Array::value($eitherField, $params)) {
                continue;
            }
            $valid = FALSE;
            $error .= $field;
            break;
        }
    }
    if (!$valid) {
        return civicrm_create_error("Required fields not found for contribution {$error}");
    }
    return array();
}