function completeTransaction(&$input, &$ids, &$objects, &$transaction, $recur = FALSE)
 {
     $contribution =& $objects['contribution'];
     $primaryContributionID = isset($contribution->id) ? $contribution->id : $objects['first_contribution']->id;
     $memberships =& $objects['membership'];
     if (is_numeric($memberships)) {
         $memberships = array($objects['membership']);
     }
     $participant =& $objects['participant'];
     $event =& $objects['event'];
     $changeToday = CRM_Utils_Array::value('trxn_date', $input, self::$_now);
     $recurContrib =& $objects['contributionRecur'];
     $values = array();
     if (isset($input['is_email_receipt'])) {
         $values['is_email_receipt'] = $input['is_email_receipt'];
     }
     $source = NULL;
     if ($input['component'] == 'contribute') {
         if ($contribution->contribution_page_id) {
             CRM_Contribute_BAO_ContributionPage::setValues($contribution->contribution_page_id, $values);
             $source = ts('Online Contribution') . ': ' . $values['title'];
         } elseif ($recurContrib && $recurContrib->id) {
             $contribution->contribution_page_id = NULL;
             $values['amount'] = $recurContrib->amount;
             $values['financial_type_id'] = $objects['contributionType']->id;
             $values['title'] = $source = ts('Offline Recurring Contribution');
             $domainValues = CRM_Core_BAO_Domain::getNameAndEmail();
             $values['receipt_from_name'] = $domainValues[0];
             $values['receipt_from_email'] = $domainValues[1];
         }
         if ($recurContrib && $recurContrib->id && !isset($input['is_email_receipt'])) {
             //CRM-13273 - is_email_receipt setting on recurring contribution should take precedence over contribution page setting
             // but CRM-16124 if $input['is_email_receipt'] is set then that should not be overridden.
             $values['is_email_receipt'] = $recurContrib->is_email_receipt;
         }
         $contribution->source = $source;
         if (CRM_Utils_Array::value('is_email_receipt', $values)) {
             $contribution->receipt_date = self::$_now;
         }
         if (!empty($memberships)) {
             $membershipsUpdate = array();
             foreach ($memberships as $membershipTypeIdKey => $membership) {
                 if ($membership) {
                     $format = '%Y%m%d';
                     $currentMembership = CRM_Member_BAO_Membership::getContactMembership($membership->contact_id, $membership->membership_type_id, $membership->is_test, $membership->id);
                     // CRM-8141 update the membership type with the value recorded in log when membership created/renewed
                     // this picks up membership type changes during renewals
                     $sql = "\nSELECT    membership_type_id\nFROM      civicrm_membership_log\nWHERE     membership_id={$membership->id}\nORDER BY  id DESC\nLIMIT 1;";
                     $dao = new CRM_Core_DAO();
                     $dao->query($sql);
                     if ($dao->fetch()) {
                         if (!empty($dao->membership_type_id)) {
                             $membership->membership_type_id = $dao->membership_type_id;
                             $membership->save();
                         }
                         // else fall back to using current membership type
                     }
                     // else fall back to using current membership type
                     $dao->free();
                     $num_terms = $contribution->getNumTermsByContributionAndMembershipType($membership->membership_type_id, $primaryContributionID);
                     if ($currentMembership) {
                         /*
                          * Fixed FOR CRM-4433
                          * In BAO/Membership.php(renewMembership function), we skip the extend membership date and status
                          * when Contribution mode is notify and membership is for renewal )
                          */
                         CRM_Member_BAO_Membership::fixMembershipStatusBeforeRenew($currentMembership, $changeToday);
                         // @todo - we should pass membership_type_id instead of null here but not
                         // adding as not sure of testing
                         $dates = CRM_Member_BAO_MembershipType::getRenewalDatesForMembershipType($membership->id, $changeToday, NULL, $num_terms);
                         $dates['join_date'] = CRM_Utils_Date::customFormat($currentMembership['join_date'], $format);
                     } else {
                         $dates = CRM_Member_BAO_MembershipType::getDatesForMembershipType($membership->membership_type_id, NULL, NULL, NULL, $num_terms);
                     }
                     //get the status for membership.
                     $calcStatus = CRM_Member_BAO_MembershipStatus::getMembershipStatusByDate($dates['start_date'], $dates['end_date'], $dates['join_date'], 'today', TRUE, $membership->membership_type_id, (array) $membership);
                     $formatedParams = array('status_id' => CRM_Utils_Array::value('id', $calcStatus, 2), 'join_date' => CRM_Utils_Date::customFormat(CRM_Utils_Array::value('join_date', $dates), $format), 'start_date' => CRM_Utils_Date::customFormat(CRM_Utils_Array::value('start_date', $dates), $format), 'end_date' => CRM_Utils_Date::customFormat(CRM_Utils_Array::value('end_date', $dates), $format));
                     //we might be renewing membership,
                     //so make status override false.
                     $formatedParams['is_override'] = FALSE;
                     $membership->copyValues($formatedParams);
                     $membership->save();
                     //updating the membership log
                     $membershipLog = array();
                     $membershipLog = $formatedParams;
                     $logStartDate = $formatedParams['start_date'];
                     if (CRM_Utils_Array::value('log_start_date', $dates)) {
                         $logStartDate = CRM_Utils_Date::customFormat($dates['log_start_date'], $format);
                         $logStartDate = CRM_Utils_Date::isoToMysql($logStartDate);
                     }
                     $membershipLog['start_date'] = $logStartDate;
                     $membershipLog['membership_id'] = $membership->id;
                     $membershipLog['modified_id'] = $membership->contact_id;
                     $membershipLog['modified_date'] = date('Ymd');
                     $membershipLog['membership_type_id'] = $membership->membership_type_id;
                     CRM_Member_BAO_MembershipLog::add($membershipLog, CRM_Core_DAO::$_nullArray);
                     //update related Memberships.
                     CRM_Member_BAO_Membership::updateRelatedMemberships($membership->id, $formatedParams);
                     //update the membership type key of membership relatedObjects array
                     //if it has changed after membership update
                     if ($membershipTypeIdKey != $membership->membership_type_id) {
                         $membershipsUpdate[$membership->membership_type_id] = $membership;
                         $contribution->_relatedObjects['membership'][$membership->membership_type_id] = $membership;
                         unset($contribution->_relatedObjects['membership'][$membershipTypeIdKey]);
                         unset($memberships[$membershipTypeIdKey]);
                     }
                 }
             }
             //update the memberships object with updated membershipTypeId data
             //if membershipTypeId has changed after membership update
             if (!empty($membershipsUpdate)) {
                 $memberships = $memberships + $membershipsUpdate;
             }
         }
     } else {
         // event
         $eventParams = array('id' => $objects['event']->id);
         $values['event'] = array();
         CRM_Event_BAO_Event::retrieve($eventParams, $values['event']);
         //get location details
         $locationParams = array('entity_id' => $objects['event']->id, 'entity_table' => 'civicrm_event');
         $values['location'] = CRM_Core_BAO_Location::getValues($locationParams);
         $ufJoinParams = array('entity_table' => 'civicrm_event', 'entity_id' => $ids['event'], 'module' => 'CiviEvent');
         list($custom_pre_id, $custom_post_ids) = CRM_Core_BAO_UFJoin::getUFGroupIds($ufJoinParams);
         $values['custom_pre_id'] = $custom_pre_id;
         $values['custom_post_id'] = $custom_post_ids;
         //for tasks 'Change Participant Status' and 'Batch Update Participants Via Profile' case
         //and cases involving status updation through ipn
         $values['totalAmount'] = $input['amount'];
         $contribution->source = ts('Online Event Registration') . ': ' . $values['event']['title'];
         if ($values['event']['is_email_confirm']) {
             $contribution->receipt_date = self::$_now;
             $values['is_email_receipt'] = 1;
         }
         if (!CRM_Utils_Array::value('skipComponentSync', $input)) {
             $participant->status_id = 1;
         }
         $participant->save();
     }
     if (CRM_Utils_Array::value('net_amount', $input, 0) == 0 && CRM_Utils_Array::value('fee_amount', $input, 0) != 0) {
         $input['net_amount'] = $input['amount'] - $input['fee_amount'];
     }
     // This complete transaction function is being overloaded to create new contributions too.
     // here we record if it is a new contribution.
     // @todo separate the 2 more appropriately.
     $isNewContribution = FALSE;
     if (empty($contribution->id)) {
         $isNewContribution = TRUE;
         if (!empty($input['amount']) && $input['amount'] != $contribution->total_amount) {
             $contribution->total_amount = $input['amount'];
             // The BAO does this stuff but we are actually kinda bypassing it here (bad code! go sit in the corner)
             // so we have to handle net_amount in this (naughty) code.
             if (isset($input['fee_amount']) && is_numeric($input['fee_amount'])) {
                 $contribution->fee_amount = $input['fee_amount'];
             }
             $contribution->net_amount = $contribution->total_amount - $contribution->fee_amount;
         }
         if (!empty($input['campaign_id'])) {
             $contribution->campaign_id = $input['campaign_id'];
         }
     }
     $contributionStatuses = CRM_Core_PseudoConstant::get('CRM_Contribute_DAO_Contribution', 'contribution_status_id', array('labelColumn' => 'name', 'flip' => 1));
     // @todo this section should call the api  in order to have hooks called &
     // because all this 'messiness' setting variables could be avoided
     // by letting the api resolve pseudoconstants & copy set values and format dates.
     $contribution->contribution_status_id = $contributionStatuses['Completed'];
     $contribution->is_test = $input['is_test'];
     // CRM-15960 If we don't have a value we 'want' for the amounts, leave it to the BAO to sort out.
     if (isset($input['net_amount'])) {
         $contribution->fee_amount = CRM_Utils_Array::value('fee_amount', $input, 0);
     }
     if (isset($input['net_amount'])) {
         $contribution->net_amount = $input['net_amount'];
     }
     $contribution->trxn_id = $input['trxn_id'];
     $contribution->receive_date = CRM_Utils_Date::isoToMysql($contribution->receive_date);
     $contribution->thankyou_date = CRM_Utils_Date::isoToMysql($contribution->thankyou_date);
     $contribution->receipt_date = CRM_Utils_Date::isoToMysql($contribution->receipt_date);
     $contribution->cancel_date = 'null';
     if (CRM_Utils_Array::value('check_number', $input)) {
         $contribution->check_number = $input['check_number'];
     }
     if (CRM_Utils_Array::value('payment_instrument_id', $input)) {
         $contribution->payment_instrument_id = $input['payment_instrument_id'];
     }
     if (!empty($contribution->id)) {
         $contributionId['id'] = $contribution->id;
         $input['prevContribution'] = CRM_Contribute_BAO_Contribution::getValues($contributionId, CRM_Core_DAO::$_nullArray, CRM_Core_DAO::$_nullArray);
     }
     $contribution->save();
     //add line items for recurring payments
     if (!empty($contribution->contribution_recur_id)) {
         if ($isNewContribution) {
             $input['line_item'] = $this->addRecurLineItems($contribution->contribution_recur_id, $contribution);
         } else {
             // this is just to prevent e-notices when we call recordFinancialAccounts - per comments on that line - intention is somewhat unclear
             $input['line_item'] = array();
         }
         if (!empty($memberships) && $primaryContributionID != $contribution->id) {
             foreach ($memberships as $membership) {
                 try {
                     $membershipPayment = array('membership_id' => $membership->id, 'contribution_id' => $contribution->id);
                     if (!civicrm_api3('membership_payment', 'getcount', $membershipPayment)) {
                         civicrm_api3('membership_payment', 'create', $membershipPayment);
                     }
                 } catch (CiviCRM_API3_Exception $e) {
                     echo $e->getMessage();
                     // we are catching & ignoring errors as an extra precaution since lost IPNs may be more serious that lost membership_payment data
                     // this fn is unit-tested so risk of changes elsewhere breaking it are otherwise mitigated
                 }
             }
         }
     }
     //copy initial contribution custom fields for recurring contributions
     if ($recurContrib && $recurContrib->id) {
         $this->copyCustomValues($recurContrib->id, $contribution->id);
     }
     // next create the transaction record
     $paymentProcessor = $paymentProcessorId = '';
     if (isset($objects['paymentProcessor'])) {
         if (is_array($objects['paymentProcessor'])) {
             $paymentProcessor = $objects['paymentProcessor']['payment_processor_type'];
             $paymentProcessorId = $objects['paymentProcessor']['id'];
         } else {
             $paymentProcessor = $objects['paymentProcessor']->payment_processor_type;
             $paymentProcessorId = $objects['paymentProcessor']->id;
         }
     }
     //it's hard to see how it could reach this point without a contributon id as it is saved in line 511 above
     // which raised the question as to whether this check preceded line 511 & if so whether something could be broken
     // From a lot of code reading /debugging I'm still not sure the intent WRT first & subsequent payments in this code
     // it would be good if someone added some comments or refactored this
     if ($contribution->id) {
         $contributionStatuses = CRM_Contribute_PseudoConstant::contributionStatus(NULL, 'name');
         if (empty($input['prevContribution']) && $paymentProcessorId || !$input['prevContribution']->is_pay_later && $input['prevContribution']->contribution_status_id == array_search('Pending', $contributionStatuses)) {
             $input['payment_processor'] = $paymentProcessorId;
         }
         $input['contribution_status_id'] = array_search('Completed', $contributionStatuses);
         $input['total_amount'] = $input['amount'];
         $input['contribution'] = $contribution;
         $input['financial_type_id'] = $contribution->financial_type_id;
         if (CRM_Utils_Array::value('participant', $contribution->_relatedObjects)) {
             $input['contribution_mode'] = 'participant';
             $input['participant_id'] = $contribution->_relatedObjects['participant']->id;
             $input['skipLineItem'] = 1;
         }
         //@todo writing a unit test I was unable to create a scenario where this line did not fatal on second
         // and subsequent payments. In this case the line items are created at $this->addRecurLineItems
         // and since the contribution is saved prior to this line there is always a contribution-id,
         // however there is never a prevContribution (which appears to mean original contribution not previous
         // contribution - or preUpdateContributionObject most accurately)
         // so, this is always called & only appears to succeed when prevContribution exists - which appears
         // to mean "are we updating an exisitng pending contribution"
         //I was able to make the unit test complete as fataling here doesn't prevent
         // the contribution being created - but activities would not be created or emails sent
         CRM_Contribute_BAO_Contribution::recordFinancialAccounts($input, NULL);
     }
     self::updateRecurLinkedPledge($contribution);
     // create an activity record
     if ($input['component'] == 'contribute') {
         //CRM-4027
         $targetContactID = NULL;
         if (CRM_Utils_Array::value('related_contact', $ids)) {
             $targetContactID = $contribution->contact_id;
             $contribution->contact_id = $ids['related_contact'];
         }
         CRM_Activity_BAO_Activity::addActivity($contribution, NULL, $targetContactID);
         // event
     } else {
         CRM_Activity_BAO_Activity::addActivity($participant);
     }
     CRM_Core_Error::debug_log_message("Contribution record updated successfully");
     $transaction->commit();
     // CRM-9132 legacy behaviour was that receipts were sent out in all instances. Still sending
     // when array_key 'is_email_receipt doesn't exist in case some instances where is needs setting haven't been set
     if (!array_key_exists('is_email_receipt', $values) || $values['is_email_receipt'] == 1) {
         self::sendMail($input, $ids, $objects, $values, $recur, FALSE);
         CRM_Core_Error::debug_log_message("Receipt sent");
     }
     CRM_Core_Error::debug_log_message("Success: Database updated");
 }
 /**
  * @return array
  */
 public function getZipCodeInfo()
 {
     if (!$this->stateMap) {
         $query = 'SELECT id, name, abbreviation from civicrm_state_province where country_id = 1228';
         $dao = new CRM_Core_DAO();
         $dao->query($query);
         $this->stateMap = array();
         while ($dao->fetch()) {
             $this->stateMap[$dao->abbreviation] = $dao->id;
             $this->states[$dao->id] = $dao->name;
         }
         $dao->free();
     }
     $offset = mt_rand(1, 43000);
     $query = "SELECT city, state, zip, latitude, longitude FROM zipcodes LIMIT {$offset}, 1";
     $dao = new CRM_Core_DAO();
     $dao->query($query);
     while ($dao->fetch()) {
         if ($this->stateMap[$dao->state]) {
             $stateID = $this->stateMap[$dao->state];
         } else {
             $stateID = 1004;
         }
         $zip = str_pad($dao->zip, 5, '0', STR_PAD_LEFT);
         return array(1228, $stateID, $dao->city, $zip, $dao->latitude, $dao->longitude);
     }
 }
 function completeTransaction(&$input, &$ids, &$objects, &$transaction, $recur = FALSE)
 {
     $contribution =& $objects['contribution'];
     $memberships =& $objects['membership'];
     if (is_numeric($memberships)) {
         $memberships = array($objects['membership']);
     }
     $participant =& $objects['participant'];
     $event =& $objects['event'];
     $changeToday = CRM_Utils_Array::value('trxn_date', $input, self::$_now);
     $recurContrib =& $objects['contributionRecur'];
     $values = array();
     if ($input['component'] == 'contribute') {
         if ($contribution->contribution_page_id) {
             CRM_Contribute_BAO_ContributionPage::setValues($contribution->contribution_page_id, $values);
             $source = ts('Online Contribution') . ': ' . $values['title'];
         } elseif ($recurContrib->id) {
             $contribution->contribution_page_id = NULL;
             $values['amount'] = $recurContrib->amount;
             $values['contribution_type_id'] = $objects['contributionType']->id;
             $values['title'] = $source = ts('Offline Recurring Contribution');
             $values['is_email_receipt'] = $recurContrib->is_email_receipt;
             $domainValues = CRM_Core_BAO_Domain::getNameAndEmail();
             $values['receipt_from_name'] = $domainValues[0];
             $values['receipt_from_email'] = $domainValues[1];
         }
         $contribution->source = $source;
         if (CRM_Utils_Array::value('is_email_receipt', $values)) {
             $contribution->receipt_date = self::$_now;
         }
         if (!empty($memberships)) {
             foreach ($memberships as $membershipTypeIdKey => $membership) {
                 if ($membership) {
                     $format = '%Y%m%d';
                     $currentMembership = CRM_Member_BAO_Membership::getContactMembership($membership->contact_id, $membership->membership_type_id, $membership->is_test, $membership->id);
                     // CRM-8141 update the membership type with the value recorded in log when membership created/renewed
                     // this picks up membership type changes during renewals
                     $sql = "\nSELECT    membership_type_id\nFROM      civicrm_membership_log\nWHERE     membership_id={$membership->id}\nORDER BY  id DESC\nLIMIT 1;";
                     $dao = new CRM_Core_DAO();
                     $dao->query($sql);
                     if ($dao->fetch()) {
                         if (!empty($dao->membership_type_id)) {
                             $membership->membership_type_id = $dao->membership_type_id;
                             $membership->save();
                         }
                         // else fall back to using current membership type
                     }
                     // else fall back to using current membership type
                     $dao->free();
                     if ($currentMembership) {
                         /*
                          * Fixed FOR CRM-4433
                          * In BAO/Membership.php(renewMembership function), we skip the extend membership date and status
                          * when Contribution mode is notify and membership is for renewal )
                          */
                         CRM_Member_BAO_Membership::fixMembershipStatusBeforeRenew($currentMembership, $changeToday);
                         $dates = CRM_Member_BAO_MembershipType::getRenewalDatesForMembershipType($membership->id, $changeToday);
                         $dates['join_date'] = CRM_Utils_Date::customFormat($currentMembership['join_date'], $format);
                     } else {
                         $dates = CRM_Member_BAO_MembershipType::getDatesForMembershipType($membership->membership_type_id);
                     }
                     //get the status for membership.
                     $calcStatus = CRM_Member_BAO_MembershipStatus::getMembershipStatusByDate($dates['start_date'], $dates['end_date'], $dates['join_date'], 'today', TRUE);
                     $formatedParams = array('status_id' => CRM_Utils_Array::value('id', $calcStatus, 2), 'join_date' => CRM_Utils_Date::customFormat(CRM_Utils_Array::value('join_date', $dates), $format), 'start_date' => CRM_Utils_Date::customFormat(CRM_Utils_Array::value('start_date', $dates), $format), 'end_date' => CRM_Utils_Date::customFormat(CRM_Utils_Array::value('end_date', $dates), $format), 'reminder_date' => CRM_Utils_Date::customFormat(CRM_Utils_Array::value('reminder_date', $dates), $format));
                     //we might be renewing membership,
                     //so make status override false.
                     $formatedParams['is_override'] = FALSE;
                     $membership->copyValues($formatedParams);
                     $membership->save();
                     //updating the membership log
                     $membershipLog = array();
                     $membershipLog = $formatedParams;
                     $logStartDate = $formatedParams['start_date'];
                     if (CRM_Utils_Array::value('log_start_date', $dates)) {
                         $logStartDate = CRM_Utils_Date::customFormat($dates['log_start_date'], $format);
                         $logStartDate = CRM_Utils_Date::isoToMysql($logStartDate);
                     }
                     $membershipLog['start_date'] = $logStartDate;
                     $membershipLog['membership_id'] = $membership->id;
                     $membershipLog['modified_id'] = $membership->contact_id;
                     $membershipLog['modified_date'] = date('Ymd');
                     $membershipLog['membership_type_id'] = $membership->membership_type_id;
                     CRM_Member_BAO_MembershipLog::add($membershipLog, CRM_Core_DAO::$_nullArray);
                     //update related Memberships.
                     CRM_Member_BAO_Membership::updateRelatedMemberships($membership->id, $formatedParams);
                     //update the membership type key of membership relatedObjects array
                     //if it has changed after membership update
                     if ($membershipTypeIdKey != $membership->membership_type_id) {
                         $memberships[$membership->membership_type_id] = $membership;
                         $contribution->_relatedObjects['membership'][$membership->membership_type_id] = $membership;
                         unset($contribution->_relatedObjects['membership'][$membershipTypeIdKey]);
                         unset($memberships[$membershipTypeIdKey]);
                     }
                 }
             }
         }
     } else {
         // event
         $eventParams = array('id' => $objects['event']->id);
         $values['event'] = array();
         CRM_Event_BAO_Event::retrieve($eventParams, $values['event']);
         $eventParams = array('id' => $objects['event']->id);
         $values['event'] = array();
         CRM_Event_BAO_Event::retrieve($eventParams, $values['event']);
         //get location details
         $locationParams = array('entity_id' => $objects['event']->id, 'entity_table' => 'civicrm_event');
         $values['location'] = CRM_Core_BAO_Location::getValues($locationParams);
         $ufJoinParams = array('entity_table' => 'civicrm_event', 'entity_id' => $ids['event'], 'module' => 'CiviEvent');
         list($custom_pre_id, $custom_post_ids) = CRM_Core_BAO_UFJoin::getUFGroupIds($ufJoinParams);
         $values['custom_pre_id'] = $custom_pre_id;
         $values['custom_post_id'] = $custom_post_ids;
         $contribution->source = ts('Online Event Registration') . ': ' . $values['event']['title'];
         if ($values['event']['is_email_confirm']) {
             $contribution->receipt_date = self::$_now;
             $values['is_email_receipt'] = 1;
         }
         $participant->status_id = 1;
         $participant->save();
     }
     if (CRM_Utils_Array::value('net_amount', $input, 0) == 0 && CRM_Utils_Array::value('fee_amount', $input, 0) != 0) {
         $input['net_amount'] = $input['amount'] - $input['fee_amount'];
     }
     $addLineItems = FALSE;
     if (empty($contribution->id)) {
         $addLineItems = TRUE;
     }
     $contribution->contribution_status_id = 1;
     $contribution->is_test = $input['is_test'];
     $contribution->fee_amount = CRM_Utils_Array::value('fee_amount', $input, 0);
     $contribution->net_amount = CRM_Utils_Array::value('net_amount', $input, 0);
     $contribution->trxn_id = $input['trxn_id'];
     $contribution->receive_date = CRM_Utils_Date::isoToMysql($contribution->receive_date);
     $contribution->thankyou_date = CRM_Utils_Date::isoToMysql($contribution->thankyou_date);
     $contribution->cancel_date = 'null';
     if (CRM_Utils_Array::value('check_number', $input)) {
         $contribution->check_number = $input['check_number'];
     }
     if (CRM_Utils_Array::value('payment_instrument_id', $input)) {
         $contribution->payment_instrument_id = $input['payment_instrument_id'];
     }
     $contribution->save();
     //add lineitems for recurring payments
     if (CRM_Utils_Array::value('contributionRecur', $objects) && $objects['contributionRecur']->id && $addLineItems) {
         $this->addrecurLineItems($objects['contributionRecur']->id, $contribution->id);
     }
     // next create the transaction record
     $paymentProcessor = '';
     if (isset($objects['paymentProcessor'])) {
         if (is_array($objects['paymentProcessor'])) {
             $paymentProcessor = $objects['paymentProcessor']['payment_processor_type'];
         } else {
             $paymentProcessor = $objects['paymentProcessor']->payment_processor_type;
         }
     }
     if ($contribution->trxn_id) {
         $trxnParams = array('contribution_id' => $contribution->id, 'trxn_date' => isset($input['trxn_date']) ? $input['trxn_date'] : self::$_now, 'trxn_type' => 'Debit', 'total_amount' => $input['amount'], 'fee_amount' => $contribution->fee_amount, 'net_amount' => $contribution->net_amount, 'currency' => $contribution->currency, 'payment_processor' => $paymentProcessor, 'trxn_id' => $contribution->trxn_id);
         $trxn = CRM_Core_BAO_FinancialTrxn::create($trxnParams);
     }
     self::updateRecurLinkedPledge($contribution);
     // create an activity record
     if ($input['component'] == 'contribute') {
         //CRM-4027
         $targetContactID = NULL;
         if (CRM_Utils_Array::value('related_contact', $ids)) {
             $targetContactID = $contribution->contact_id;
             $contribution->contact_id = $ids['related_contact'];
         }
         CRM_Activity_BAO_Activity::addActivity($contribution, NULL, $targetContactID);
         // event
     } else {
         CRM_Activity_BAO_Activity::addActivity($participant);
     }
     CRM_Core_Error::debug_log_message("Contribution record updated successfully");
     $transaction->commit();
     // CRM-9132 legacy behaviour was that receipts were sent out in all instances. Still sending
     // when array_key 'is_email_receipt doesn't exist in case some instances where is needs setting haven't been set
     if (!array_key_exists('is_email_receipt', $values) || $values['is_email_receipt'] == 1) {
         self::sendMail($input, $ids, $objects, $values, $recur, FALSE);
     }
     CRM_Core_Error::debug_log_message("Success: Database updated and mail sent");
 }
 /**
  * @dataProvider entities_updatesingle
  *
  * limitations include the problem with avoiding loops when creating test objects -
  * hence FKs only set by createTestObject when required. e.g parent_id on campaign is not being followed through
  * Currency - only seems to support US
  */
 public function testCreateSingleValueAlter($entityName)
 {
     if (in_array($entityName, $this->toBeImplemented['create'])) {
         // $this->markTestIncomplete("civicrm_api3_{$Entity}_create to be implemented");
         return;
     }
     $baoString = _civicrm_api3_get_DAO($entityName);
     $this->assertNotEmpty($baoString, $entityName);
     $this->assertNotEmpty($entityName, $entityName);
     $fieldsget = $fields = $this->callAPISuccess($entityName, 'getfields', array('action' => 'get'));
     if ($entityName != 'Pledge') {
         $fields = $this->callAPISuccess($entityName, 'getfields', array('action' => 'create'));
     }
     $fields = $fields['values'];
     $return = array_keys($fieldsget['values']);
     $valuesNotToReturn = $this->getKnownUnworkablesUpdateSingle($entityName, 'break_return');
     // these can't be requested as return values
     $entityValuesThatDontWork = array_merge($this->getKnownUnworkablesUpdateSingle($entityName, 'cant_update'), $this->getKnownUnworkablesUpdateSingle($entityName, 'cant_return'), $valuesNotToReturn);
     $return = array_diff($return, $valuesNotToReturn);
     $baoObj = new CRM_Core_DAO();
     $baoObj->createTestObject($baoString, array('currency' => 'USD'), 2, 0);
     $getentities = $this->callAPISuccess($entityName, 'get', array('sequential' => 1, 'return' => $return, 'options' => array('sort' => 'id DESC', 'limit' => 2)));
     // lets use first rather than assume only one exists
     $entity = $getentities['values'][0];
     $entity2 = $getentities['values'][1];
     foreach ($fields as $field => $specs) {
         $fieldName = $field;
         if (!empty($specs['uniquename'])) {
             $fieldName = $specs['uniquename'];
         }
         if ($field == 'currency' || $field == 'id' || $field == strtolower($entityName) . '_id' || in_array($field, $entityValuesThatDontWork)) {
             //@todo id & entity_id are correct but we should fix currency & frequency_day
             continue;
         }
         switch ($specs['type']) {
             case CRM_Utils_Type::T_DATE:
             case CRM_Utils_Type::T_TIMESTAMP:
                 $entity[$fieldName] = '2012-05-20';
                 break;
                 //case CRM_Utils_Type::T_DATETIME:
             //case CRM_Utils_Type::T_DATETIME:
             case 12:
                 $entity[$fieldName] = '2012-05-20 03:05:20';
                 break;
             case CRM_Utils_Type::T_STRING:
             case CRM_Utils_Type::T_BLOB:
             case CRM_Utils_Type::T_MEDIUMBLOB:
             case CRM_Utils_Type::T_TEXT:
             case CRM_Utils_Type::T_LONGTEXT:
             case CRM_Utils_Type::T_EMAIL:
                 $entity[$fieldName] = substr('New String', 0, CRM_Utils_Array::Value('maxlength', $specs, 100));
                 break;
             case CRM_Utils_Type::T_INT:
                 // probably created with a 1
                 $entity[$fieldName] = '6';
                 if (!empty($specs['FKClassName'])) {
                     if ($specs['FKClassName'] == $baoString) {
                         $entity[$fieldName] = (string) $entity2['id'];
                     } else {
                         $uniqueName = CRM_Utils_Array::value('uniqueName', $specs);
                         $entity[$fieldName] = (string) empty($entity2[$field]) ? CRM_Utils_Array::value($uniqueName, $entity2) : $entity2[$field];
                         //todo - there isn't always something set here - & our checking on unset values is limited
                         if (empty($entity[$field])) {
                             unset($entity[$field]);
                         }
                     }
                 }
                 break;
             case CRM_Utils_Type::T_BOOLEAN:
                 // probably created with a 1
                 $entity[$fieldName] = '0';
                 break;
             case CRM_Utils_Type::T_FLOAT:
             case CRM_Utils_Type::T_MONEY:
                 $entity[$field] = '222';
                 break;
             case CRM_Utils_Type::T_URL:
                 $entity[$field] = 'warm.beer.com';
         }
         if (!empty($specs['pseudoconstant']) || !empty($specs['enumValues'])) {
             $options = $this->callAPISuccess($entityName, 'getoptions', array('context' => 'create', 'field' => $field));
             if (empty($options['values'])) {
             }
             $entity[$field] = array_rand($options['values']);
         }
         $updateParams = array('id' => $entity['id'], $field => isset($entity[$field]) ? $entity[$field] : NULL);
         $update = $this->callAPISuccess($entityName, 'create', $updateParams);
         $checkParams = array('id' => $entity['id'], 'sequential' => 1, 'return' => $return, 'options' => array('sort' => 'id DESC', 'limit' => 2));
         $checkEntity = $this->callAPISuccess($entityName, 'getsingle', $checkParams);
         $this->assertAPIArrayComparison($entity, $checkEntity, array(), "checking if {$fieldName} was correctly updaetd\n" . print_r(array('update-params' => $updateParams, 'update-result' => $update, 'getsingle-params' => $checkParams, 'getsingle-result' => $checkEntity, 'expected entity' => $entity), TRUE));
     }
     $baoObj->deleteTestObjects($baoString);
     $baoObj->free();
 }
Example #5
0
 /**
  * Update contribution as well as related objects.
  *
  * This function by-passes hooks - to address this - don't use this function.
  *
  * @deprecated
  *
  * Use api contribute.completetransaction
  * For failures use failPayment (preferably exposing by api in the process).
  *
  * @param array $params
  * @param bool $processContributionObject
  *
  * @return array
  * @throws \Exception
  */
 public static function transitionComponents($params, $processContributionObject = FALSE)
 {
     // get minimum required values.
     $contactId = CRM_Utils_Array::value('contact_id', $params);
     $componentId = CRM_Utils_Array::value('component_id', $params);
     $componentName = CRM_Utils_Array::value('componentName', $params);
     $contributionId = CRM_Utils_Array::value('contribution_id', $params);
     $contributionStatusId = CRM_Utils_Array::value('contribution_status_id', $params);
     // if we already processed contribution object pass previous status id.
     $previousContriStatusId = CRM_Utils_Array::value('previous_contribution_status_id', $params);
     $updateResult = array();
     $contributionStatuses = CRM_Contribute_PseudoConstant::contributionStatus(NULL, 'name');
     // we process only ( Completed, Cancelled, or Failed ) contributions.
     if (!$contributionId || !in_array($contributionStatusId, array(array_search('Completed', $contributionStatuses), array_search('Cancelled', $contributionStatuses), array_search('Failed', $contributionStatuses)))) {
         return $updateResult;
     }
     if (!$componentName || !$componentId) {
         // get the related component details.
         $componentDetails = self::getComponentDetails($contributionId);
     } else {
         $componentDetails['contact_id'] = $contactId;
         $componentDetails['component'] = $componentName;
         if ($componentName == 'event') {
             $componentDetails['participant'] = $componentId;
         } else {
             $componentDetails['membership'] = $componentId;
         }
     }
     if (!empty($componentDetails['contact_id'])) {
         $componentDetails['contact_id'] = CRM_Core_DAO::getFieldValue('CRM_Contribute_DAO_Contribution', $contributionId, 'contact_id');
     }
     // do check for required ids.
     if (empty($componentDetails['membership']) && empty($componentDetails['participant']) && empty($componentDetails['pledge_payment']) || empty($componentDetails['contact_id'])) {
         return $updateResult;
     }
     //now we are ready w/ required ids, start processing.
     $baseIPN = new CRM_Core_Payment_BaseIPN();
     $input = $ids = $objects = array();
     $input['component'] = CRM_Utils_Array::value('component', $componentDetails);
     $ids['contribution'] = $contributionId;
     $ids['contact'] = CRM_Utils_Array::value('contact_id', $componentDetails);
     $ids['membership'] = CRM_Utils_Array::value('membership', $componentDetails);
     $ids['participant'] = CRM_Utils_Array::value('participant', $componentDetails);
     $ids['event'] = CRM_Utils_Array::value('event', $componentDetails);
     $ids['pledge_payment'] = CRM_Utils_Array::value('pledge_payment', $componentDetails);
     $ids['contributionRecur'] = NULL;
     $ids['contributionPage'] = NULL;
     if (!$baseIPN->validateData($input, $ids, $objects, FALSE)) {
         CRM_Core_Error::fatal();
     }
     $memberships =& $objects['membership'];
     $participant =& $objects['participant'];
     $pledgePayment =& $objects['pledge_payment'];
     $contribution =& $objects['contribution'];
     if ($pledgePayment) {
         $pledgePaymentIDs = array();
         foreach ($pledgePayment as $key => $object) {
             $pledgePaymentIDs[] = $object->id;
         }
         $pledgeID = $pledgePayment[0]->pledge_id;
     }
     $membershipStatuses = CRM_Member_PseudoConstant::membershipStatus();
     if ($participant) {
         $participantStatuses = CRM_Event_PseudoConstant::participantStatus();
         $oldStatus = CRM_Core_DAO::getFieldValue('CRM_Event_DAO_Participant', $participant->id, 'status_id');
     }
     // we might want to process contribution object.
     $processContribution = FALSE;
     if ($contributionStatusId == array_search('Cancelled', $contributionStatuses)) {
         if (is_array($memberships)) {
             foreach ($memberships as $membership) {
                 if ($membership) {
                     $membership->status_id = array_search('Cancelled', $membershipStatuses);
                     $membership->save();
                     $updateResult['updatedComponents']['CiviMember'] = $membership->status_id;
                     if ($processContributionObject) {
                         $processContribution = TRUE;
                     }
                 }
             }
         }
         if ($participant) {
             $updatedStatusId = array_search('Cancelled', $participantStatuses);
             CRM_Event_BAO_Participant::updateParticipantStatus($participant->id, $oldStatus, $updatedStatusId, TRUE);
             $updateResult['updatedComponents']['CiviEvent'] = $updatedStatusId;
             if ($processContributionObject) {
                 $processContribution = TRUE;
             }
         }
         if ($pledgePayment) {
             CRM_Pledge_BAO_PledgePayment::updatePledgePaymentStatus($pledgeID, $pledgePaymentIDs, $contributionStatusId);
             $updateResult['updatedComponents']['CiviPledge'] = $contributionStatusId;
             if ($processContributionObject) {
                 $processContribution = TRUE;
             }
         }
     } elseif ($contributionStatusId == array_search('Failed', $contributionStatuses)) {
         if (is_array($memberships)) {
             foreach ($memberships as $membership) {
                 if ($membership) {
                     $membership->status_id = array_search('Expired', $membershipStatuses);
                     $membership->save();
                     $updateResult['updatedComponents']['CiviMember'] = $membership->status_id;
                     if ($processContributionObject) {
                         $processContribution = TRUE;
                     }
                 }
             }
         }
         if ($participant) {
             $updatedStatusId = array_search('Cancelled', $participantStatuses);
             CRM_Event_BAO_Participant::updateParticipantStatus($participant->id, $oldStatus, $updatedStatusId, TRUE);
             $updateResult['updatedComponents']['CiviEvent'] = $updatedStatusId;
             if ($processContributionObject) {
                 $processContribution = TRUE;
             }
         }
         if ($pledgePayment) {
             CRM_Pledge_BAO_PledgePayment::updatePledgePaymentStatus($pledgeID, $pledgePaymentIDs, $contributionStatusId);
             $updateResult['updatedComponents']['CiviPledge'] = $contributionStatusId;
             if ($processContributionObject) {
                 $processContribution = TRUE;
             }
         }
     } elseif ($contributionStatusId == array_search('Completed', $contributionStatuses)) {
         // only pending contribution related object processed.
         if ($previousContriStatusId && $previousContriStatusId != array_search('Pending', $contributionStatuses)) {
             // this is case when we already processed contribution object.
             return $updateResult;
         } elseif (!$previousContriStatusId && $contribution->contribution_status_id != array_search('Pending', $contributionStatuses)) {
             // this is case when we are going to process contribution object later.
             return $updateResult;
         }
         if (is_array($memberships)) {
             foreach ($memberships as $membership) {
                 if ($membership) {
                     $format = '%Y%m%d';
                     //CRM-4523
                     $currentMembership = CRM_Member_BAO_Membership::getContactMembership($membership->contact_id, $membership->membership_type_id, $membership->is_test, $membership->id);
                     // CRM-8141 update the membership type with the value recorded in log when membership created/renewed
                     // this picks up membership type changes during renewals
                     $sql = "\n              SELECT    membership_type_id\n              FROM      civicrm_membership_log\n              WHERE     membership_id={$membership->id}\n              ORDER BY  id DESC\n              LIMIT     1;";
                     $dao = new CRM_Core_DAO();
                     $dao->query($sql);
                     if ($dao->fetch()) {
                         if (!empty($dao->membership_type_id)) {
                             $membership->membership_type_id = $dao->membership_type_id;
                             $membership->save();
                         }
                     }
                     // else fall back to using current membership type
                     $dao->free();
                     // Figure out number of terms
                     $numterms = 1;
                     $lineitems = CRM_Price_BAO_LineItem::getLineItems($contributionId, 'contribution');
                     foreach ($lineitems as $lineitem) {
                         if ($membership->membership_type_id == CRM_Utils_Array::value('membership_type_id', $lineitem)) {
                             $numterms = CRM_Utils_Array::value('membership_num_terms', $lineitem);
                             // in case membership_num_terms comes through as null or zero
                             $numterms = $numterms >= 1 ? $numterms : 1;
                             break;
                         }
                     }
                     // CRM-15735-to update the membership status as per the contribution receive date
                     $joinDate = NULL;
                     if (!empty($params['receive_date'])) {
                         $joinDate = $params['receive_date'];
                         $status = CRM_Member_BAO_MembershipStatus::getMembershipStatusByDate($membership->start_date, $membership->end_date, $membership->join_date, $params['receive_date'], FALSE, $membership->membership_type_id, (array) $membership);
                         $membership->status_id = CRM_Utils_Array::value('id', $status, $membership->status_id);
                         $membership->save();
                     }
                     if ($currentMembership) {
                         CRM_Member_BAO_Membership::fixMembershipStatusBeforeRenew($currentMembership, NULL);
                         $dates = CRM_Member_BAO_MembershipType::getRenewalDatesForMembershipType($membership->id, NULL, NULL, $numterms);
                         $dates['join_date'] = CRM_Utils_Date::customFormat($currentMembership['join_date'], $format);
                     } else {
                         $dates = CRM_Member_BAO_MembershipType::getDatesForMembershipType($membership->membership_type_id, $joinDate, NULL, NULL, $numterms);
                     }
                     //get the status for membership.
                     $calcStatus = CRM_Member_BAO_MembershipStatus::getMembershipStatusByDate($dates['start_date'], $dates['end_date'], $dates['join_date'], 'today', TRUE, $membership->membership_type_id, (array) $membership);
                     $formattedParams = array('status_id' => CRM_Utils_Array::value('id', $calcStatus, array_search('Current', $membershipStatuses)), 'join_date' => CRM_Utils_Date::customFormat($dates['join_date'], $format), 'start_date' => CRM_Utils_Date::customFormat($dates['start_date'], $format), 'end_date' => CRM_Utils_Date::customFormat($dates['end_date'], $format));
                     CRM_Utils_Hook::pre('edit', 'Membership', $membership->id, $formattedParams);
                     $membership->copyValues($formattedParams);
                     $membership->save();
                     //updating the membership log
                     $membershipLog = array();
                     $membershipLog = $formattedParams;
                     $logStartDate = CRM_Utils_Date::customFormat(CRM_Utils_Array::value('log_start_date', $dates), $format);
                     $logStartDate = $logStartDate ? CRM_Utils_Date::isoToMysql($logStartDate) : $formattedParams['start_date'];
                     $membershipLog['start_date'] = $logStartDate;
                     $membershipLog['membership_id'] = $membership->id;
                     $membershipLog['modified_id'] = $membership->contact_id;
                     $membershipLog['modified_date'] = date('Ymd');
                     $membershipLog['membership_type_id'] = $membership->membership_type_id;
                     CRM_Member_BAO_MembershipLog::add($membershipLog, CRM_Core_DAO::$_nullArray);
                     //update related Memberships.
                     CRM_Member_BAO_Membership::updateRelatedMemberships($membership->id, $formattedParams);
                     $updateResult['membership_end_date'] = CRM_Utils_Date::customFormat($dates['end_date'], '%B %E%f, %Y');
                     $updateResult['updatedComponents']['CiviMember'] = $membership->status_id;
                     if ($processContributionObject) {
                         $processContribution = TRUE;
                     }
                     CRM_Utils_Hook::post('edit', 'Membership', $membership->id, $membership);
                 }
             }
         }
         if ($participant) {
             $updatedStatusId = array_search('Registered', $participantStatuses);
             CRM_Event_BAO_Participant::updateParticipantStatus($participant->id, $oldStatus, $updatedStatusId, TRUE);
             $updateResult['updatedComponents']['CiviEvent'] = $updatedStatusId;
             if ($processContributionObject) {
                 $processContribution = TRUE;
             }
         }
         if ($pledgePayment) {
             CRM_Pledge_BAO_PledgePayment::updatePledgePaymentStatus($pledgeID, $pledgePaymentIDs, $contributionStatusId);
             $updateResult['updatedComponents']['CiviPledge'] = $contributionStatusId;
             if ($processContributionObject) {
                 $processContribution = TRUE;
             }
         }
     }
     // process contribution object.
     if ($processContribution) {
         $contributionParams = array();
         $fields = array('contact_id', 'total_amount', 'receive_date', 'is_test', 'campaign_id', 'payment_instrument_id', 'trxn_id', 'invoice_id', 'financial_type_id', 'contribution_status_id', 'non_deductible_amount', 'receipt_date', 'check_number');
         foreach ($fields as $field) {
             if (empty($params[$field])) {
                 continue;
             }
             $contributionParams[$field] = $params[$field];
         }
         $ids = array('contribution' => $contributionId);
         $contribution = CRM_Contribute_BAO_Contribution::create($contributionParams, $ids);
     }
     return $updateResult;
 }
Example #6
0
 /**
  * Execute a query and get the single result.
  *
  * @param string $query
  *   Query to be executed.
  * @param array $params
  * @param bool $abort
  * @param bool $i18nRewrite
  * @return string|null
  *   the result of the query if any
  *
  */
 public static function &singleValueQuery($query, $params = array(), $abort = TRUE, $i18nRewrite = TRUE)
 {
     $queryStr = self::composeQuery($query, $params, $abort);
     static $_dao = NULL;
     if (!$_dao) {
         $_dao = new CRM_Core_DAO();
     }
     $_dao->query($queryStr, $i18nRewrite);
     $result = $_dao->getDatabaseResult();
     $ret = NULL;
     if ($result) {
         $row = $result->fetchRow();
         if ($row) {
             $ret = $row[0];
         }
     }
     $_dao->free();
     return $ret;
 }
 public function fillTable()
 {
     // get the list of queries handy
     $tableQueries = $this->tableQuery();
     if ($this->params && !$this->noRules) {
         $tempTableQuery = "CREATE TEMPORARY TABLE dedupe (id1 int, weight int, UNIQUE UI_id1 (id1)) ENGINE=MyISAM";
         $insertClause = "INSERT INTO dedupe (id1, weight)";
         $groupByClause = "GROUP BY id1";
         $dupeCopyJoin = " JOIN dedupe_copy ON dedupe_copy.id1 = t1.column WHERE ";
     } else {
         $tempTableQuery = "CREATE TEMPORARY TABLE dedupe (id1 int, id2 int, weight int, UNIQUE UI_id1_id2 (id1, id2)) ENGINE=MyISAM";
         $insertClause = "INSERT INTO dedupe (id1, id2, weight)";
         $groupByClause = "GROUP BY id1, id2";
         $dupeCopyJoin = " JOIN dedupe_copy ON dedupe_copy.id1 = t1.column AND dedupe_copy.id2 = t2.column WHERE ";
     }
     $patternColumn = '/t1.(\\w+)/';
     $exclWeightSum = array();
     // create temp table
     $dao = new CRM_Core_DAO();
     $dao->query($tempTableQuery);
     CRM_Utils_Hook::dupeQuery($this, 'table', $tableQueries);
     while (!empty($tableQueries)) {
         list($isInclusive, $isDie) = self::isQuerySetInclusive($tableQueries, $this->threshold, $exclWeightSum);
         if ($isInclusive) {
             // order queries by table count
             self::orderByTableCount($tableQueries);
             $weightSum = array_sum($exclWeightSum);
             $searchWithinDupes = !empty($exclWeightSum) ? 1 : 0;
             while (!empty($tableQueries)) {
                 // extract the next query ( and weight ) to be executed
                 $fieldWeight = array_keys($tableQueries);
                 $fieldWeight = $fieldWeight[0];
                 $query = array_shift($tableQueries);
                 if ($searchWithinDupes) {
                     // get prepared to search within already found dupes if $searchWithinDupes flag is set
                     $dao->query("DROP TEMPORARY TABLE IF EXISTS dedupe_copy");
                     $dao->query("CREATE TEMPORARY TABLE dedupe_copy SELECT * FROM dedupe WHERE weight >= {$weightSum}");
                     $dao->free();
                     preg_match($patternColumn, $query, $matches);
                     $query = str_replace(' WHERE ', str_replace('column', $matches[1], $dupeCopyJoin), $query);
                 }
                 $searchWithinDupes = 1;
                 // construct and execute the intermediate query
                 $query = "{$insertClause} {$query} {$groupByClause} ON DUPLICATE KEY UPDATE weight = weight + VALUES(weight)";
                 $dao->query($query);
                 // FIXME: we need to be more acurate with affected rows, especially for insert vs duplicate insert.
                 // And that will help optimize further.
                 $affectedRows = $dao->affectedRows();
                 $dao->free();
                 // In an inclusive situation, failure of any query means no further processing -
                 if ($affectedRows == 0) {
                     // reset to make sure no further execution is done.
                     $tableQueries = array();
                     break;
                 }
                 $weightSum = substr($fieldWeight, strrpos($fieldWeight, '.') + 1) + $weightSum;
             }
             // An exclusive situation -
         } elseif (!$isDie) {
             // since queries are already sorted by weights, we can continue as is
             $fieldWeight = array_keys($tableQueries);
             $fieldWeight = $fieldWeight[0];
             $query = array_shift($tableQueries);
             $query = "{$insertClause} {$query} {$groupByClause} ON DUPLICATE KEY UPDATE weight = weight + VALUES(weight)";
             $dao->query($query);
             if ($dao->affectedRows() >= 1) {
                 $exclWeightSum[] = substr($fieldWeight, strrpos($fieldWeight, '.') + 1);
             }
             $dao->free();
         } else {
             // its a die situation
             break;
         }
     }
 }
Example #8
0
 /**
  * Build & execute the query and return results array
  *
  * @return array
  * @throws \API_Exception
  * @throws \CRM_Core_Exception
  * @throws \Exception
  */
 public function run()
 {
     // $select_fields maps column names to the field names of the result values.
     $select_fields = $custom_fields = array();
     // populate $select_fields
     $return_all_fields = empty($this->options['return']) || !is_array($this->options['return']);
     $return = $return_all_fields ? array_fill_keys($this->entityFieldNames, 1) : $this->options['return'];
     // core return fields
     foreach ($return as $field_name => $include) {
         if ($include) {
             $field = $this->getField($field_name);
             if ($field && in_array($field['name'], $this->entityFieldNames)) {
                 // 'a.' is an alias for the entity table.
                 $select_fields["a.{$field['name']}"] = $field['name'];
             } elseif ($include && strpos($field_name, '.')) {
                 $fkField = $this->addFkField($field_name);
                 if ($fkField) {
                     $select_fields[implode('.', $fkField)] = $field_name;
                 }
             }
         }
     }
     // Do custom fields IF the params contain the word "custom" or we are returning *
     if ($return_all_fields || strpos(json_encode($this->params), 'custom')) {
         $custom_fields = _civicrm_api3_custom_fields_for_entity($this->entity);
         foreach ($custom_fields as $cf_id => $custom_field) {
             $field_name = "custom_{$cf_id}";
             if ($return_all_fields || !empty($this->options['return'][$field_name]) || !empty($this->options['return']['custom'])) {
                 list($table_name, $column_name) = $this->addCustomField($custom_field);
                 if ($custom_field["data_type"] != "ContactReference") {
                     // 'ordinary' custom field. We will select the value as custom_XX.
                     $select_fields["{$table_name}.{$column_name}"] = $field_name;
                 } else {
                     // contact reference custom field. The ID will be stored in custom_XX_id.
                     // custom_XX will contain the sort name of the contact.
                     $this->query->join("c_{$cf_id}", "LEFT JOIN civicrm_contact c_{$cf_id} ON c_{$cf_id}.id = `{$table_name}`.`{$column_name}`");
                     $select_fields["{$table_name}.{$column_name}"] = $field_name . "_id";
                     // We will call the contact table for the join c_XX.
                     $select_fields["c_{$cf_id}.sort_name"] = $field_name;
                 }
             }
         }
     }
     // Always select the ID.
     $select_fields["a.id"] = "id";
     // populate where_clauses
     foreach ($this->params as $key => $value) {
         $table_name = NULL;
         $column_name = NULL;
         if (substr($key, 0, 7) == 'filter.') {
             // Legacy support for old filter syntax per the test contract.
             // (Convert the style to the later one & then deal with them).
             $filterArray = explode('.', $key);
             $value = array($filterArray[1] => $value);
             $key = 'filters';
         }
         // Legacy support for 'filter's construct.
         if ($key == 'filters') {
             foreach ($value as $filterKey => $filterValue) {
                 if (substr($filterKey, -4, 4) == 'high') {
                     $key = substr($filterKey, 0, -5);
                     $value = array('<=' => $filterValue);
                 }
                 if (substr($filterKey, -3, 3) == 'low') {
                     $key = substr($filterKey, 0, -4);
                     $value = array('>=' => $filterValue);
                 }
                 if ($filterKey == 'is_current' || $filterKey == 'isCurrent') {
                     // Is current is almost worth creating as a 'sql filter' in the DAO function since several entities have the
                     // concept.
                     $todayStart = date('Ymd000000', strtotime('now'));
                     $todayEnd = date('Ymd235959', strtotime('now'));
                     $this->query->where(array("(a.start_date <= '{$todayStart}' OR a.start_date IS NULL) AND (a.end_date >= '{$todayEnd}' OR\n          a.end_date IS NULL)\n          AND a.is_active = 1\n        "));
                 }
             }
         }
         // Ignore the "options" param if it is referring to api options and not a field in this entity
         if ($key === 'options' && is_array($value) && !in_array(\CRM_Utils_Array::first(array_keys($value)), \CRM_Core_DAO::acceptedSQLOperators())) {
             continue;
         }
         $field = $this->getField($key);
         if ($field) {
             $key = $field['name'];
         }
         if (in_array($key, $this->entityFieldNames)) {
             $table_name = 'a';
             $column_name = $key;
         } elseif (($cf_id = \CRM_Core_BAO_CustomField::getKeyID($key)) != FALSE) {
             list($table_name, $column_name) = $this->addCustomField($custom_fields[$cf_id]);
         } elseif (strpos($key, '.')) {
             $fkInfo = $this->addFkField($key);
             if ($fkInfo) {
                 list($table_name, $column_name) = $fkInfo;
                 $this->validateNestedInput($key, $value);
             }
         }
         // I don't know why I had to specifically exclude 0 as a key - wouldn't the others have caught it?
         // We normally silently ignore null values passed in - if people want IS_NULL they can use acceptedSqlOperator syntax.
         if (!$table_name || empty($key) || is_null($value)) {
             // No valid filter field. This might be a chained call or something.
             // Just ignore this for the $where_clause.
             continue;
         }
         if (!is_array($value)) {
             $this->query->where(array("`{$table_name}`.`{$column_name}` = @value"), array("@value" => $value));
         } else {
             // We expect only one element in the array, of the form
             // "operator" => "rhs".
             $operator = \CRM_Utils_Array::first(array_keys($value));
             if (!in_array($operator, \CRM_Core_DAO::acceptedSQLOperators())) {
                 $this->query->where(array("{$table_name}.{$column_name} = @value"), array("@value" => $value));
             } else {
                 $this->query->where(\CRM_Core_DAO::createSQLFilter("{$table_name}.{$column_name}", $value));
             }
         }
     }
     if (!$this->options['is_count']) {
         foreach ($select_fields as $column => $alias) {
             $this->query->select("{$column} as `{$alias}`");
         }
     } else {
         $this->query->select("count(*) as c");
     }
     // order by
     if (!empty($this->options['sort'])) {
         $sort_fields = array();
         foreach (explode(',', $this->options['sort']) as $sort_option) {
             $words = preg_split("/[\\s]+/", $sort_option);
             if (count($words) > 0 && in_array($words[0], array_values($select_fields))) {
                 $tmp = $words[0];
                 if (!empty($words[1]) && strtoupper($words[1]) == 'DESC') {
                     $tmp .= " DESC";
                 }
                 $sort_fields[] = $tmp;
             }
         }
         if (count($sort_fields) > 0) {
             $this->query->orderBy(implode(",", $sort_fields));
         }
     }
     // limit
     if (!empty($this->options['limit']) || !empty($this->options['offset'])) {
         $this->query->limit($this->options['limit'], $this->options['offset']);
     }
     // ACLs
     $this->query->where($this->getAclClause('a'));
     $this->bao->free();
     $result_entities = array();
     $result_dao = \CRM_Core_DAO::executeQuery($this->query->toSQL());
     while ($result_dao->fetch()) {
         if ($this->options['is_count']) {
             $result_dao->free();
             return (int) $result_dao->c;
         }
         $result_entities[$result_dao->id] = array();
         foreach ($select_fields as $column => $alias) {
             $returnName = $alias;
             $alias = str_replace('.', '_', $alias);
             if (property_exists($result_dao, $alias) && $result_dao->{$alias} != NULL) {
                 $result_entities[$result_dao->id][$returnName] = $result_dao->{$alias};
             }
             // Backward compatibility on fields names.
             if ($this->isFillUniqueFields && !empty($this->apiFieldSpec[$alias]['uniqueName'])) {
                 $result_entities[$result_dao->id][$this->apiFieldSpec[$alias]['uniqueName']] = $result_dao->{$alias};
             }
             foreach ($this->apiFieldSpec as $returnName => $spec) {
                 if (empty($result_entities[$result_dao->id][$returnName]) && !empty($result_entities[$result_dao->id][$spec['name']])) {
                     $result_entities[$result_dao->id][$returnName] = $result_entities[$result_dao->id][$spec['name']];
                 }
             }
         }
     }
     $result_dao->free();
     return $result_entities;
 }
 /**
  * @dataProvider entities_updatesingle
  *
  * limitations include the problem with avoiding loops when creating test objects -
  * hence FKs only set by createTestObject when required. e.g parent_id on campaign is not being followed through
  * Currency - only seems to support US
  * @param $entityName
  */
 public function testCreateSingleValueAlter($entityName)
 {
     if (in_array($entityName, $this->toBeImplemented['create'])) {
         // $this->markTestIncomplete("civicrm_api3_{$Entity}_create to be implemented");
         return;
     }
     $baoString = _civicrm_api3_get_BAO($entityName);
     $this->assertNotEmpty($baoString, $entityName);
     $this->assertNotEmpty($entityName, $entityName);
     $fieldsGet = $fields = $this->callAPISuccess($entityName, 'getfields', array('action' => 'get', 'options' => array('get_options' => 'all')));
     if ($entityName != 'Pledge') {
         $fields = $this->callAPISuccess($entityName, 'getfields', array('action' => 'create', 'options' => array('get_options' => 'all')));
     }
     $fields = $fields['values'];
     $return = array_keys($fieldsGet['values']);
     $valuesNotToReturn = $this->getKnownUnworkablesUpdateSingle($entityName, 'break_return');
     // these can't be requested as return values
     $entityValuesThatDoNotWork = array_merge($this->getKnownUnworkablesUpdateSingle($entityName, 'cant_update'), $this->getKnownUnworkablesUpdateSingle($entityName, 'cant_return'), $valuesNotToReturn);
     $return = array_diff($return, $valuesNotToReturn);
     $baoObj = new CRM_Core_DAO();
     $baoObj->createTestObject($baoString, array('currency' => 'USD'), 2, 0);
     $getEntities = $this->callAPISuccess($entityName, 'get', array('sequential' => 1, 'return' => $return, 'options' => array('sort' => 'id DESC', 'limit' => 2)));
     // lets use first rather than assume only one exists
     $entity = $getEntities['values'][0];
     $entity2 = $getEntities['values'][1];
     $this->deletableTestObjects[$baoString][] = $entity['id'];
     $this->deletableTestObjects[$baoString][] = $entity2['id'];
     foreach ($fields as $field => $specs) {
         $resetFKTo = NULL;
         $fieldName = $field;
         if (!empty($specs['uniquename'])) {
             $fieldName = $specs['uniquename'];
         }
         if ($field == 'currency' || $field == 'id' || $field == strtolower($entityName) . '_id' || in_array($field, $entityValuesThatDoNotWork)) {
             //@todo id & entity_id are correct but we should fix currency & frequency_day
             continue;
         }
         $this->assertArrayHasKey('type', $specs, "the _spec function for {$entityName} field {$field} does not specify the type");
         switch ($specs['type']) {
             case CRM_Utils_Type::T_DATE:
                 $entity[$fieldName] = '2012-05-20';
                 break;
             case CRM_Utils_Type::T_TIMESTAMP:
             case 12:
                 $entity[$fieldName] = '2012-05-20 03:05:20';
                 break;
             case CRM_Utils_Type::T_STRING:
             case CRM_Utils_Type::T_BLOB:
             case CRM_Utils_Type::T_MEDIUMBLOB:
             case CRM_Utils_Type::T_TEXT:
             case CRM_Utils_Type::T_LONGTEXT:
             case CRM_Utils_Type::T_EMAIL:
                 if ($fieldName == 'form_values' && $entityName == 'SavedSearch') {
                     // This is a hack for the SavedSearch API.
                     // It expects form_values to be an array.
                     // If you want to fix this, you should definitely read this forum
                     // post.
                     // http://forum.civicrm.org/index.php/topic,33990.0.html
                     // See also my question on the CiviCRM Stack Exchange:
                     // https://civicrm.stackexchange.com/questions/3437
                     $entity[$fieldName] = array('sort_name' => "SortName2");
                 } else {
                     $entity[$fieldName] = substr('New String', 0, CRM_Utils_Array::Value('maxlength', $specs, 100));
                     // typecast with array to satisfy changes made in CRM-13160
                     if ($entityName == 'MembershipType' && in_array($fieldName, array('relationship_type_id', 'relationship_direction'))) {
                         $entity[$fieldName] = (array) $entity[$fieldName];
                     }
                 }
                 break;
             case CRM_Utils_Type::T_INT:
                 // probably created with a 1
                 if ($fieldName == 'weight') {
                     $entity[$fieldName] = 2;
                 } elseif (!empty($specs['FKClassName'])) {
                     if ($specs['FKClassName'] == $baoString) {
                         $entity[$fieldName] = (string) $entity2['id'];
                     } else {
                         $uniqueName = CRM_Utils_Array::value('uniqueName', $specs, $fieldName);
                         if (!empty($entity[$fieldName])) {
                             $resetFKTo = array($fieldName => $entity[$fieldName], $uniqueName => $entity[$fieldName]);
                         }
                         $entity[$fieldName] = (string) empty($entity2[$field]) ? CRM_Utils_Array::value($uniqueName, $entity2) : $entity2[$field];
                         //todo - there isn't always something set here - & our checking on unset values is limited
                         if (empty($entity[$field])) {
                             unset($entity[$field]);
                         }
                     }
                 } else {
                     $entity[$fieldName] = '6';
                 }
                 break;
             case CRM_Utils_Type::T_BOOLEAN:
                 // probably created with a 1
                 $entity[$fieldName] = '0';
                 break;
             case CRM_Utils_Type::T_FLOAT:
             case CRM_Utils_Type::T_MONEY:
                 $entity[$field] = '22.75';
                 break;
             case CRM_Utils_Type::T_URL:
                 $entity[$field] = 'warm.beer.com';
         }
         if (empty($specs['FKClassName']) && (!empty($specs['pseudoconstant']) || !empty($specs['options']))) {
             $options = CRM_Utils_Array::value('options', $specs, array());
             if (!$options) {
                 //eg. pdf_format id doesn't ship with any
                 if (isset($specs['pseudoconstant']['optionGroupName'])) {
                     $optionValue = $this->callAPISuccess('option_value', 'create', array('option_group_id' => $specs['pseudoconstant']['optionGroupName'], 'label' => 'new option value', 'sequential' => 1));
                     $optionValue = $optionValue['values'];
                     $keyColumn = CRM_Utils_Array::value('keyColumn', $specs['pseudoconstant'], 'value');
                     $options[$optionValue[0][$keyColumn]] = 'new option value';
                 }
             }
             $entity[$field] = array_rand($options);
         }
         if (!empty($specs['FKClassName']) && !empty($specs['pseudoconstant'])) {
             // in the weird situation where a field has both an fk and pseudoconstant defined,
             // e.g. campaign_id field, need to flush caches.
             // FIXME: Why doesn't creating a campaign clear caches?
             civicrm_api3($entityName, 'getfields', array('cache_clear' => 1));
         }
         $updateParams = array('id' => $entity['id'], $field => isset($entity[$field]) ? $entity[$field] : NULL);
         if (isset($updateParams['financial_type_id']) && in_array($entityName, array('Grant'))) {
             //api has special handling on these 2 fields for backward compatibility reasons
             $entity['contribution_type_id'] = $updateParams['financial_type_id'];
         }
         if (!empty($specs['uniqueName'])) {
             $entity[$specs['uniqueName']] = $entity[$specs['name']];
         }
         $update = $this->callAPISuccess($entityName, 'create', $updateParams);
         $checkParams = array('id' => $entity['id'], 'sequential' => 1, 'return' => $return, 'options' => array('sort' => 'id DESC', 'limit' => 2));
         $checkEntity = $this->callAPISuccess($entityName, 'getsingle', $checkParams);
         $this->assertAPIArrayComparison($entity, $checkEntity, array(), "checking if {$fieldName} was correctly updated\n" . print_r(array('update-params' => $updateParams, 'update-result' => $update, 'getsingle-params' => $checkParams, 'getsingle-result' => $checkEntity, 'expected entity' => $entity), TRUE));
         if ($resetFKTo) {
             //reset the foreign key fields because otherwise our cleanup routine fails & some other unexpected stuff can kick in
             $entity = array_merge($entity, $resetFKTo);
             $updateParams = array_merge($updateParams, $resetFKTo);
             $this->callAPISuccess($entityName, 'create', $updateParams);
             if (isset($updateParams['financial_type_id']) && in_array($entityName, array('Grant'))) {
                 //api has special handling on these 2 fields for backward compatibility reasons
                 $entity['contribution_type_id'] = $updateParams['financial_type_id'];
             }
         }
     }
     $baoObj->free();
 }
Example #10
0
 /**
  * Return an item that could not be processed.
  *
  * @param CRM_Core_DAO $dao
  *   The item returned by claimItem.
  */
 public function releaseItem($dao)
 {
     $sql = "UPDATE civicrm_queue_item SET release_time = NULL WHERE id = %1";
     $params = array(1 => array($dao->id, 'Integer'));
     CRM_Core_DAO::executeQuery($sql, $params);
     $dao->free();
 }
Example #11
0
 /**
  * This is a test to check if setting fields one at a time alters other fields.
  *
  * Issues Hit so far =
  * 1) Currency keeps getting reset to USD -  BUT this may be the only enabled currency
  *  - in which case it is valid
  * 2)
  */
 public function testCreateAutoGrant()
 {
     $entityName = $this->_entity;
     $baoString = 'CRM_Grant_BAO_Grant';
     $fields = $this->callAPISuccess($entityName, 'getfields', array('action' => 'create'));
     $fields = $fields['values'];
     $return = array_keys($fields);
     $baoObj = new CRM_Core_DAO();
     $baoObj->createTestObject($baoString, array('currency' => 'USD'), 2, 0);
     $getentities = $this->callAPISuccess($entityName, 'get', array('sequential' => 1, 'return' => $return));
     // lets use first rather than assume only one exists
     $entity = $getentities['values'][0];
     $entity2 = $getentities['values'][1];
     foreach ($fields as $field => $specs) {
         if ($field == 'currency' || $field == 'id') {
             continue;
         }
         switch ($specs['type']) {
             case CRM_Utils_Type::T_DATE:
             case CRM_Utils_Type::T_TIMESTAMP:
                 $entity[$field] = '2012-05-20';
                 break;
             case CRM_Utils_Type::T_STRING:
             case CRM_Utils_Type::T_BLOB:
             case CRM_Utils_Type::T_MEDIUMBLOB:
             case CRM_Utils_Type::T_TEXT:
             case CRM_Utils_Type::T_LONGTEXT:
             case CRM_Utils_Type::T_EMAIL:
                 $entity[$field] = 'New String';
                 break;
             case CRM_Utils_Type::T_INT:
                 // probably created with a 1
                 $entity[$field] = 2;
                 if (!empty($specs['FKClassName'])) {
                     $entity[$field] = empty($entity2[$field]) ? $entity2[$specs]['uniqueName'] : $entity2[$field];
                 }
                 break;
             case CRM_Utils_Type::T_BOOLEAN:
                 // probably created with a 1
                 $entity[$field] = 0;
                 break;
             case CRM_Utils_Type::T_FLOAT:
             case CRM_Utils_Type::T_MONEY:
                 $entity[$field] = 222;
                 break;
             case CRM_Utils_Type::T_URL:
                 $entity[$field] = 'warm.beer.com';
         }
         $updateParams = array('id' => $entity['id'], $field => $entity[$field], 'debug' => 1);
         $update = $this->callAPISuccess($entityName, 'create', $updateParams);
         $this->assertAPISuccess($update, "setting {$field} to {$entity[$field]} in line " . __LINE__);
         $checkParams = array('id' => $entity['id'], 'sequential' => 1);
         $checkEntity = $this->callAPISuccess($entityName, 'getsingle', $checkParams);
         $this->assertAPIArrayComparison((array) $entity, $checkEntity);
     }
     $baoObj->deleteTestObjects($baoString);
     $baoObj->free();
 }
 /**
  * There's probably a better way to do this.
  */
 public static function runSqlReturnAffectedRows($sql, $params = array())
 {
     $dao = new CRM_Core_DAO();
     $q = CRM_Core_DAO::composeQuery($sql, $params);
     $result = $dao->query($q);
     if (is_a($result, 'DB_Error')) {
         throw new Exception($result->message . "\n" . $result->userinfo);
     }
     $dao->free();
     return $result;
 }