protected function processCreditCardCustomer($values) { // generate another recurring contribution, matching our recurring template with submitted value $total_amount = $values['amount']; $contribution_template = _iats_civicrm_getContributionTemplate(array('contribution_recur_id' => $values['crid'])); $contact_id = $values['cid']; $hash = md5(uniqid(rand(), true)); $contribution_recur_id = $values['crid']; $payment_processor_id = $values['paymentProcessorId']; $type = _iats_civicrm_is_iats($payment_processor_id); $subtype = substr($type, 11); $source = "iATS Payments {$subtype} Recurring Contribution (id={$contribution_recur_id})"; $receive_date = date("YmdHis", time()); // i.e. now $contribution = array('version' => 3, 'contact_id' => $contact_id, 'receive_date' => $receive_date, 'total_amount' => $total_amount, 'contribution_recur_id' => $contribution_recur_id, 'invoice_id' => $hash, 'source' => $source, 'contribution_status_id' => 2, 'payment_processor' => $payment_processor_id, 'is_test' => $values['is_test']); foreach (array('payment_instrument_id', 'currency', 'financial_type_id') as $key) { $contribution[$key] = $contribution_template[$key]; } $options = array('is_email_receipt' => 0, 'customer_code' => $values['customerCode'], 'subtype' => $subtype); // now all the hard work in this function, recycled from the original recurring payment job $result = _iats_process_contribution_payment($contribution, $options); return $result; }
/** * hook_civicrm_pre * * Handle special cases of creating contribution (regular and recurring) records when using IATS Payments * * 1. CiviCRM assumes all recurring contributions need to be confirmed using the IPN mechanism. This is not true for iATS recurring contributions. * So when creating a contribution that is part of a recurring series, test for status = 2, and set to status = 1 instead, unless we're using the fixed day feature * Do this only for the initial contribution record. * The (subsequent) recurring contributions' status id is set explicitly in the job that creates it, this modification breaks that process. * * 2. For ACH/EFT, we also have the opposite problem - all contributions will need to verified by iATS and only later set to status success or * failed via the acheft verify job. We also want to modify the payment instrument from CC to ACH/EFT * * TODO: update this code with constants for the various id values of 1 and 2. * TODO: CiviCRM should have nicer ways to handle this. */ function iats_civicrm_pre($op, $objectName, $objectId, &$params) { // since this function gets called a lot, quickly determine if I care about the record being created if ('create' == $op && ('Contribution' == $objectName || 'ContributionRecur' == $objectName) && !empty($params['contribution_status_id'])) { // watchdog('iats_civicrm','hook_civicrm_pre for Contribution <pre>@params</pre>',array('@params' => print_r($params)); // figure out the payment processor id, not nice $version = CRM_Utils_System::version(); $payment_processor_id = 'ContributionRecur' == $objectName ? $params['payment_processor_id'] : (!empty($params['payment_processor']) ? $params['payment_processor'] : (!empty($params['contribution_recur_id']) ? _iats_civicrm_get_payment_processor_id($params['contribution_recur_id']) : 0)); if ($type = _iats_civicrm_is_iats($payment_processor_id)) { $settings = CRM_Core_BAO_Setting::getItem('iATS Payments Extension', 'iats_settings'); $allow_days = empty($settings['days']) ? array('-1') : $settings['days']; switch ($type . $objectName) { case 'iATSServiceContribution': // cc contribution, test if it's been set to status 2 on a recurring contribution // cc contribution, test if it's been set to status 2 on a recurring contribution case 'iATSServiceSWIPEContribution': // for civi version before 4.6.6, we had to force the status to 1 if (2 == $params['contribution_status_id'] && !empty($params['contribution_recur_id']) && max($allow_days) <= 0 && version_compare($version, '4.6.6') < 0) { // but only for the first one $count = civicrm_api('Contribution', 'getcount', array('version' => 3, 'contribution_recur_id' => $params['contribution_recur_id'])); if (is_array($count) && empty($count['result']) || empty($count)) { // watchdog('iats_civicrm','hook_civicrm_pre updating status_id for objectName @id, count <pre>!count</pre>, params <pre>!params</pre>, ',array('@id' => $objectName, '!count' => print_r($count,TRUE),'!params' => print_r($params,TRUE))); $params['contribution_status_id'] = 1; } } break; case 'iATSServiceContributionRecur': // cc/swipe/ACHEFT recurring contribution record // cc/swipe/ACHEFT recurring contribution record case 'iATSServiceSWIPEContributionRecur': case 'iATSServiceACHEFTContributionRecur': // the next scheduled contribution date field name is civicrm version dependent $field_name = _iats_civicrm_nscd_fid(); // when creating a recurring contribution record via a civicrm contribution form // we've already taken the first payment, so calculate the next one (core assumes the intial contribution is pending) // we set this to 'in-progress' even for ACH/EFT if the first one hasn't been verified, because we still want to be attempting later ones // this condition helps avoid mangling records being imported from a csv file if (5 != $params['contribution_status_id'] && empty($params[$field_name])) { $params['contribution_status_id'] = 5; $params['trxn_id'] = NULL; // civi wants to put the returned trxn_id in here $next = strtotime('+' . $params['frequency_interval'] . ' ' . $params['frequency_unit']); $params[$field_name] = date('YmdHis', $next); } if ($type == 'iATSServiceACHEFT') { // fix the payment type for ACH/EFT $params['payment_instrument_id'] = 2; } break; case 'iATSServiceACHEFTContribution': // ach/eft contribution: update the payment instrument $params['payment_instrument_id'] = 2; // and push the status to 2 if civicrm thinks it's 1, i.e. for one-time contributions // in other words, never create ach/eft contributions as complete, always push back to pending and verify if ($params['contribution_status_id'] == 1) { $params['contribution_status_id'] = 2; } break; case 'iATSServiceUKDDContribution': // UK DD contribution: update the payment instrument, fix the receive date $params['payment_instrument_id'] = 2; if ($start_date = strtotime($_POST['payer_validate_start_date'])) { $params['receive_date'] = date('Ymd', $start_date) . '120000'; } break; case 'iATSServiceUKDDContributionRecur': // UK DD recurring contribution record: update the payment instrument, fix the start_date $params['payment_instrument_id'] = 2; if ($start_date = strtotime($_POST['payer_validate_start_date'])) { $params['start_date'] = date('Ymd', $start_date) . '120000'; } break; } if ($type != 'iATSServiceUKDD' && $objectName == 'Contribution') { // new, non-UKDD contribution records in a schedule are forced to comply with any restrictions if (0 < max($allow_days)) { $from_time = _iats_contributionrecur_next(strtotime($params['receive_date']), $allow_days); $params['receive_date'] = date('Ymd', $from_time) . '030000'; } } } // watchdog('iats_civicrm','ignoring hook_civicrm_pre for objectName @id',array('@id' => $objectName)); } // if I've set fixed monthly recurring dates, force any iats (non uk dd) recurring contribution schedule records to comply // it's a bit draconian, and you likely want to give administrators the ability to modify these schedules // this is separate from the above because I want to deal with both create and edit possibilities if ('ContributionRecur' == $objectName && ('create' == $op || 'edit' == $op)) { if ($type = _iats_civicrm_is_iats($params['payment_processor_id'])) { if ($type != 'iATSServiceUKDD' && !empty($params['next_sched_contribution_date'])) { $settings = CRM_Core_BAO_Setting::getItem('iATS Payments Extension', 'iats_settings'); $allow_days = empty($settings['days']) ? array('-1') : $settings['days']; if (0 < max($allow_days)) { // force one of the fixed days, and set the cycle_day at the same time $init_time = 'create' == $op ? time() : strtotime($params['next_sched_contribution_date']); $from_time = _iats_contributionrecur_next($init_time, $allow_days); $params['next_sched_contribution_date'] = date('YmdHis', $from_time); $params['cycle_day'] = date('j', $from_time); // day of month without leading 0 } } if (empty($params['installments'])) { // fix a civi bug while I'm here $params['installments'] = '0'; } } } }
/** * hook_civicrm_pre * * Handle special cases of creating contribution (regular and recurring) records when using IATS Payments * * 1. CiviCRM assumes all recurring contributions need to be confirmed using the IPN mechanism. This is not true for iATS recurring contributions. * So when creating a contribution that is part of a recurring series, test for status = 2, and set to status = 1 instead. * Do this only for the initial contribution record. * The (subsequent) recurring contributions' status id is set explicitly in the job that creates it, this modification breaks that process. * * 2. For ACH/EFT, we also have the opposite problem - all contributions will need to verified by iATS and only later set to status success or * failed via the acheft verify job. We also want to modify the payment instrument from CC to ACH/EFT * * TODO: update this code with constants for the various id values of 1 and 2. * TODO: CiviCRM should have nicer ways to handle this. */ function iats_civicrm_pre($op, $objectName, $objectId, &$params) { // since this function gets called a lot, quickly determine if I care about the record being created if ('create' == $op && ('Contribution' == $objectName || 'ContributionRecur' == $objectName) && !empty($params['contribution_status_id'])) { // watchdog('iats_civicrm','hook_civicrm_pre for Contribution <pre>@params</pre>',array('@params' => print_r($params)); // figure out the payment processor id, not nice $version = CRM_Utils_System::version(); $payment_processor_id = 'ContributionRecur' == $objectName ? $params['payment_processor_id'] : (!empty($params['payment_processor']) ? $params['payment_processor'] : (!empty($params['contribution_recur_id']) ? _iats_civicrm_get_payment_processor_id($params['contribution_recur_id']) : 0)); if ($type = _iats_civicrm_is_iats($payment_processor_id)) { switch ($type . $objectName) { case 'iATSServiceContribution': // cc contribution, test if it's been set to status 2 on a recurring contribution // cc contribution, test if it's been set to status 2 on a recurring contribution case 'iATSServiceSWIPEContribution': // for civi version before 4.6.6, we had to force the status to 1 if (2 == $params['contribution_status_id'] && !empty($params['contribution_recur_id']) && version_compare($version, '4.6.6') < 0) { // but only for the first one $count = civicrm_api('Contribution', 'getcount', array('version' => 3, 'contribution_recur_id' => $params['contribution_recur_id'])); if (is_array($count) && empty($count['result']) || empty($count)) { // watchdog('iats_civicrm','hook_civicrm_pre updating status_id for objectName @id, count <pre>!count</pre>, params <pre>!params</pre>, ',array('@id' => $objectName, '!count' => print_r($count,TRUE),'!params' => print_r($params,TRUE))); $params['contribution_status_id'] = 1; } } break; case 'iATSServiceContributionRecur': // cc/swipe/ACHEFT recurring contribution record // cc/swipe/ACHEFT recurring contribution record case 'iATSServiceSWIPEContributionRecur': case 'iATSServiceACHEFTContributionRecur': // the next scheduled contribution date field name is civicrm version dependent $field_name = _iats_civicrm_nscd_fid(); // when creating a recurring contribution record via a civicrm contribution form // we've already taken the first payment, so calculate the next one (core assumes the intial contribution is pending) // we set this to 'in-progress' even for ACH/EFT if the first one hasn't been verified, because we still want to be attempting later ones // this condition helps avoid mangling records being imported from a csv file if (5 != $params['contribution_status_id'] && empty($params[$field_name])) { $params['contribution_status_id'] = 5; $params['trxn_id'] = NULL; $next = strtotime('+' . $params['frequency_interval'] . ' ' . $params['frequency_unit']); $params[$field_name] = date('YmdHis', $next); } if ($type == 'iATSServiceACHEFT') { // fix the payment type for ACH/EFT $params['payment_instrument_id'] = 2; } break; case 'iATSServiceACHEFTContribution': // ach/eft contribution: update the payment instrument $params['payment_instrument_id'] = 2; // and push the status to 2 if civicrm thinks it's 1, i.e. for one-time contributions // in other words, never create ach/eft contributions as complete, always push back to pending and verify if ($params['contribution_status_id'] == 1) { $params['contribution_status_id'] = 2; } break; case 'iATSServiceUKDDContribution': // UK DD contribution: update the payment instrument, fix the receive date $params['payment_instrument_id'] = 2; if ($start_date = strtotime($_POST['payer_validate_start_date'])) { $params['receive_date'] = date('Ymd', $start_date) . '120000'; } break; case 'iATSServiceUKDDContributionRecur': // UK DD recurring contribution record: update the payment instrument, fix the start_date $params['payment_instrument_id'] = 2; if ($start_date = strtotime($_POST['payer_validate_start_date'])) { $params['start_date'] = date('Ymd', $start_date) . '120000'; } break; } } // watchdog('iats_civicrm','ignoring hook_civicrm_pre for objectName @id',array('@id' => $objectName)); } }