Add try catch to main loops on core ipn classes
[civicrm-core.git] / CRM / Core / Payment / Dummy.php
1 <?php
2 /*
3 * Copyright (C) 2007
4 * Licensed to CiviCRM under the Academic Free License version 3.0.
5 *
6 * Written and contributed by Ideal Solution, LLC (http://www.idealso.com)
7 *
8 */
9
10 /**
11 *
12 * @package CRM
13 * @author Marshal Newrock <marshal@idealso.com>
14 */
15
16 use Civi\Payment\Exception\PaymentProcessorException;
17 use Civi\Payment\PropertyBag;
18
19 /**
20 * Dummy payment processor
21 */
22 class CRM_Core_Payment_Dummy extends CRM_Core_Payment {
23 protected $_mode;
24
25 protected $_params = [];
26 protected $_doDirectPaymentResult = [];
27
28 /**
29 * Set result from do Direct Payment for test purposes.
30 *
31 * @param array $doDirectPaymentResult
32 * Result to be returned from test.
33 */
34 public function setDoDirectPaymentResult($doDirectPaymentResult) {
35 $this->_doDirectPaymentResult = $doDirectPaymentResult;
36 if (empty($this->_doDirectPaymentResult['trxn_id'])) {
37 $this->_doDirectPaymentResult['trxn_id'] = [];
38 }
39 else {
40 $this->_doDirectPaymentResult['trxn_id'] = (array) $doDirectPaymentResult['trxn_id'];
41 }
42 }
43
44 /**
45 * Constructor.
46 *
47 * @param string $mode
48 * The mode of operation: live or test.
49 *
50 * @param array $paymentProcessor
51 */
52 public function __construct($mode, &$paymentProcessor) {
53 $this->_mode = $mode;
54 $this->_paymentProcessor = $paymentProcessor;
55 }
56
57 /**
58 * Submit a payment using Advanced Integration Method.
59 *
60 * @param array $params
61 * Assoc array of input parameters for this transaction.
62 *
63 * @return array
64 * the result in a nice formatted array (or an error object)
65 * @throws \Civi\Payment\Exception\PaymentProcessorException
66 */
67 public function doDirectPayment(&$params) {
68 $propertyBag = PropertyBag::cast($params);
69 // Invoke hook_civicrm_paymentProcessor
70 // In Dummy's case, there is no translation of parameters into
71 // the back-end's canonical set of parameters. But if a processor
72 // does this, it needs to invoke this hook after it has done translation,
73 // but before it actually starts talking to its proprietary back-end.
74 if ($propertyBag->getIsRecur()) {
75 $throwAnENoticeIfNotSetAsTheseAreRequired = $propertyBag->getRecurFrequencyInterval() . $propertyBag->getRecurFrequencyUnit();
76 }
77 // no translation in Dummy processor
78 CRM_Utils_Hook::alterPaymentProcessorParams($this,
79 $params,
80 $propertyBag
81 );
82 // This means we can test failing transactions by setting a past year in expiry. A full expiry check would
83 // be more complete.
84 if (!empty($params['credit_card_exp_date']['Y']) && date('Y') >
85 CRM_Core_Payment_Form::getCreditCardExpirationYear($params)) {
86 throw new PaymentProcessorException(ts('Invalid expiry date'));
87 }
88 //end of hook invocation
89 if (!empty($this->_doDirectPaymentResult)) {
90 $result = $this->_doDirectPaymentResult;
91 if (CRM_Utils_Array::value('payment_status_id', $result) === 'failed') {
92 throw new PaymentProcessorException($result['message'] ?? 'failed');
93 }
94 $result['trxn_id'] = array_shift($this->_doDirectPaymentResult['trxn_id']);
95 return $result;
96 }
97
98 $params['trxn_id'] = $this->getTrxnID();;
99
100 // Add a fee_amount so we can make sure fees are handled properly in underlying classes.
101 $params['fee_amount'] = 1.50;
102 $params['description'] = $this->getPaymentDescription($params);
103
104 return $params;
105 }
106
107 /**
108 * Does this payment processor support refund?
109 *
110 * @return bool
111 */
112 public function supportsRefund() {
113 return TRUE;
114 }
115
116 /**
117 * Supports altering future start dates.
118 *
119 * @return bool
120 */
121 public function supportsFutureRecurStartDate() {
122 return TRUE;
123 }
124
125 /**
126 * Submit a refund payment
127 *
128 * @throws \Civi\Payment\Exception\PaymentProcessorException
129 *
130 * @param array $params
131 * Assoc array of input parameters for this transaction.
132 */
133 public function doRefund(&$params) {}
134
135 /**
136 * This function checks to see if we have the right config values.
137 *
138 * @return string
139 * the error message if any
140 */
141 public function checkConfig() {
142 return NULL;
143 }
144
145 /**
146 * Get an array of the fields that can be edited on the recurring contribution.
147 *
148 * Some payment processors support editing the amount and other scheduling details of recurring payments, especially
149 * those which use tokens. Others are fixed. This function allows the processor to return an array of the fields that
150 * can be updated from the contribution recur edit screen.
151 *
152 * The fields are likely to be a subset of these
153 * - 'amount',
154 * - 'installments',
155 * - 'frequency_interval',
156 * - 'frequency_unit',
157 * - 'cycle_day',
158 * - 'next_sched_contribution_date',
159 * - 'end_date',
160 * - 'failure_retry_day',
161 *
162 * The form does not restrict which fields from the contribution_recur table can be added (although if the html_type
163 * metadata is not defined in the xml for the field it will cause an error.
164 *
165 * Open question - would it make sense to return membership_id in this - which is sometimes editable and is on that
166 * form (UpdateSubscription).
167 *
168 * @return array
169 */
170 public function getEditableRecurringScheduleFields() {
171 return ['amount', 'next_sched_contribution_date'];
172 }
173
174 /**
175 * Does this processor support cancelling recurring contributions through code.
176 *
177 * If the processor returns true it must be possible to take action from within CiviCRM
178 * that will result in no further payments being processed. In the case of token processors (e.g
179 * IATS, eWay) updating the contribution_recur table is probably sufficient.
180 *
181 * @return bool
182 */
183 protected function supportsCancelRecurring() {
184 return TRUE;
185 }
186
187 /**
188 * Cancel a recurring subscription.
189 *
190 * Payment processor classes should override this rather than implementing cancelSubscription.
191 *
192 * A PaymentProcessorException should be thrown if the update of the contribution_recur
193 * record should not proceed (in many cases this function does nothing
194 * as the payment processor does not need to take any action & this should silently
195 * proceed. Note the form layer will only call this after calling
196 * $processor->supports('cancelRecurring');
197 *
198 * @param \Civi\Payment\PropertyBag $propertyBag
199 *
200 * @return array
201 *
202 * @throws \Civi\Payment\Exception\PaymentProcessorException
203 */
204 public function doCancelRecurring(PropertyBag $propertyBag) {
205 return ['message' => ts('Recurring contribution cancelled')];
206 }
207
208 /**
209 * Get a value for the transaction ID.
210 *
211 * Value is made up of the max existing value + a random string.
212 *
213 * Note the random string is likely a historical workaround.
214 *
215 * @return string
216 */
217 protected function getTrxnID() {
218 $string = $this->_mode;
219 $trxn_id = CRM_Core_DAO::singleValueQuery("SELECT MAX(trxn_id) FROM civicrm_contribution WHERE trxn_id LIKE '{$string}_%'");
220 $trxn_id = str_replace($string, '', $trxn_id);
221 $trxn_id = (int) $trxn_id + 1;
222 return $string . '_' . $trxn_id . '_' . uniqid();
223 }
224
225 }