PageRenderTime 28ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 0ms

/sites/all/modules/contrib/civicrm/ext/iatspayments/api/v3/Job/Iatsreport.php

https://gitlab.com/virtualrealms/d7civicrm
PHP | 211 lines | 145 code | 7 blank | 59 comment | 15 complexity | 601203e9c39c9444619d12a96fd60680 MD5 | raw file
  1. <?php
  2. /**
  3. * Job.IatsReport API specification (optional)
  4. *
  5. * Pull in the iATS transaction journal and save it in the corresponding table
  6. * for local access for easier verification, auditing and reporting.
  7. *
  8. * @param array $spec description of fields supported by this API call
  9. * @return void
  10. * @see http://wiki.civicrm.org/confluence/display/CRM/API+Architecture+Standards
  11. */
  12. function _civicrm_api3_job_iatsreport_spec(&$spec) {
  13. // no arguments
  14. // TODO: configure for a date range, report, etc.
  15. }
  16. /**
  17. * Job.IatsReport API
  18. *
  19. * Fetch all recent transactions from iATS for the purposes of auditing (in separate jobs).
  20. * This addresses multiple needs:
  21. * 1. Verify incomplete ACH/EFT contributions.
  22. * 2. Verify recent contributions that went through but weren't reported to CiviCRM due to unexpected connection/code breakage.
  23. * 3. Input recurring contributions managed by iATS
  24. * 4. Input one-time contributions that did not go through CiviCRM
  25. * 5. Audit for remote changes in iATS.
  26. *
  27. * @param array $params
  28. * @return array API result descriptor
  29. * @see civicrm_api3_create_success
  30. * @see civicrm_api3_create_error
  31. * @throws API_Exception
  32. */
  33. function civicrm_api3_job_iatsreport($params) {
  34. /* get a list of all active/non-test iATS payment processors of any type, quit if there are none */
  35. /* We'll make sure they are unique from iATS point of view (i.e. distinct agent codes = username) */
  36. try {
  37. $result = civicrm_api3('PaymentProcessor', 'get', array(
  38. 'sequential' => 1,
  39. 'class_name' => array('LIKE' => 'Payment_iATSService%'),
  40. 'is_active' => 1,
  41. 'is_test' => 0,
  42. ));
  43. }
  44. catch (CiviCRM_API3_Exception $e) {
  45. throw new API_Exception('Unexpected error getting payment processors: ' . $e->getMessage()); // . "\n" . $e->getTraceAsString());
  46. }
  47. if (empty($result['values'])) {
  48. return;
  49. }
  50. $payment_processors = array();
  51. foreach ($result['values'] as $payment_processor) {
  52. $user_name = $payment_processor['user_name'];
  53. $type = $payment_processor['payment_type']; // 1 for cc, 2 for ach/eft
  54. $id = $payment_processor['id'];
  55. if (empty($payment_processors[$user_name])) {
  56. $payment_processors[$user_name] = array();
  57. }
  58. if (empty($payment_processors[$user_name][$type])) {
  59. $payment_processors[$user_name][$type] = array();
  60. }
  61. $payment_processors[$user_name][$type][$id] = $payment_processor;
  62. }
  63. // CRM_Core_Error::debug_var('Payment Processors', $payment_processors);
  64. // get the settings: TODO allow more detailed configuration of which transactions to import?
  65. $iats_settings = CRM_Core_BAO_Setting::getItem('iATS Payments Extension', 'iats_settings');
  66. // I also use the setttings to keep track of the last time I imported journal data from iATS.
  67. $iats_journal = CRM_Core_BAO_Setting::getItem('iATS Payments Extension', 'iats_journal');
  68. foreach (array('quick', 'recur', 'series') as $setting) {
  69. $import[$setting] = empty($iats_settings['import_' . $setting]) ? 0 : 1;
  70. }
  71. require_once "CRM/iATS/iATSService.php";
  72. // an array of types => methods => payment status of the records retrieved
  73. $process_methods = array(
  74. 1 => array('cc_journal_csv' => 1, 'cc_payment_box_journal_csv' => 1, 'cc_payment_box_reject_csv' => 4),
  75. 2 => array('acheft_journal_csv' => 1, 'acheft_payment_box_journal_csv' => 1, 'acheft_payment_box_reject_csv' => 4),
  76. );
  77. /* initialize some values so I can report at the end */
  78. // count the number of records from each iats account analysed, and the number of each kind found ('action')
  79. $processed = array();
  80. // save all my api result error messages as well
  81. $error_log = array();
  82. foreach ($payment_processors as $user_name => $payment_processors_per_user) {
  83. $processed[$user_name] = array();
  84. foreach ($payment_processors_per_user as $type => $payment_processors_per_user_type) {
  85. $processed[$user_name][$type] = array();
  86. // we might have multiple payment processors by type e.g. SWIPE or separate codes for
  87. // one-time and recurring contributions, I only want to process once per user_name + type
  88. $payment_processor = reset($payment_processors_per_user_type);
  89. $process_methods_per_type = $process_methods[$type];
  90. $iats_service_params = array('type' => 'report', 'iats_domain' => parse_url($payment_processor['url_site'], PHP_URL_HOST)); // + $iats_service_params;
  91. /* the is_test below should always be 0, but I'm leaving it in, in case eventually we want to be verifying tests */
  92. $credentials = iATS_Service_Request::credentials($payment_processor['id'], $payment_processor['is_test']);
  93. foreach ($process_methods_per_type as $method => $payment_status_id) {
  94. // initialize my counts
  95. $processed[$user_name][$type][$method] = 0;
  96. // watchdog('civicrm_iatspayments_com', 'pp: <pre>!pp</pre>', array('!pp' => print_r($payment_processor,TRUE)), WATCHDOG_NOTICE);
  97. /* get approvals from yesterday, approvals from previous days, and then rejections for this payment processor */
  98. /* we're going to assume that all the payment_processors_per_type are using the same server */
  99. $iats_service_params['method'] = $method;
  100. $iats = new iATS_Service_Request($iats_service_params);
  101. // For some methods, I only want to check once per day.
  102. $skip_method = FALSE;
  103. $journal_setting_key = 'last_update_' . $method;
  104. switch ($method) {
  105. case 'acheft_journal_csv': // special case to get today's transactions, so we're as real-time as we can be
  106. case 'cc_journal_csv':
  107. $request = array(
  108. 'date' => date('Y-m-d') . 'T23:59:59+00:00',
  109. 'customerIPAddress' => (function_exists('ip_address') ? ip_address() : $_SERVER['REMOTE_ADDR']),
  110. );
  111. break;
  112. default:
  113. // box journals (approvals and rejections) only go up to the end of yesterday
  114. $request = array(
  115. 'startIndex' => 0,
  116. 'endIndex' => 1000,
  117. 'toDate' => date('Y-m-d', strtotime('-1 day')) . 'T23:59:59+00:00',
  118. 'customerIPAddress' => (function_exists('ip_address') ? ip_address() : $_SERVER['REMOTE_ADDR']),
  119. );
  120. // Calculate how far back I want to go, default 2 days ago.
  121. $fromDate = strtotime('-2 days');
  122. // Check when I last downloaded this box journal
  123. if (!empty($iats_journal[$journal_setting_key])) {
  124. // If I've already done this today, don't do it again.
  125. if (0 === strpos($iats_journal[$journal_setting_key], date('Y-m-d'))) {
  126. $skip_method = TRUE;
  127. }
  128. else {
  129. // Make sure I fill in any gaps if this cron hasn't run for a while, but no more than a month
  130. $fromDate = min(strtotime($iats_journal[$journal_setting_key]), strtotime('-2 days'));
  131. $fromDate = max($fromDate, strtotime('-30 days'));
  132. }
  133. }
  134. else {
  135. // If I've cleared the settings, then go back a month of data.
  136. $fromDate = strtotime('-30 days');
  137. }
  138. // reset the request fromDate, from the beginning of fromDate's day.
  139. $request['fromDate'] = date('Y-m-d', $fromDate) . 'T00:00:00+00:00';
  140. break;
  141. }
  142. if (!$skip_method) {
  143. $iats_journal[$journal_setting_key] = date('Y-m-d H:i:s');
  144. // make the soap request, should return a csv file
  145. $response = $iats->request($credentials, $request);
  146. // use my iats object to parse the result into an array of transaction ojects
  147. $transactions = $iats->getCSV($response, $method);
  148. // for the acheft journal, I also pull the previous 4 days and append, a bit of a hack.
  149. if ('acheft_journal_csv' == $method) {
  150. for ($days_before = -1; $days_before > -5; $days_before--) {
  151. $request['date'] = date('Y-m-d', strtotime($days_before . ' day')) . 'T23:59:59+00:00';
  152. $response = $iats->request($credentials, $request);
  153. $transactions = array_merge($transactions, $iats->getCSV($response, $method));
  154. }
  155. }
  156. // CRM_Core_Error::debug_var($method, $transactions);
  157. foreach ($transactions as $transaction) {
  158. try {
  159. $t = get_object_vars($transaction);
  160. $t['status_id'] = $payment_status_id;
  161. // A few more hacks for the one day journals
  162. switch ($method) {
  163. case 'acheft_journal_csv':
  164. $t['data']['Method of Payment'] = 'ACHEFT';
  165. $t['data']['Client Code'] = $credentials['agentCode'];
  166. break;
  167. case 'cc_journal_csv':
  168. $t['data']['Method of Payment'] = $t['data']['CCType'];
  169. $t['data']['Client Code'] = $credentials['agentCode'];
  170. break;
  171. }
  172. civicrm_api3('IatsPayments', 'journal', $t);
  173. $processed[$user_name][$type][$method]++;
  174. }
  175. catch (CiviCRM_API3_Exception $e) {
  176. $error_log[] = $e->getMessage();
  177. }
  178. }
  179. }
  180. }
  181. }
  182. }
  183. CRM_Core_BAO_Setting::setItem($iats_journal, 'iATS Payments Extension', 'iats_journal');
  184. // watchdog('civicrm_iatspayments_com', 'found: <pre>!found</pre>', array('!found' => print_r($processed,TRUE)), WATCHDOG_NOTICE);
  185. $message = '';
  186. foreach ($processed as $user_name => $p) {
  187. foreach ($p as $type => $ps) {
  188. $prefix = ($type == 1) ? 'cc' : 'acheft';
  189. $results
  190. = array(
  191. 1 => $user_name,
  192. 2 => $prefix,
  193. 3 => $ps[$prefix . '_journal_csv'],
  194. 4 => $ps[$prefix . '_payment_box_journal_csv'],
  195. 5 => $ps[$prefix . '_payment_box_reject_csv'],
  196. );
  197. $message .= '<br />' . ts('For account %1, type %2, processed %3 approvals from the one-day journals, and %4 approval and %5 rejection records from previous days using the box journals.', $results);
  198. }
  199. }
  200. if (count($error_log) > 0) {
  201. return civicrm_api3_create_error($message . '</br />' . implode('<br />', $error_log));
  202. }
  203. return civicrm_api3_create_success($message);
  204. }