Merge pull request #16093 from civicrm/5.21
[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 * $Id: Dummy.php 45429 2013-02-06 22:11:18Z lobo $
15 */
16
17 use Civi\Payment\Exception\PaymentProcessorException;
18
19 /**
20 * Dummy payment processor
21 */
22 class CRM_Core_Payment_Dummy extends CRM_Core_Payment {
23 const CHARSET = 'iso-8859-1';
24
25 protected $_mode = NULL;
26
27 protected $_params = [];
28 protected $_doDirectPaymentResult = [];
29
30 /**
31 * Set result from do Direct Payment for test purposes.
32 *
33 * @param array $doDirectPaymentResult
34 * Result to be returned from test.
35 */
36 public function setDoDirectPaymentResult($doDirectPaymentResult) {
37 $this->_doDirectPaymentResult = $doDirectPaymentResult;
38 if (empty($this->_doDirectPaymentResult['trxn_id'])) {
39 $this->_doDirectPaymentResult['trxn_id'] = [];
40 }
41 else {
42 $this->_doDirectPaymentResult['trxn_id'] = (array) $doDirectPaymentResult['trxn_id'];
43 }
44 }
45
46 /**
47 * We only need one instance of this object. So we use the singleton
48 * pattern and cache the instance in this variable
49 *
50 * @var object
51 */
52 static private $_singleton = NULL;
53
54 /**
55 * Constructor.
56 *
57 * @param string $mode
58 * The mode of operation: live or test.
59 *
60 * @param $paymentProcessor
61 *
62 * @return \CRM_Core_Payment_Dummy
63 */
64 public function __construct($mode, &$paymentProcessor) {
65 $this->_mode = $mode;
66 $this->_paymentProcessor = $paymentProcessor;
67 $this->_processorName = ts('Dummy Processor');
68 }
69
70 /**
71 * Submit a payment using Advanced Integration Method.
72 *
73 * @param array $params
74 * Assoc array of input parameters for this transaction.
75 *
76 * @return array
77 * the result in a nice formatted array (or an error object)
78 * @throws \Civi\Payment\Exception\PaymentProcessorException
79 */
80 public function doDirectPayment(&$params) {
81 // Invoke hook_civicrm_paymentProcessor
82 // In Dummy's case, there is no translation of parameters into
83 // the back-end's canonical set of parameters. But if a processor
84 // does this, it needs to invoke this hook after it has done translation,
85 // but before it actually starts talking to its proprietary back-end.
86 if (!empty($params['is_recur'])) {
87 $throwAnENoticeIfNotSetAsTheseAreRequired = $params['frequency_interval'] . $params['frequency_unit'];
88 }
89 // no translation in Dummy processor
90 $cookedParams = $params;
91 CRM_Utils_Hook::alterPaymentProcessorParams($this,
92 $params,
93 $cookedParams
94 );
95 // This means we can test failing transactions by setting a past year in expiry. A full expiry check would
96 // be more complete.
97 if (!empty($params['credit_card_exp_date']['Y']) && date('Y') >
98 CRM_Core_Payment_Form::getCreditCardExpirationYear($params)) {
99 $error = new CRM_Core_Error(ts('transaction failed'));
100 return $error;
101 }
102 //end of hook invocation
103 if (!empty($this->_doDirectPaymentResult)) {
104 $result = $this->_doDirectPaymentResult;
105 if (CRM_Utils_Array::value('payment_status_id', $result) === 'failed') {
106 throw new PaymentProcessorException($result['message'] ?? 'failed');
107 }
108 $result['trxn_id'] = array_shift($this->_doDirectPaymentResult['trxn_id']);
109 return $result;
110 }
111 if ($this->_mode == 'test') {
112 $query = "SELECT MAX(trxn_id) FROM civicrm_contribution WHERE trxn_id LIKE 'test\\_%'";
113 $p = [];
114 $trxn_id = strval(CRM_Core_DAO::singleValueQuery($query, $p));
115 $trxn_id = str_replace('test_', '', $trxn_id);
116 $trxn_id = intval($trxn_id) + 1;
117 $params['trxn_id'] = 'test_' . $trxn_id . '_' . uniqid();
118 }
119 else {
120 $query = "SELECT MAX(trxn_id) FROM civicrm_contribution WHERE trxn_id LIKE 'live_%'";
121 $p = [];
122 $trxn_id = strval(CRM_Core_DAO::singleValueQuery($query, $p));
123 $trxn_id = str_replace('live_', '', $trxn_id);
124 $trxn_id = intval($trxn_id) + 1;
125 $params['trxn_id'] = 'live_' . $trxn_id . '_' . uniqid();
126 }
127 $params['gross_amount'] = $params['amount'];
128 // Add a fee_amount so we can make sure fees are handled properly in underlying classes.
129 $params['fee_amount'] = 1.50;
130 $params['net_amount'] = $params['gross_amount'] - $params['fee_amount'];
131
132 return $params;
133 }
134
135 /**
136 * Are back office payments supported.
137 *
138 * E.g paypal standard won't permit you to enter a credit card associated with someone else's login.
139 *
140 * @return bool
141 */
142 protected function supportsLiveMode() {
143 return TRUE;
144 }
145
146 /**
147 * Does this payment processor support refund?
148 *
149 * @return bool
150 */
151 public function supportsRefund() {
152 return TRUE;
153 }
154
155 /**
156 * Supports altering future start dates
157 * @return bool
158 */
159 public function supportsFutureRecurStartDate() {
160 return TRUE;
161 }
162
163 /**
164 * Submit a refund payment
165 *
166 * @throws \Civi\Payment\Exception\PaymentProcessorException
167 *
168 * @param array $params
169 * Assoc array of input parameters for this transaction.
170 */
171 public function doRefund(&$params) {}
172
173 /**
174 * Generate error object.
175 *
176 * Throwing exceptions is preferred over this.
177 *
178 * @param string $errorCode
179 * @param string $errorMessage
180 *
181 * @return CRM_Core_Error
182 * Error object.
183 */
184 public function &error($errorCode = NULL, $errorMessage = NULL) {
185 $e = CRM_Core_Error::singleton();
186 if ($errorCode) {
187 $e->push($errorCode, 0, NULL, $errorMessage);
188 }
189 else {
190 $e->push(9001, 0, NULL, 'Unknown System Error.');
191 }
192 return $e;
193 }
194
195 /**
196 * This function checks to see if we have the right config values.
197 *
198 * @return string
199 * the error message if any
200 */
201 public function checkConfig() {
202 return NULL;
203 }
204
205 /**
206 * Get an array of the fields that can be edited on the recurring contribution.
207 *
208 * Some payment processors support editing the amount and other scheduling details of recurring payments, especially
209 * those which use tokens. Others are fixed. This function allows the processor to return an array of the fields that
210 * can be updated from the contribution recur edit screen.
211 *
212 * The fields are likely to be a subset of these
213 * - 'amount',
214 * - 'installments',
215 * - 'frequency_interval',
216 * - 'frequency_unit',
217 * - 'cycle_day',
218 * - 'next_sched_contribution_date',
219 * - 'end_date',
220 * - 'failure_retry_day',
221 *
222 * The form does not restrict which fields from the contribution_recur table can be added (although if the html_type
223 * metadata is not defined in the xml for the field it will cause an error.
224 *
225 * Open question - would it make sense to return membership_id in this - which is sometimes editable and is on that
226 * form (UpdateSubscription).
227 *
228 * @return array
229 */
230 public function getEditableRecurringScheduleFields() {
231 return ['amount', 'next_sched_contribution_date'];
232 }
233
234 /**
235 * @param string $message
236 * @param array $params
237 *
238 * @return bool|object
239 */
240 public function cancelSubscription(&$message = '', $params = []) {
241 return TRUE;
242 }
243
244 }