Convert Dummy payment processor to use doPayment function
[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 * @param array|PropertyBag $params
59 *
60 * @param string $component
61 *
62 * @return array
63 * Result array (containing at least the key payment_status_id)
64 *
65 * @throws \Civi\Payment\Exception\PaymentProcessorException
66 */
67 public function doPayment(&$params, $component = 'contribute') {
68 $this->_component = $component;
69 $statuses = CRM_Contribute_BAO_Contribution::buildOptions('contribution_status_id', 'validate');
70
71 $propertyBag = PropertyBag::cast($params);
72
73 // If we have a $0 amount, skip call to processor and set payment_status to Completed.
74 // Conceivably a processor might override this - perhaps for setting up a token - but we don't
75 // have an example of that at the mome.
76 if ($propertyBag->getAmount() == 0) {
77 $result['payment_status_id'] = array_search('Completed', $statuses);
78 $result['payment_status'] = 'Completed';
79 return $result;
80 }
81
82 // Invoke hook_civicrm_paymentProcessor
83 // In Dummy's case, there is no translation of parameters into
84 // the back-end's canonical set of parameters. But if a processor
85 // does this, it needs to invoke this hook after it has done translation,
86 // but before it actually starts talking to its proprietary back-end.
87 if ($propertyBag->getIsRecur()) {
88 $throwAnENoticeIfNotSetAsTheseAreRequired = $propertyBag->getRecurFrequencyInterval() . $propertyBag->getRecurFrequencyUnit();
89 }
90 // no translation in Dummy processor
91 CRM_Utils_Hook::alterPaymentProcessorParams($this, $params, $propertyBag);
92 // This means we can test failing transactions by setting a past year in expiry. A full expiry check would
93 // be more complete.
94 if (!empty($params['credit_card_exp_date']['Y']) && date('Y') >
95 CRM_Core_Payment_Form::getCreditCardExpirationYear($params)) {
96 throw new PaymentProcessorException(ts('Invalid expiry date'));
97 }
98
99 if (!empty($this->_doDirectPaymentResult)) {
100 $result = $this->_doDirectPaymentResult;
101 if (CRM_Utils_Array::value('payment_status_id', $result) === 'failed') {
102 throw new PaymentProcessorException($result['message'] ?? 'failed');
103 }
104 $result['trxn_id'] = array_shift($this->_doDirectPaymentResult['trxn_id']);
105 return $result;
106 }
107
108 $result['trxn_id'] = $this->getTrxnID();
109
110 // Add a fee_amount so we can make sure fees are handled properly in underlying classes.
111 $result['fee_amount'] = 1.50;
112 $result['description'] = $this->getPaymentDescription($params);
113
114 if (!isset($result['payment_status_id'])) {
115 if (!empty($propertyBag->getIsRecur())) {
116 // See comment block.
117 $result['payment_status_id'] = array_search('Pending', $statuses);
118 $result['payment_status'] = 'Pending';
119 }
120 else {
121 $result['payment_status_id'] = array_search('Completed', $statuses);
122 $result['payment_status'] = 'Completed';
123 }
124 }
125
126 // We shouldn't do this but it saves us changing the `testPayNowPayment` test to actually test the contribution
127 // like it should.
128 $result = array_merge($params, $result);
129
130 return $result;
131 }
132
133 /**
134 * Does this payment processor support refund?
135 *
136 * @return bool
137 */
138 public function supportsRefund() {
139 return TRUE;
140 }
141
142 /**
143 * Supports altering future start dates.
144 *
145 * @return bool
146 */
147 public function supportsFutureRecurStartDate() {
148 return TRUE;
149 }
150
151 /**
152 * Submit a refund payment
153 *
154 * @throws \Civi\Payment\Exception\PaymentProcessorException
155 *
156 * @param array $params
157 * Assoc array of input parameters for this transaction.
158 */
159 public function doRefund(&$params) {}
160
161 /**
162 * This function checks to see if we have the right config values.
163 *
164 * @return string
165 * the error message if any
166 */
167 public function checkConfig() {
168 return NULL;
169 }
170
171 /**
172 * Get an array of the fields that can be edited on the recurring contribution.
173 *
174 * Some payment processors support editing the amount and other scheduling details of recurring payments, especially
175 * those which use tokens. Others are fixed. This function allows the processor to return an array of the fields that
176 * can be updated from the contribution recur edit screen.
177 *
178 * The fields are likely to be a subset of these
179 * - 'amount',
180 * - 'installments',
181 * - 'frequency_interval',
182 * - 'frequency_unit',
183 * - 'cycle_day',
184 * - 'next_sched_contribution_date',
185 * - 'end_date',
186 * - 'failure_retry_day',
187 *
188 * The form does not restrict which fields from the contribution_recur table can be added (although if the html_type
189 * metadata is not defined in the xml for the field it will cause an error.
190 *
191 * Open question - would it make sense to return membership_id in this - which is sometimes editable and is on that
192 * form (UpdateSubscription).
193 *
194 * @return array
195 */
196 public function getEditableRecurringScheduleFields() {
197 return ['amount', 'next_sched_contribution_date'];
198 }
199
200 /**
201 * Does this processor support cancelling recurring contributions through code.
202 *
203 * If the processor returns true it must be possible to take action from within CiviCRM
204 * that will result in no further payments being processed. In the case of token processors (e.g
205 * IATS, eWay) updating the contribution_recur table is probably sufficient.
206 *
207 * @return bool
208 */
209 protected function supportsCancelRecurring() {
210 return TRUE;
211 }
212
213 /**
214 * Cancel a recurring subscription.
215 *
216 * Payment processor classes should override this rather than implementing cancelSubscription.
217 *
218 * A PaymentProcessorException should be thrown if the update of the contribution_recur
219 * record should not proceed (in many cases this function does nothing
220 * as the payment processor does not need to take any action & this should silently
221 * proceed. Note the form layer will only call this after calling
222 * $processor->supports('cancelRecurring');
223 *
224 * @param \Civi\Payment\PropertyBag $propertyBag
225 *
226 * @return array
227 *
228 * @throws \Civi\Payment\Exception\PaymentProcessorException
229 */
230 public function doCancelRecurring(PropertyBag $propertyBag) {
231 return ['message' => ts('Recurring contribution cancelled')];
232 }
233
234 /**
235 * Get a value for the transaction ID.
236 *
237 * Value is made up of the max existing value + a random string.
238 *
239 * Note the random string is likely a historical workaround.
240 *
241 * @return string
242 */
243 protected function getTrxnID() {
244 $string = $this->_mode;
245 $trxn_id = CRM_Core_DAO::singleValueQuery("SELECT MAX(trxn_id) FROM civicrm_contribution WHERE trxn_id LIKE '{$string}_%'");
246 $trxn_id = str_replace($string, '', $trxn_id);
247 $trxn_id = (int) $trxn_id + 1;
248 return $string . '_' . $trxn_id . '_' . uniqid();
249 }
250
251 }