· 7 years ago · Feb 27, 2019, 03:08 PM
1<?php
2use PrestaShop\PrestaShop\Core\Payment\PaymentOption;
3
4if (!defined('_PS_VERSION_')) {
5 exit;
6}
7
8class GenericGateway extends PaymentModule
9{
10 const PREFIX = '003020300C06082A864886F70D020505000410';
11 const SUFFIX = '0001';
12
13 public function __construct()
14 {
15 $this->name = 'HIDDEN';
16 $this->tab = 'payments_gateways';
17 $this->version = '1.0';
18 $this->author = 'HIDDEN';
19 $this->display = 'view';
20 $this->is_eu_compatible = 1;
21 $this->ps_version_compliancy = array('min' => '1.7', 'max' => _PS_VERSION_);
22 $this->controllers = array('payment', 'validation');
23 $this->bootstrap = true;
24
25 $this->currencies = true;
26 $this->currencies_mode = 'checkbox';
27
28 parent::__construct();
29
30 $this->displayName = 'HIDDEN Gateway API';
31 $this->description = $this->l('Payment by Credit/Debit Card through HIDDEN.');
32
33 if (!count(Currency::checkPaymentCurrencies($this->id))) {
34 $this->warning = $this->l('No currency has been selected!');
35 }
36
37 if (!Configuration::get('HIDDEN_GATEWAY')) {
38 $this->warning = $this->l('Gateway URL to HIDDEN is missing.');
39 }
40
41 if (!Configuration::get('HIDDEN_MERCHANT')) {
42 $this->warning = $this->l('Merchant ID is missing..');
43 }
44
45 if (!Configuration::get('HIDDEN_TERMINAL')) {
46 $this->warning = $this->l('Terminal is missing.');
47 }
48 }
49
50 public function install()
51 {
52 if (!function_exists('curl_version')) {
53 $this->warning = $this->l('Please enable cURL extension for PHP.');
54 }
55
56 if (Shop::isFeatureActive()) {
57 Shop::setContext(Shop::CONTEXT_ALL);
58 }
59
60 if (!$this->installSQL()) {
61 return false;
62 }
63
64 if (!parent::install() ||
65 !$this->installSQL() ||
66 !$this->registerHook('paymentOptions') ||
67 !$this->registerHook('paymentReturn') ||
68 !$this->registerHook('actionOrderStatusPostUpdate') ||
69 !Configuration::updateValue('HIDDEN_NAME', 'Company Name') ||
70 !Configuration::updateValue('HIDDEN_ADDRESS', 'Generic Address') ||
71 !Configuration::updateValue('HIDDEN_GATEWAY', 'https://genericgateway.com') ||
72 !Configuration::updateValue('HIDDEN_MERCHANT', '111111111111111') ||
73 !Configuration::updateValue('HIDDEN_TERMINAL', '11111111')
74 ) {
75 return false;
76 }
77 return true;
78 }
79
80 private function installSQL()
81 {
82 $sql = array();
83
84 $sql[] = "CREATE TABLE IF NOT EXISTS `"._DB_PREFIX_."HIDDEN_transactions` (
85 `id` BIGINT(20) UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT,
86 `id_cart` INT(10) UNSIGNED NOT NULL,
87 `id_order` INT(10) UNSIGNED DEFAULT NULL,
88 `ammount` DECIMAL(8,2) NOT NULL,
89 `currency` VARCHAR(3) NOT NULL,
90 `order` VARCHAR(32) NOT NULL,
91 `desc` TEXT,
92 `merch_name` VARCHAR(64) NOT NULL,
93 `merch_url` VARCHAR(64) NOT NULL,
94 `merchant` BIGINT(15) NOT NULL,
95 `terminal` MEDIUMINT(8) UNSIGNED NOT NULL,
96 `email` VARCHAR(64) NOT NULL,
97 `merch_address` VARCHAR(64) NOT NULL,
98 `trtype` TINYINT(2) UNSIGNED NOT NULL,
99 `country` VARCHAR(2) NOT NULL,
100 `merch_gmt` VARCHAR(5) NOT NULL,
101 `timestamp` BIGINT(14) NOT NULL,
102 `nonce` VARCHAR(64) NOT NULL,
103 `p_sign` TEXT,
104 `lang` VARCHAR(2) NOT NULL,
105 `action` ENUM('0','1','2','3') DEFAULT NULL,
106 `rc` VARCHAR(3) DEFAULT NULL,
107 `approval` VARCHAR(6) DEFAULT NULL,
108 `rrn` VARCHAR(12) DEFAULT NULL,
109 `int_ref` VARCHAR(32) DEFAULT NULL,
110 `eci` ENUM('05','06','07') DEFAULT NULL
111 ) ENGINE = "._MYSQL_ENGINE_;
112
113 foreach ($sql as $q) {
114 if (!DB::getInstance()->execute($sql)) {
115 return false;
116 }
117 }
118 }
119
120 public function uninstall()
121 {
122 $sql = "DROP TABLE IF EXISTS `" . _DB_PREFIX_ . " HIDDEN_transactions`";
123 DB::getInstance()->execute($sql);
124
125 if (!parent::uninstall() ||
126 !Configuration::deleteByName('HIDDEN_NAME') ||
127 !Configuration::deleteByName('HIDDEN_ADDRESS') ||
128 !Configuration::deleteByName('HIDDEN_GATEWAY') ||
129 !Configuration::deleteByName('HIDDEN_MERCHANT') ||
130 !Configuration::deleteByName('HIDDEN_TERMINAL')) {
131 return false;
132 }
133 return true;
134 }
135
136 public function getContent()
137 {
138 $output = null;
139
140 if (Tools::isSubmit('submit'.$this->name)) {
141 $company_name = Tools::getValue('HIDDEN_NAME');
142 $company_address = Tools::getValue('HIDDEN_ADDRESS');
143 $gateway = Tools::getValue('HIDDEN_GATEWAY');
144 $merchant_id = Tools::getValue('HIDDEN_MERCHANT');
145 $terminal = Tools::getValue('HIDDEN_TERMINAL');
146
147 if (
148 !$company_name ||
149 empty($company_name) ||
150 !Validate::isGenericName($company_name)
151 ) {
152 $output .= $this->displayError($this->l('Invalid COMPANY NAME Configuration value'));
153 } else {
154 Configuration::updateValue('HIDDEN_NAME', $company_name);
155 $output .= $this->displayConfirmation($this->l('Settings updated'));
156 }
157
158 if (
159 !$company_address ||
160 empty($company_address) ||
161 !Validate::isGenericName($company_address)
162 ) {
163 $output .= $this->displayError($this->l('Invalid COMPANY ADDRESS Configuration value'));
164 } else {
165 Configuration::updateValue('HIDDEN_ADDRESS', $company_address);
166 $output .= $this->displayConfirmation($this->l('Settings updated'));
167 }
168
169 if (
170 !$gateway ||
171 empty($gateway) ||
172 !Validate::isGenericName($gateway)
173 ) {
174 $output .= $this->displayError($this->l('Invalid GATEWAY Configuration value'));
175 } else {
176 Configuration::updateValue('HIDDEN_GATEWAY', $gateway);
177 $output .= $this->displayConfirmation($this->l('Settings updated'));
178 }
179
180 if (
181 !$merchant_id ||
182 empty($merchant_id) ||
183 !Validate::isGenericName($merchant_id)
184 ) {
185 $output .= $this->displayError($this->l('Invalid MERCHANT Configuration value'));
186 } else {
187 Configuration::updateValue('HIDDEN_MERCHANT', $merchant_id);
188 $output .= $this->displayConfirmation($this->l('Settings updated'));
189 }
190
191 if (
192 !$terminal ||
193 empty($terminal) ||
194 !Validate::isGenericName($terminal)
195 ) {
196 $output .= $this->displayError($this->l('Invalid TERMINAL Configuration value'));
197 } else {
198 Configuration::updateValue('HIDDEN_TERMINAL', $terminal);
199 $output .= $this->displayConfirmation($this->l('Settings updated'));
200 }
201 }
202
203 return $output.$this->displayForm();
204 }
205
206 public function displayform()
207 {
208 $default_lang = (int)Configuration::get('PS_LANG_DEFAULT');
209 $response_url = (Configuration::get('PS_SSL_ENABLED') ? 'https://' : 'http://').htmlspecialchars($_SERVER['HTTP_HOST'], ENT_COMPAT, 'UTF-8').__PS_BASE_URI__.'index.php?fc=module&module='.$this->name.'&controller=validation';
210
211 $fields_form = array();
212 $fields_form[0]['form'] = array(
213 'legend' => array(
214 'title' => $this->l('Settings'),
215 ),
216 'input' => array(
217 array(
218 'type' => 'text',
219 'label' => $this->l('Company Name'),
220 'name' => 'HIDDEN_NAME',
221 'size' => 32,
222 'desc' => $this->l('Company name registered to bank.'),
223 'required' => true
224 ),
225 array(
226 'type' => 'text',
227 'label' => $this->l('Company Address'),
228 'name' => 'HIDDEN_ADDRESS',
229 'size' => 32,
230 'desc' => $this->l('Company address registerd to bank.'),
231 'required' => true
232 ),
233 array(
234 'type' => 'text',
235 'label' => $this->l('Merchant'),
236 'name' => 'HIDDEN_MERCHANT',
237 'size' => 15,
238 'desc' => $this->l('Merchant ID assigned by bank.'),
239 'required' => true
240 ),
241 array(
242 'type' => 'text',
243 'label' => $this->l('Terminal'),
244 'name' => 'HIDDEN_TERMINAL',
245 'size' => 8,
246 'desc' => $this->l('Merchant Terminal ID assigned by bank.').'<br />Response URL: '.$response_url,
247 'required' => true
248 ),
249 array(
250 'type' => 'text',
251 'label' => $this->l('Gateway'),
252 'name' => 'HIDDEN_GATEWAY',
253 'size' => 64,
254 'desc' => $this->l('URL for payment redirects.'),
255 'required' => true
256 )
257 ),
258 'submit' => array(
259 'title' => $this->l('Save')
260 )
261 );
262
263 $helper = new HelperForm();
264
265 $helper->module = $this;
266 $helper->name_controller = $this->name;
267 $helper->token = Tools::getAdminTokenLite('AdminModules');
268 $helper->currentIndex = AdminController::$currentIndex.'&configure='.$this->name;
269
270 $helper->default_form_language = $default_lang;
271 $helper->allow_employee_form_lang = $default_lang;
272
273 $helper->title = $this->displayName;
274 $helper->show_toolbar = true;
275 $helper->toolbar_scroll = true;
276 $helper->submit_action = 'submit'.$this->name;
277 $helper->toolbar_btn = array(
278 'save' =>
279 array(
280 'desc' => $this->l('Save'),
281 'href' => AdminController::$currentIndex.'&configure='.$this->name.'&save'.$this->name.
282 '&token='.Tools::getAdminTokenLite('AdminModules'),
283 ),
284 'back' => array(
285 'href' => AdminController::$currentIndex.'&token='.Tools::getAdminTokenLite('AdminModules'),
286 'desc' => $this->l('Back to list')
287 )
288 );
289
290 $helper->fields_value['HIDDEN_NAME'] = Configuration::get('HIDDEN_NAME');
291 $helper->fields_value['HIDDEN_ADDRESS'] = Configuration::get('HIDDEN_ADDRESS');
292 $helper->fields_value['HIDDEN_MERCHANT'] = Configuration::get('HIDDEN_MERCHANT');
293 $helper->fields_value['HIDDEN_TERMINAL'] = Configuration::get('HIDDEN_TERMINAL');
294 $helper->fields_value['HIDDEN_GATEWAY'] = Configuration::get('HIDDEN_GATEWAY');
295
296 return $helper->generateForm($fields_form);
297 }
298
299 public function hookPaymentOptions($params)
300 {
301 if (!$this->active) {
302 return;
303 }
304
305 if (!$this->checkCurrency($params['cart'])) {
306 return;
307 }
308
309 $payment_options = [
310 $this->getExternalPaymentOption(),
311 ];
312
313 return $payment_options;
314 }
315
316 public function checkCurrency($cart)
317 {
318 $currency_order = new Currency($cart->id_currency);
319 $currencies_module = $this->getCurrency($cart->id_currency);
320 if (is_array($currencies_module)) {
321 foreach ($currencies_module as $currency_module) {
322 if ($currency_order->id == $currency_module['id_currency']) {
323 return true;
324 }
325 }
326 }
327 return false;
328 }
329
330 public function getExternalPaymentOption()
331 {
332 $externalOption = new PaymentOption();
333 $externalOption->setCallToActionText($this->l('Pay by Credit/Debit Card'))
334 ->setAction($this->context->link->getModuleLink($this->name, 'payment', array(), true))
335 ->setInputs([
336 'TRTYPE' => [
337 'name' =>'TRTYPE',
338 'type' =>'hidden',
339 'value' =>'0',
340 ],
341 ])
342 ->setAdditionalInformation($this->context->smarty->fetch('module:HIDDEN/views/templates/front/payment_infos.tpl'));
343 return $externalOption;
344 }
345
346 public function hookPaymentReturn($params)
347 {
348 $state = $params['order']->getCurrentState();
349 if (
350 $state == Configuration::get('PS_OS_PREPARATION') ||
351 $state == Configuration::get('PS_OS_OUTOFSTOCK')
352 ) {
353 $this->context->smarty->assign('status', 'ok');
354 } else {
355 $this->context->smarty->assign('status', 'failed');
356 }
357 return $this->display(__FILE__, 'displayPaymentReturn.tpl');
358 }
359
360 public function hookActionOrderUpdatePostStatus($params)
361 {
362 if (!$this->active) {
363 return;
364 }
365
366 if (!$this->checkCurrency($params['cart'])) {
367 die('Missing cart params!');
368 }
369
370 if (OrderPayment::getByOrderId($params->id_order) == 'HIDDEN Gateway API') {
371 if ($params['newOrderStatus']->id == Configuration::get('PS_OS_SHIPPING')) {
372 $trtype = '21';
373 } elseif ($params['newOrderStatus']->id == Configuration::get('PS_OS_CANCELED')) {
374 $trtype = '24';
375 } else {
376 return false;
377 }
378 $sql = "UPDATE `"._DB_PREFIX_."HIDDEN_transactions` SET `trtype` = '".$trtype."' WHERE `id_order` = '".(int)$params->id_order."'";
379 Db::getInstance()->execute($sql);
380
381 $sql = "SELECT * FROM `"._DB_PREFIX_."HIDDEN_transactions` WHERE `id_order` = '".(int)$params->id_order."' LIMIT 1";
382 $query = Db::getInstance()->executeS($sql);
383 if ($query) {
384 foreach ($query as $row) {
385 $order = $row['order'];
386 $amount = $row['amount'];
387 $currency = $row['currency'];
388 $rrn = $row['rrn'];
389 $int_red = $row['int_ref'];
390 }
391 }
392
393 date_default_timezone_set("UTC");
394 $timestamp = strftime("%Y%m%d%H%M%S");
395 $nonce = Tools::strtoupper(md5(uniqid('nonce', true)));
396
397 $array_vb = array(
398 'ORDER' => $order,
399 'NONCE' => $nonce,
400 'TIMESTAMP' => $timestamp,
401 'TRTYPE' => $trtype,
402 'AMOUNT' => $amount
403 );
404
405 $p_sign = $this->createPsign($array_vb);
406
407 $post_fields = array(
408 'ORDER' => $order,
409 'AMOUNT' => $amount,
410 'CURRENCY' => $currency,
411 'RRN' => $rrn,
412 'INT_REF' => $int_ref,
413 'TRTYPE' => $trtype,
414 'TERMINAL' => $terminal,
415 'TIMESTAMP' => $timestamp,
416 'NONCE' => $nonce,
417 'P_SIGN' => $p_sign
418 );
419
420 $ch = curl_init();
421
422 curl_setopt($ch, CURLOPT_URL, Configuration::get('HIDDEN_GATEWAY'));
423 curl_setopt($ch, CURLOPT_POST, 1);
424 curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($post_fields));
425 } else {
426 return false;
427 }
428 }
429
430 public function createPsign($array)
431 {
432 $path = dirname(__FILE__);
433 $rsaKeyFile = $path . '/secure/HIDDEN-priv-key.pem';
434
435 $content = Tools::file_get_contents($rsaKeyFile);
436 $rsaPrivKey = openssl_get_privatekey($content);
437
438 $rsaKeyDetails = openssl_pkey_get_details($rsaPrivKey);
439 $rsaKeyLength = $rsaKeyDetails['bits'] / 8;
440
441 $data = $array;
442
443 $macSource = "";
444 foreach ($data as $value) {
445 if ($value != null) {
446 $macSource .= Tools::strlen($value) . $value;
447 } else {
448 $macSource .= "-";
449 }
450 }
451
452 $suffix = self::SUFFIX;
453 $prefix = self::PREFIX;
454 $md5Hash = Tools::strtoupper(md5($macSource));
455 $hashedData = $suffix;
456 $paddingLength = $rsaKeyLength - Tools::strlen($md5Hash) / 2 - Tools::strlen($prefix) / 2 - Tools::strlen($suffix) / 2;
457 for ($i = 0; $i < $paddingLength; $i++) {
458 $hashedData .= "FF";
459 }
460 $hashedData .= $prefix . $md5Hash;
461
462 $bin = pack("H*", $hashedData);
463 if (!openssl_private_encrypt($bin, $encryptedBin, $rsaPrivKey, OPENSSL_NO_PADDING)) {
464 while ($msg = openssl_error_string()) {
465 echo $msg . "<br />\n";
466 }
467 die ('Failed encrypt');
468 }
469 $hex = bin2hex($encryptedBin);
470 return Tools::strtoupper($hex);
471 }
472
473 public function checkPsign($array, $p_sign)
474 {
475 $data = $array;
476 $macSource = "";
477 foreach ($data as $value) {
478 if ($value != null) {
479 $macSource .= Tools::strlen($value) . $value;
480 } else {
481 $macSource .= "-";
482 }
483 }
484 $md5HashIn = Tools::strtoupper(md5($macSource));
485
486 $path = dirname(__FILE__);
487 $rsaKeyFile = $path . '/secure/HIDDEN-pub-key.pem';
488 $rsaPubKey = Tools::file_get_contents($rsaKeyFile);
489
490 $p_signbin = hex2bin($p_sign);
491 if (!openssl_public_decrypt($p_signbin, $decryptedBin, $rsaPubKey)) {
492 while ($msg = openssl_error_string()) {
493 echo $msg . "<br />\n";
494 }
495 die('Failed decrypt');
496 }
497
498 $decrypted = Tools::strtoupper(bin2hex($decryptedBin));
499 $prefix = self::PREFIX;
500 $decrypted_hash = str_replace($prefix, '', $decrypted);
501
502 return strcasecmp($decrypted_hash, $md5HashIn);
503 }
504}