├── views
└── default
│ ├── images
│ ├── logo.png
│ └── alipay.webp
│ ├── process.pdt
│ └── settings.pdt
├── config.json
├── composer.json
├── language
├── zh_cn
│ └── epay.php
└── en_us
│ └── epay.php
├── README.md
├── lib
└── epay_sdk
│ └── EpayCore.class.php
└── epay.php
/views/default/images/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/anshi233/blesta-gateway-epay/HEAD/views/default/images/logo.png
--------------------------------------------------------------------------------
/views/default/images/alipay.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/anshi233/blesta-gateway-epay/HEAD/views/default/images/alipay.webp
--------------------------------------------------------------------------------
/config.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": "0.0.1",
3 | "name": "Epay.name",
4 | "description": "Epay.description",
5 | "authors": [
6 | {
7 | "name": "Anshi",
8 | "url": "https://www.catserver.ca"
9 | }
10 | ],
11 | "currencies": ["CNY"],
12 | "signup_url": "https://pay.cccyun.cc"
13 | }
--------------------------------------------------------------------------------
/views/default/process.pdt:
--------------------------------------------------------------------------------
1 |
4 |
7 |
--------------------------------------------------------------------------------
/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "Catserver/epay",
3 | "description": "EPay gateway API",
4 | "license": "MIT",
5 | "type": "blesta-gateway-nonmerchant",
6 | "require": {
7 | "blesta/composer-installer": "~1.0"
8 | },
9 | "authors": [
10 | {
11 | "name": "Anshi",
12 | "homepage": "https://www.catserver.ca"
13 | }
14 | ],
15 | "config": {
16 | "allow-plugins": {
17 | "composer/installers": true,
18 | "blesta/composer-installer": true
19 | }
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/language/zh_cn/epay.php:
--------------------------------------------------------------------------------
1 |
3 |
4 | Form->label($this->_('Epay.meta.apiurl', true), 'apiurl');
6 | $this->Form->fieldText('apiurl', ($meta['apiurl'] ?? null), ['id' => 'apiurl', 'class' => 'block']);
7 | ?>
8 |
9 |
10 | Form->label($this->_('Epay.meta.pid', true), 'pid');
12 | $this->Form->fieldText('pid', ($meta['pid'] ?? null), ['id' => 'pid', 'class' => 'block']);
13 | ?>
14 |
15 |
16 | Form->label($this->_('Epay.meta.key', true), 'key');
18 | $this->Form->fieldText('key', ($meta['key'] ?? null), ['id' => 'key', 'class' => 'block']);
19 | ?>
20 |
21 |
22 |
23 |
24 |
_('Epay.webhook'); ?>
25 |
26 |
27 |
_('Epay.webhook_note'); ?>
28 |
29 |
30 |
--------------------------------------------------------------------------------
/language/en_us/epay.php:
--------------------------------------------------------------------------------
1 | Settings > Payment Gateways
30 |
31 | 4. Find the EPay gateway and click the "Install" button to install it
32 |
33 | 5. You're done!
34 |
35 | # Limitation
36 | * EPay only support CNY. Please use Blesta's currency setting to convert currencies.
37 | * Each payment trascation only support one inovice order.
38 | * Currently no refund support.
39 | * No void invoice support (EPay API does not support it).
40 |
41 | # TO-DO
42 | * Any bug fix.
43 | * add refund support.
44 |
45 | # Support me
46 | Considering buying a VPS from [CatServer.ca](https://www.catserver.ca)
47 |
48 | # Reference
49 | * [blesta-stripe-universal](https://github.com/anshi233/blesta-stripe-universal)
50 | * [gateway-paypal_checkout](https://github.com/blesta/gateway-paypal_checkout)
--------------------------------------------------------------------------------
/lib/epay_sdk/EpayCore.class.php:
--------------------------------------------------------------------------------
1 | pid = $config['pid'];
19 | $this->key = $config['key'];
20 | $this->submit_url = $config['apiurl'].'submit.php';
21 | $this->mapi_url = $config['apiurl'].'mapi.php';
22 | $this->api_url = $config['apiurl'].'api.php';
23 | }
24 |
25 | // 发起支付(页面跳转)
26 | public function pagePay($param_tmp, $button='正在跳转'){
27 | $param = $this->buildRequestParam($param_tmp);
28 |
29 | $html = '';
34 |
35 | return $html;
36 | }
37 |
38 | // 发起支付(获取链接)
39 | public function getPayLink($param_tmp){
40 | $param = $this->buildRequestParam($param_tmp);
41 | $url = $this->submit_url.'?'.http_build_query($param);
42 | return $url;
43 | }
44 |
45 | // 发起支付(API接口)
46 | public function apiPay($param_tmp){
47 | $param = $this->buildRequestParam($param_tmp);
48 | $response = $this->getHttpResponse($this->mapi_url, http_build_query($param));
49 | $arr = json_decode($response, true);
50 | return $arr;
51 | }
52 |
53 | // 异步回调验证
54 | public function verifyNotify(){
55 | if(empty($_GET)) return false;
56 |
57 | $sign = $this->getSign($_GET);
58 |
59 | if($sign === $_GET['sign']){
60 | $signResult = true;
61 | }else{
62 | $signResult = false;
63 | }
64 |
65 | return $signResult;
66 | }
67 |
68 | // 同步回调验证
69 | public function verifyReturn(){
70 | if(empty($_GET)) return false;
71 |
72 | $sign = $this->getSign($_GET);
73 |
74 | if($sign === $_GET['sign']){
75 | $signResult = true;
76 | }else{
77 | $signResult = false;
78 | }
79 |
80 | return $signResult;
81 | }
82 | /**
83 | * Validates the incoming POST/GET response from the gateway and verify its sign
84 | * @param array $get The GET data for this request
85 | * @param array $post The POST data for this request
86 | * @return array An array of transaction data, sets any errors using Input if the data fails to validate
87 | **/
88 | public function verifyReturnBlesta($get){
89 | if(empty($get)) return false;
90 | //Remove the blesta appended field '0', '1' and 'client_id' from $get
91 | unset($get['0']);
92 | unset($get['1']);
93 | unset($get['client_id']);
94 | $sign = $this->getSign($get);
95 |
96 | if($sign === $get['sign']){
97 | $signResult = true;
98 | }else{
99 | $signResult = false;
100 | }
101 |
102 | return $signResult;
103 | }
104 |
105 |
106 | // 查询订单支付状态
107 | public function orderStatus($trade_no){
108 | //Add empty value check
109 | if(empty($trade_no)){
110 | return false;
111 | }
112 | $result = $this->queryOrder($trade_no);
113 | if($result['status']==1){
114 | return true;
115 | }else{
116 | return false;
117 | }
118 | }
119 |
120 | // 查询订单
121 | public function queryOrder($trade_no){
122 | $url = $this->api_url.'?act=order&pid=' . $this->pid . '&key=' . $this->key . '&trade_no=' . $trade_no;
123 | $response = $this->getHttpResponse($url);
124 | $arr = json_decode($response, true);
125 | return $arr;
126 | }
127 |
128 | // 查询商户信息
129 | public function queryMerchant($pid, $key, $api_url){
130 | $url = $this->api_url.'?act=query&pid=' . $this->pid . '&key=' . $this->key;
131 | $response = $this->getHttpResponse($url);
132 | $arr = json_decode($response, true);
133 | return $arr;
134 | }
135 |
136 | // 订单退款
137 | public function refund($trade_no, $money){
138 | $url = $this->api_url.'?act=refund';
139 | $post = 'pid=' . $this->pid . '&key=' . $this->key . '&trade_no=' . $trade_no . '&money=' . $money;
140 | $response = $this->getHttpResponse($url, $post);
141 | $arr = json_decode($response, true);
142 | return $arr;
143 | }
144 |
145 | private function buildRequestParam($param){
146 | $mysign = $this->getSign($param);
147 | $param['sign'] = $mysign;
148 | $param['sign_type'] = $this->sign_type;
149 | return $param;
150 | }
151 |
152 | // 计算签名
153 | private function getSign($param){
154 | ksort($param);
155 | reset($param);
156 | $signstr = '';
157 |
158 | foreach($param as $k => $v){
159 | if($k != "sign" && $k != "sign_type" && $v!=''){
160 | $signstr .= $k.'='.$v.'&';
161 | }
162 | }
163 | $signstr = substr($signstr,0,-1);
164 | $signstr .= $this->key;
165 | $sign = md5($signstr);
166 | return $sign;
167 | }
168 |
169 | // 请求外部资源
170 | private function getHttpResponse($url, $post = false, $timeout = 10){
171 | $ch = curl_init($url);
172 | curl_setopt($ch, CURLOPT_TIMEOUT, $timeout);
173 | //set to ture to use https
174 | curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true);
175 | //set to ture to use https
176 | curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2);
177 | $httpheader[] = "Accept: */*";
178 | $httpheader[] = "Accept-Language: zh-CN,zh;q=0.8";
179 | $httpheader[] = "Connection: close";
180 | curl_setopt($ch, CURLOPT_HTTPHEADER, $httpheader);
181 | curl_setopt($ch, CURLOPT_HEADER, false);
182 | curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
183 | if($post){
184 | curl_setopt($ch, CURLOPT_POST, true);
185 | curl_setopt($ch, CURLOPT_POSTFIELDS, $post);
186 | }
187 | $response = curl_exec($ch);
188 | curl_close($ch);
189 | return $response;
190 | }
191 | }
192 |
--------------------------------------------------------------------------------
/epay.php:
--------------------------------------------------------------------------------
1 | loadConfig(dirname(__FILE__) . DS . 'config.json');
33 |
34 | // Load components required by this gateway
35 | Loader::loadComponents($this, ['Input']);
36 |
37 | // Load the language required by this gateway
38 | Language::loadLang('epay', null, dirname(__FILE__) . DS . 'language' . DS);
39 | }
40 |
41 | /**
42 | * Sets the meta data for this particular gateway
43 | *
44 | * @param array $meta An array of meta data to set for this gateway
45 | */
46 | public function setMeta(array $meta = null)
47 | {
48 | $this->meta = $meta;
49 | //Also set the EPay parameters
50 | $this->ePayConfig = [
51 | 'pid' => $meta['pid'],
52 | 'key' => $meta['key'],
53 | 'apiurl' => $meta['apiurl']
54 | ];
55 |
56 | }
57 |
58 | /**
59 | * Create and return the view content required to modify the settings of this gateway
60 | *
61 | * @param array $meta An array of meta (settings) data belonging to this gateway
62 | * @return string HTML content containing the fields to update the meta data for this gateway
63 | */
64 | public function getSettings(array $meta = null)
65 | {
66 | // Load the view into this object, so helpers can be automatically add to the view
67 | $this->view = new View('settings', 'default');
68 | $this->view->setDefaultView('components' . DS . 'gateways' . DS . 'nonmerchant' . DS . 'epay' . DS);
69 |
70 | // Load the helpers required for this view
71 | Loader::loadHelpers($this, ['Form', 'Html']);
72 |
73 | $this->view->set('meta', $meta);
74 |
75 | return $this->view->fetch();
76 | }
77 |
78 | /**
79 | * Validates the given meta (settings) data to be updated for this gateway
80 | *
81 | * @param array $meta An array of meta (settings) data to be updated for this gateway
82 | * @return array The meta data to be updated in the database for this gateway, or reset into the form on failure
83 | */
84 | public function editSettings(array $meta)
85 | {
86 | // Set rules
87 | $rules = [
88 | //Merchant ID
89 | 'pid' => [
90 | //Check is pid is empty
91 | 'empty' => [
92 | 'rule' => 'isEmpty',
93 | 'negate' => true,
94 | 'message' => Language::_('Epay.!error.pid.empty', true)
95 | ],
96 | ],
97 | //Merchant Key
98 | 'key' => [
99 | //Check is key is empty
100 | 'empty' => [
101 | 'rule' => 'isEmpty',
102 | 'negate' => true,
103 | 'message' => Language::_('Epay.!error.key.empty', true)
104 | ],
105 | ],
106 | //Gateway URL
107 | 'apiurl' => [
108 | //Check is apiurl is empty
109 | 'empty' => [
110 | 'rule' => 'isEmpty',
111 | 'negate' => true,
112 | 'message' => Language::_('Epay.!error.apiurl.empty', true)
113 | ],
114 | //Check is apiurl is valid
115 | 'valid' => [
116 | 'rule' => [[$this, 'validateApiurl'], $meta['pid'], $meta['key']],
117 | 'message' => Language::_('Epay.!error.api.valid', true)
118 | ]
119 | ]
120 | ];
121 | $this->Input->setRules($rules);
122 |
123 | // Validate the given meta data to ensure it meets the requirements
124 | $this->Input->validates($meta);
125 |
126 |
127 | // Return the meta data, no changes required regardless of success or failure for this gateway
128 | return $meta;
129 | }
130 |
131 | /**
132 | * Returns an array of all fields to encrypt when storing in the database
133 | *
134 | * @return array An array of the field names to encrypt when storing in the database
135 | */
136 | public function encryptableFields()
137 | {
138 |
139 | //For debug, no need to encrypt now
140 | //return ['key'];
141 | //return empty array
142 | return [];
143 | }
144 |
145 | /**
146 | * Sets the currency code to be used for all subsequent payments
147 | *
148 | * @param string $currency The ISO 4217 currency code to be used for subsequent payments
149 | */
150 | public function setCurrency($currency)
151 | {
152 | $this->currency = $currency;
153 | }
154 |
155 | /**
156 | * Returns all HTML markup required to render an authorization and capture payment form
157 | *
158 | * @param array $contact_info An array of contact info including:
159 | * - id The contact ID
160 | * - client_id The ID of the client this contact belongs to
161 | * - user_id The user ID this contact belongs to (if any)
162 | * - contact_type The type of contact
163 | * - contact_type_id The ID of the contact type
164 | * - first_name The first name on the contact
165 | * - last_name The last name on the contact
166 | * - title The title of the contact
167 | * - company The company name of the contact
168 | * - address1 The address 1 line of the contact
169 | * - address2 The address 2 line of the contact
170 | * - city The city of the contact
171 | * - state An array of state info including:
172 | * - code The 2 or 3-character state code
173 | * - name The local name of the country
174 | * - country An array of country info including:
175 | * - alpha2 The 2-character country code
176 | * - alpha3 The 3-cahracter country code
177 | * - name The english name of the country
178 | * - alt_name The local name of the country
179 | * - zip The zip/postal code of the contact
180 | * @param float $amount The amount to charge this contact
181 | * @param array $invoice_amounts An array of invoices, each containing:
182 | * - id The ID of the invoice being processed
183 | * - amount The amount being processed for this invoice (which is included in $amount)
184 | * @param array $options An array of options including:
185 | * - description The Description of the charge
186 | * - return_url The URL to redirect users to after a successful payment
187 | * - recur An array of recurring info including:
188 | * - amount The amount to recur
189 | * - term The term to recur
190 | * - period The recurring period (day, week, month, year, onetime) used in conjunction
191 | * with term in order to determine the next recurring payment
192 | * @return string HTML markup required to render an authorization and capture payment form
193 | */
194 | public function buildProcess(array $contact_info, $amount, array $invoice_amounts = null, array $options = null)
195 | {
196 | // Force 1-decimal places only
197 | $amount = round($amount, 2);
198 | if (isset($options['recur']['amount'])) {
199 | $options['recur']['amount'] = round($options['recur']['amount'], 2);
200 | }
201 |
202 | //EPay only support RMB
203 |
204 | // At this line, we will load the view html file. It is the payment button.
205 | $this->view = $this->makeView('process', 'default', str_replace(ROOTWEBDIR, '', dirname(__FILE__) . DS));
206 |
207 | // Load the models and helpers required for this view
208 | Loader::loadModels($this, ['Companies']);
209 | Loader::loadHelpers($this, ['Form', 'Html']);
210 |
211 | // Get Client Information
212 | Loader::loadModels($this, ['Contacts']);
213 |
214 | //EPay only support one invoice for each transaction
215 | //Give error if more than one invoice
216 | if(count($invoice_amounts) > 1){
217 | $this->Input->setErrors(['api' => ['internal' => 'EPay only support one invoice for each transaction']]);
218 | return;
219 | }
220 | $out_trade_no = $invoice_amounts[0]['id'];
221 |
222 |
223 |
224 | // Initialize API
225 | $api = $this->getApi($this->ePayConfig);
226 | //2024-11-28 Found an issue that the return url is different for payment made from order page or invoice payment page.
227 | //Always use invoice payment page to make epay gateway api happy. Otherwise it will give parameter changed error.
228 | $callbackUrl = Configure::get('Blesta.gw_callback_url');
229 | preg_match('/^(https?:\/\/[^\/]+)/', $callbackUrl, $matches);
230 | $baseUrl = $matches[1];
231 |
232 | // For EPay, we need to don't need to create order first.
233 | // Just collect enough information and send to EPay directly, it will give us a payment link.
234 | // We will use the EPayCore class to do this.
235 | // ePayUrl is the link that we want to redirect the user to.
236 | $orderInfo = array(
237 | "pid" => $this->ePayConfig['pid'],
238 | //Type leave blank for now. We want to let user select payment method. (Alipay, WeChat Pay .etc)
239 | //TO-DO: Add a dropdown to let user select payment method. (No ETA)
240 | "type" => '',
241 | //Notify URL is the blesta websocket URL.
242 | "notify_url" => Configure::get('Blesta.gw_callback_url') . Configure::get('Blesta.company_id') . '/epay/',
243 | //Return URL is the URL that user will be redirected to after payment.
244 | //"return_url" => $options['return_url'],
245 | //TO-DO: May have issue if multi-company is used.
246 | "return_url" => $baseUrl . '/client/pay/received/epay/?client_id=' . $contact_info['client_id'],
247 | //out_trade_no is our blesta created order number(Invoice number)
248 | "out_trade_no" => $out_trade_no,
249 | //name is the product name e.g. "HK VPS Value Plan"
250 | "name" => $options['description'],
251 | //money is the price of the product in RMB!!!
252 | "money" => $amount,
253 | //use EPay API's param field to passing client_id
254 | "param" => "client_id=" . $contact_info['client_id']
255 | );
256 | //Log the api input
257 | $this->log('buildProcess', json_encode($orderInfo), 'input', true);
258 | //Get payment link
259 | try {
260 | $ePayUrl = $api->getPayLink($orderInfo);
261 | } catch (Exception $e) {
262 | $this->Input->setErrors(['api' => ['internal' => $e->getMessage()]]);
263 | return;
264 | }
265 |
266 | $this->view->set('epay_url', $ePayUrl);
267 |
268 | return $this->view->fetch();
269 |
270 | }
271 |
272 | /**
273 | * Handle Verified payment result information
274 | * This function will format the raw EPay API return information to somthing Blesta can understand.
275 | * @param array $get The GET data from EPay API requests
276 | * @return array The array of transaction data
277 | */
278 | private function handleEPayOrder(array $get){
279 | $out_trade_no = $get['out_trade_no'] ?? null;
280 | $trade_no = $get['trade_no'] ?? null;
281 | //I will use amount not money
282 | $amount = $get['money'] ?? null;
283 |
284 | // Start process the successful payment
285 | // Get Client ID from EPay API's param field
286 | preg_match('/client_id=(\d+)/', $get['param'], $matches);
287 | if (!empty($matches) && !empty($matches[1])) {
288 | $clientId = $matches[1];
289 | } else {
290 | // Handle the case where client_id is empty or not found
291 | $this->Input->setErrors(['api' => ['internal' => 'empty client id']]);
292 | return;
293 | }
294 | return [
295 | 'client_id' => $clientId ?? null,
296 | 'amount' => $amount,
297 | 'currency' => 'CNY',
298 | //'invoices' => $this->unserializeInvoices($out_trade_no),
299 | 'invoices' => [['id' => $out_trade_no, 'amount' => $amount]],
300 | 'status' => 'approved',
301 | 'reference_id' => null,
302 | 'transaction_id' => $trade_no,
303 | 'parent_transaction_id' => null
304 | ];
305 | }
306 |
307 |
308 | /**
309 | * Validates the incoming POST/GET response from the gateway to ensure it is
310 | * legitimate and can be trusted.
311 | *
312 | * @param array $get The GET data for this request
313 | * @param array $post The POST data for this request
314 | * @return array An array of transaction data, sets any errors using Input if the data fails to validate
315 | * - client_id The ID of the client that attempted the payment
316 | * - amount The amount of the payment
317 | * - currency The currency of the payment
318 | * - invoices An array of invoices and the amount the payment should be applied to (if any) including:
319 | * - id The ID of the invoice to apply to
320 | * - amount The amount to apply to the invoice
321 | * - status The status of the transaction (approved, declined, void, pending, reconciled, refunded, returned)
322 | * - reference_id The reference ID for gateway-only use with this transaction (optional)
323 | * - transaction_id The ID returned by the gateway to identify this transaction
324 | * - parent_transaction_id The ID returned by the gateway to identify this
325 | * transaction's original transaction (in the case of refunds)
326 | */
327 | public function validate(array $get, array $post)
328 | {
329 | // Initialize API
330 | $api = $this->getApi($this->ePayConfig);
331 | //From raw get data verify EPay sign
332 | $sign_result = $api->verifyReturnBlesta($get);
333 | if($sign_result == false) {
334 | //Throw error when sign validation failed
335 | $this->Input->setErrors([
336 | 'event' => ['invalid_sign' => Language::_('Epay.!error.event.invalid_sign', true)]
337 | ]);
338 | return;
339 | }
340 | // Discard all webhook events, except when the order is completed or approved
341 | if ($get['trade_status'] != 'TRADE_SUCCESS') {
342 | //Throw error event for unsuccessful payment result
343 | $this->Input->setErrors([
344 | 'event' => ['unsupported' => Language::_('Epay.!error.event.unsupported', true)]
345 | ]);
346 | return;
347 | }
348 |
349 | // log the sucess payment in blesta logs
350 | $this->log('validate', json_encode($get), 'input', !empty($get));
351 | //Tell Epay API Gateway that we have received the payment
352 | echo 'success';
353 |
354 |
355 | return $this->handleEPayOrder($get);
356 | }
357 |
358 | /**
359 | * Returns data regarding a success transaction. This method is invoked when
360 | * a client returns from the non-merchant gateway's web site back to Blesta.
361 | * Most of the part of this function will be same as $this->validate()
362 | * however, we don't trust client since they might do the return attack.
363 | * Extra layer of security is done by requesting EPay API Gateway to confrim.
364 | *
365 | * @param array $get The GET data for this request
366 | * @param array $post The POST data for this request
367 | * @return array An array of transaction data, may set errors using Input if the data appears invalid
368 | * - client_id The ID of the client that attempted the payment
369 | * - amount The amount of the payment
370 | * - currency The currency of the payment
371 | * - invoices An array of invoices and the amount the payment should be applied to (if any) including:
372 | * - id The ID of the invoice to apply to
373 | * - amount The amount to apply to the invoice
374 | * - status The status of the transaction (approved, declined, void, pending, reconciled, refunded, returned)
375 | * - transaction_id The ID returned by the gateway to identify this transaction
376 | * - parent_transaction_id The ID returned by the gateway to identify this transaction's original transaction
377 | */
378 | public function success(array $get, array $post)
379 | {
380 | // Initialize API
381 | $api = $this->getApi($this->ePayConfig);
382 | //From raw get data verify EPay sign
383 | $sign_result = $api->verifyReturnBlesta($get);
384 | if($sign_result == false) {
385 | //Throw error when sign validation failed
386 | $this->Input->setErrors([
387 | 'event' => ['invalid_sign' => Language::_('Epay.!error.event.invalid_sign', true)]
388 | ]);
389 | return;
390 | }
391 | // Discard all webhook events, except when the order is completed or approved
392 | if ($get['trade_status'] != 'TRADE_SUCCESS') {
393 | //Throw error event for unsuccessful payment result
394 | $this->Input->setErrors([
395 | 'event' => ['unsupported' => Language::_('Epay.!error.event.unsupported', true)]
396 | ]);
397 | return;
398 | }
399 | //Send a extra request to API Gateway to make sure gateway really get the payment
400 | $isPaid = $api->orderStatus($get['trade_no'] ?? null);
401 | if(!$isPaid){
402 | //user return success but gateway not receive payment???
403 | //Suspicous! Not accept this request.
404 | $this->Input->setErrors([
405 | 'event' => ['fake_success_payment' => Language::_('Epay.!error.event.fake_success_payment', true)]
406 | ]);
407 | return;
408 | }
409 |
410 |
411 | // log the sucess payment in blesta logs
412 | $this->log('validate', json_encode($get), 'input', !empty($get));
413 | return $this->handleEPayOrder($get);
414 | }
415 |
416 | /**
417 | * Refund a payment
418 | *
419 | * @param string $reference_id The reference ID for the previously submitted transaction
420 | * @param string $transaction_id The transaction ID for the previously submitted transaction
421 | * @param float $amount The amount to refund this transaction
422 | * @param string $notes Notes about the refund that may be sent to the client by the gateway
423 | * @return array An array of transaction data including:
424 | * - status The status of the transaction (approved, declined, void, pending, reconciled, refunded, returned)
425 | * - reference_id The reference ID for gateway-only use with this transaction (optional)
426 | * - transaction_id The ID returned by the remote gateway to identify this transaction
427 | * - message The message to be displayed in the interface in addition to the standard
428 | * message for this transaction status (optional)
429 | */
430 | public function refund($reference_id, $transaction_id, $amount, $notes = null)
431 | {
432 | //TO-DO Add automatic refund feature
433 | // Method is unsupported for now
434 | if (isset($this->Input))
435 | $this->Input->setErrors($this->getCommonError("unsupported"));
436 | }
437 |
438 | /**
439 | * Void a payment or authorization.
440 | *
441 | * @param string $reference_id The reference ID for the previously submitted transaction
442 | * @param string $transaction_id The transaction ID for the previously submitted transaction
443 | * @param string $notes Notes about the void that may be sent to the client by the gateway
444 | * @return array An array of transaction data including:
445 | * - status The status of the transaction (approved, declined, void, pending, reconciled, refunded, returned)
446 | * - reference_id The reference ID for gateway-only use with this transaction (optional)
447 | * - transaction_id The ID returned by the remote gateway to identify this transaction
448 | * - message The message to be displayed in the interface in addition to the standard
449 | * message for this transaction status (optional)
450 | */
451 | public function void($reference_id, $transaction_id, $notes = null)
452 | {
453 | // Method is unsupported for now
454 | if (isset($this->Input))
455 | $this->Input->setErrors($this->getCommonError("unsupported"));
456 | }
457 |
458 | /**
459 | * Loads the given API if not already loaded
460 | *
461 | * @param array $ePayConfig The EPay configuration
462 | */
463 | private function getApi($config)
464 | {
465 | return new EpayCore($config);
466 | }
467 |
468 | /**
469 | * Validates if the provided API Key is valid
470 | *
471 | * @param string $pid The merchant ID
472 | * @param string $key The API key
473 | * @param string $apiurl the EPay gateway API URL
474 | * @return bool True if the API Key is valid, false otherwise
475 | */
476 | public function validateConnection($pid, $key, $apiurl)
477 | {
478 | try {
479 | $ePayConfigTemp = [
480 | 'pid' => $pid,
481 | 'key' => $key,
482 | 'apiurl' => $apiurl
483 | ];
484 | // Initialize API
485 | $api = $this->getApi($ePayConfigTemp);
486 | $merchantInfo = $api->queryMerchant($pid, $key, $apiurl);
487 |
488 | if(!empty($merchantInfo) && !empty($merchantInfo['code'])){
489 | if($merchantInfo['code'] == 1){
490 | return true;
491 | }elseif($merchantInfo['code'] == -3){
492 | //API Credential is invalid.
493 | $this->Input->setErrors(['create' => ['response' => 'EPay API Gateway return code ' . $merchantInfo['code'] . "\nPlease check you API Key and Merchant ID"]]);
494 | return false;
495 | }else{
496 | $this->Input->setErrors(['create' => ['response' => 'EPay API Gateway return code ' . $merchantInfo['code']]]);
497 | return false;
498 | }
499 | }
500 | $this->Input->setErrors(['create' => ['response' => 'Failed to connect to EPay API Gateway']]);
501 | return false;
502 |
503 | } catch (Throwable $e) {
504 | $this->Input->setErrors(['create' => ['response' => $e->getMessage()]]);
505 | return false;
506 | }
507 | }
508 |
509 | /**
510 | * Validate pid. api url and key comes from meta data
511 | *
512 | * @param string $file The configuration file to load
513 | */
514 | public function validatePid($pid, $key, $apiurl){
515 | return $this->validateConnection($pid, $key, $apiurl);
516 | }
517 | /**
518 | * Validate api url. pid and key comes from meta data
519 | *
520 | * @param string $file The configuration file to load
521 | */
522 | public function validateApiurl($apiurl, $pid, $key){
523 | return $this->validateConnection($pid, $key, $apiurl);
524 | }
525 | /**
526 | * Validate key. pid and api url comes from meta data
527 | *
528 | * @param string $file The configuration file to load
529 | */
530 | public function validateKey($key, $pid, $apiurl){
531 | return $this->validateConnection($pid, $key, $apiurl);
532 | }
533 |
534 | }
535 |
--------------------------------------------------------------------------------