Version Notes
Testing has been done on Magento versions 1.7-1.9.
There is no overloading of any classes so there should be no impact on existing functionality.
Download this release
Release Info
Developer | Mark Davidson-Houston |
Extension | Boku_Paymentgateway |
Version | 0.0.4 |
Comparing to | |
See all releases |
Version 0.0.4
- app/code/community/Boku/Paymentgateway/Block/Payment/Standard/Cancel.php +16 -0
- app/code/community/Boku/Paymentgateway/Block/Payment/Standard/Form.php +17 -0
- app/code/community/Boku/Paymentgateway/Block/Payment/Standard/Prepare.php +22 -0
- app/code/community/Boku/Paymentgateway/Block/Payment/Standard/Result.php +39 -0
- app/code/community/Boku/Paymentgateway/Block/Payment/Standard/Success.php +16 -0
- app/code/community/Boku/Paymentgateway/Helper/Data.php +400 -0
- app/code/community/Boku/Paymentgateway/Model/AdminSession.php +18 -0
- app/code/community/Boku/Paymentgateway/Model/Cron.php +18 -0
- app/code/community/Boku/Paymentgateway/Model/Mapped/Abstract.php +57 -0
- app/code/community/Boku/Paymentgateway/Model/Payment/Callback.php +19 -0
- app/code/community/Boku/Paymentgateway/Model/Payment/Chargeback.php +70 -0
- app/code/community/Boku/Paymentgateway/Model/Payment/Event.php +86 -0
- app/code/community/Boku/Paymentgateway/Model/Payment/Standard.php +76 -0
- app/code/community/Boku/Paymentgateway/Model/Payment/Transaction.php +364 -0
- app/code/community/Boku/Paymentgateway/Model/Prices.php +386 -0
- app/code/community/Boku/Paymentgateway/Model/Resource/Payment/Callback.php +20 -0
- app/code/community/Boku/Paymentgateway/Model/Resource/Payment/Callback/Collection.php +20 -0
- app/code/community/Boku/Paymentgateway/Model/Resource/Payment/Chargeback.php +19 -0
- app/code/community/Boku/Paymentgateway/Model/Resource/Payment/Chargeback/Collection.php +20 -0
- app/code/community/Boku/Paymentgateway/Model/Resource/Payment/Event.php +19 -0
- app/code/community/Boku/Paymentgateway/Model/Resource/Payment/Event/Collection.php +20 -0
- app/code/community/Boku/Paymentgateway/Model/Resource/Payment/Transaction.php +22 -0
- app/code/community/Boku/Paymentgateway/Model/Resource/Payment/Transaction/Collection.php +20 -0
- app/code/community/Boku/Paymentgateway/Model/Resource/Setup.php +12 -0
- app/code/community/Boku/Paymentgateway/Model/Session.php +18 -0
- app/code/community/Boku/Paymentgateway/Model/System/Config.php +71 -0
- app/code/community/Boku/Paymentgateway/Model/Test.php +72 -0
- app/code/community/Boku/Paymentgateway/Model/Xml.php +100 -0
- app/code/community/Boku/Paymentgateway/controllers/Adminhtml/BokuController.php +16 -0
- app/code/community/Boku/Paymentgateway/controllers/ApiController.php +236 -0
- app/code/community/Boku/Paymentgateway/controllers/StandardController.php +106 -0
- app/code/community/Boku/Paymentgateway/etc/adminhtml.xml +61 -0
- app/code/community/Boku/Paymentgateway/etc/config.xml +177 -0
- app/code/community/Boku/Paymentgateway/etc/system.xml +248 -0
- app/code/community/Boku/Paymentgateway/sql/boku_setup/install-0.0.1.php +146 -0
- app/code/community/Boku/Paymentgateway/sql/boku_setup/upgrade-0.0.1-0.0.2.php +45 -0
- app/design/adminhtml/default/default/layout/boku_paymentgateway.xml +27 -0
- app/design/adminhtml/default/default/template/boku/paymentgateway/test.phtml +63 -0
- app/design/frontend/base/default/layout/boku_paymentgateway.xml +37 -0
- app/design/frontend/base/default/template/boku/paymentgateway/standard/cancel.phtml +13 -0
- app/design/frontend/base/default/template/boku/paymentgateway/standard/form.phtml +14 -0
- app/design/frontend/base/default/template/boku/paymentgateway/standard/prepare.phtml +12 -0
- app/design/frontend/base/default/template/boku/paymentgateway/standard/success.phtml +13 -0
- app/etc/modules/Boku_Paymentgateway.xml +22 -0
- app/locale/en_US/Boku_Paymentgateway.csv +41 -0
- package.xml +21 -0
app/code/community/Boku/Paymentgateway/Block/Payment/Standard/Cancel.php
ADDED
@@ -0,0 +1,16 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* After failed Boku buy-url submission (via Prepare block)
|
4 |
+
*
|
5 |
+
* @category Payment gateway
|
6 |
+
* @package boku_paymentgateway
|
7 |
+
* @copyright Copyright (c) Boku (http://www.boku.com/)
|
8 |
+
* @author MDH <mdh@treatid.me.uk>
|
9 |
+
*/
|
10 |
+
|
11 |
+
class Boku_Paymentgateway_Block_Payment_Standard_Cancel extends Boku_Paymentgateway_Block_Payment_Standard_Result
|
12 |
+
{
|
13 |
+
protected function getRedirectUrl(){
|
14 |
+
return Mage::helper(self::APP_ROOT)->getUrl('checkout/onepage/failure');
|
15 |
+
}
|
16 |
+
}
|
app/code/community/Boku/Paymentgateway/Block/Payment/Standard/Form.php
ADDED
@@ -0,0 +1,17 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* Displayed for Boku payment option
|
4 |
+
*
|
5 |
+
* @category Payment gateway
|
6 |
+
* @package boku_paymentgateway
|
7 |
+
* @copyright Copyright (c) Boku (http://www.boku.com/)
|
8 |
+
* @author MDH <mdh@treatid.me.uk>
|
9 |
+
*/
|
10 |
+
|
11 |
+
class Boku_Paymentgateway_Block_Payment_Standard_Form extends Mage_Payment_Block_Form
|
12 |
+
{
|
13 |
+
protected function _construct(){
|
14 |
+
parent::_construct();
|
15 |
+
$this->setTemplate('boku/paymentgateway/standard/form.phtml');
|
16 |
+
}
|
17 |
+
}
|
app/code/community/Boku/Paymentgateway/Block/Payment/Standard/Prepare.php
ADDED
@@ -0,0 +1,22 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* Boku standard payment Form Block
|
4 |
+
*
|
5 |
+
* @category Payment gateway
|
6 |
+
* @package boku_paymentgateway
|
7 |
+
* @copyright Copyright (c) Boku (http://www.boku.com/)
|
8 |
+
* @author MDH <mdh@treatid.me.uk>
|
9 |
+
*/
|
10 |
+
|
11 |
+
class Boku_Paymentgateway_Block_Payment_Standard_Prepare extends Mage_Core_Block_Template
|
12 |
+
{
|
13 |
+
/**
|
14 |
+
* Returns the Boku gateway url
|
15 |
+
* This is set in Boku_Paymentgateway_Model_Payment_Standard
|
16 |
+
*
|
17 |
+
* @return string
|
18 |
+
*/
|
19 |
+
protected function getBuyUrl(){
|
20 |
+
return Mage::helper('boku')->getSession()->getData('buy-url');
|
21 |
+
}
|
22 |
+
}
|
app/code/community/Boku/Paymentgateway/Block/Payment/Standard/Result.php
ADDED
@@ -0,0 +1,39 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* Boku standard payment response Form Block
|
4 |
+
*
|
5 |
+
* @category Payment gateway
|
6 |
+
* @package boku_paymentgateway
|
7 |
+
* @copyright Copyright (c) Boku (http://www.boku.com/)
|
8 |
+
* @author MDH <mdh@treatid.me.uk>
|
9 |
+
*/
|
10 |
+
|
11 |
+
class Boku_Paymentgateway_Block_Payment_Standard_Result extends Mage_Core_Block_Template
|
12 |
+
{
|
13 |
+
const APP_ROOT = 'boku';
|
14 |
+
|
15 |
+
private $_trx_id = null;
|
16 |
+
private $_transaction = null;
|
17 |
+
private $_order = null;
|
18 |
+
|
19 |
+
protected function _construct(){
|
20 |
+
$data = Mage::app()->getRequest()->getParams();
|
21 |
+
if (isset($data['trx-id']))
|
22 |
+
$this->_trx_id = $data['trx-id'];
|
23 |
+
parent::_construct();
|
24 |
+
}
|
25 |
+
|
26 |
+
protected function getTransaction(){
|
27 |
+
if (empty($this->_transaction) && !empty($this->_trx_id))
|
28 |
+
$this->_transaction = Mage::helper(self::APP_ROOT)->getTransaction($this->_trx_id);
|
29 |
+
return $this->_transaction;
|
30 |
+
}
|
31 |
+
protected function getOrder(){
|
32 |
+
if (empty($this->_order) && !empty($this->_trx_id)){
|
33 |
+
$transaction = $this->getTransaction();
|
34 |
+
if (!empty($transaction))
|
35 |
+
$this->_order = $transaction->getOrder();
|
36 |
+
}
|
37 |
+
return $this->_order;
|
38 |
+
}
|
39 |
+
}
|
app/code/community/Boku/Paymentgateway/Block/Payment/Standard/Success.php
ADDED
@@ -0,0 +1,16 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* After successful Boku buy-url submission (via Prepare block)
|
4 |
+
*
|
5 |
+
* @category Payment gateway
|
6 |
+
* @package boku_paymentgateway
|
7 |
+
* @copyright Copyright (c) Boku (http://www.boku.com/)
|
8 |
+
* @author MDH <mdh@treatid.me.uk>
|
9 |
+
*/
|
10 |
+
|
11 |
+
class Boku_Paymentgateway_Block_Payment_Standard_Success extends Boku_Paymentgateway_Block_Payment_Standard_Result
|
12 |
+
{
|
13 |
+
protected function getRedirectUrl(){
|
14 |
+
return Mage::helper(self::APP_ROOT)->getUrl('checkout/onepage/success');
|
15 |
+
}
|
16 |
+
}
|
app/code/community/Boku/Paymentgateway/Helper/Data.php
ADDED
@@ -0,0 +1,400 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* Data helper
|
4 |
+
*
|
5 |
+
* @category Payment gateway
|
6 |
+
* @package boku_paymentgateway
|
7 |
+
* @copyright Copyright (c) Boku (http://www.boku.com/)
|
8 |
+
* @author MDH <mdh@treatid.me.uk>
|
9 |
+
*/
|
10 |
+
|
11 |
+
class Boku_Paymentgateway_Helper_Data extends Mage_Core_Helper_Abstract
|
12 |
+
{
|
13 |
+
const APP_ROOT = 'boku';
|
14 |
+
const CONFIG_ROOT = 'payment/boku';
|
15 |
+
|
16 |
+
/**
|
17 |
+
* Are we in the admin system ?
|
18 |
+
*
|
19 |
+
* @return boolean
|
20 |
+
*/
|
21 |
+
public static function isAdmin(){
|
22 |
+
return Mage::app()->getStore()->isAdmin() || Mage::getDesign()->getArea() == 'adminhtml';
|
23 |
+
}
|
24 |
+
|
25 |
+
/**
|
26 |
+
* get the country ISO code
|
27 |
+
* If there is a quote in the basket and it has a billing address then uses this
|
28 |
+
* otherwise it defaults to the store's country.
|
29 |
+
*
|
30 |
+
* @return string
|
31 |
+
*/
|
32 |
+
public static function getCountryCode(){
|
33 |
+
if (($q = self::getQuote()) && ($m = $q->getBillingAddress()) && ($m = $m->getCountryId()))
|
34 |
+
return $m;
|
35 |
+
return self::getStore()->getConfig('general/country/default');
|
36 |
+
}
|
37 |
+
|
38 |
+
/**
|
39 |
+
* get the base currency ISO code
|
40 |
+
*
|
41 |
+
* @return string
|
42 |
+
*/
|
43 |
+
public static function getBaseCurrencyCode(){
|
44 |
+
return self::getStore()->getBaseCurrencyCode();
|
45 |
+
}
|
46 |
+
|
47 |
+
/**
|
48 |
+
* get the current quote/order's currency ISO code
|
49 |
+
*
|
50 |
+
* @return string
|
51 |
+
*/
|
52 |
+
public static function getCurrencyCode(){
|
53 |
+
return self::getQuote()->getQuoteCurrencyCode();
|
54 |
+
}
|
55 |
+
|
56 |
+
/**
|
57 |
+
* Get a currency's decimal places
|
58 |
+
*
|
59 |
+
* @param string (ISO 4217) $currency
|
60 |
+
* @return int
|
61 |
+
*/
|
62 |
+
public static function getCurrencyPrecision($currency){
|
63 |
+
return Mage::getSingleton(self::APP_ROOT.'/prices')->getCurrencyPrecision($currency);
|
64 |
+
}
|
65 |
+
|
66 |
+
/**
|
67 |
+
* Get the currency value expressed in the fractional currency unit
|
68 |
+
*
|
69 |
+
* @param float $price
|
70 |
+
* @param string (ISO 4217) $currency
|
71 |
+
* @return int
|
72 |
+
*/
|
73 |
+
public static function getIntegerPrice($price, $currency){
|
74 |
+
return Mage::getSingleton(self::APP_ROOT.'/prices')->getIntegerPrice($price, $currency);
|
75 |
+
}
|
76 |
+
|
77 |
+
/**
|
78 |
+
* Convert a value expressed in the fractional currency unit to the normal float value
|
79 |
+
*
|
80 |
+
* @param int $price
|
81 |
+
* @param string (ISO 4217) $currency
|
82 |
+
* @return float
|
83 |
+
*/
|
84 |
+
public static function getFloatPrice($price, $currency){
|
85 |
+
return Mage::getSingleton(self::APP_ROOT.'/prices')->getFloatPrice($price, $currency);
|
86 |
+
}
|
87 |
+
|
88 |
+
/**
|
89 |
+
* convert from one currency to another
|
90 |
+
*
|
91 |
+
* @param number $val
|
92 |
+
* @param string $currency_from - ISO code for $val currency - default store currency
|
93 |
+
* @param string $currency_to - ISO code for return currency - default base currency
|
94 |
+
* @return number
|
95 |
+
*/
|
96 |
+
public static function convertCurrency($val, $currency_from = null, $currency_to = null){
|
97 |
+
if (empty($currency_from)) $currency_from = self::getCurrencyCode();
|
98 |
+
if (empty($currency_to)) $currency_to = self::getBaseCurrencyCode();
|
99 |
+
$currency_from = strtoupper($currency_from);
|
100 |
+
$currency_to = strtoupper($currency_to);
|
101 |
+
if ($currency_from != $currency_to)
|
102 |
+
$val = Mage::helper('directory')->currencyConvert($val, $currency_from, $currency_to);
|
103 |
+
return $val;
|
104 |
+
}
|
105 |
+
public static function convertToBaseCurrency($val, $currency = null){
|
106 |
+
return self::convertCurrency($val, $currency);
|
107 |
+
}
|
108 |
+
|
109 |
+
public static function getCheckout(){
|
110 |
+
return Mage::getModel('checkout/cart');
|
111 |
+
}
|
112 |
+
|
113 |
+
/**
|
114 |
+
* Get the current quote
|
115 |
+
*
|
116 |
+
* @return Mage_Sales_Model_Quote
|
117 |
+
*/
|
118 |
+
public static function getQuote(){
|
119 |
+
return self::isAdmin() ? Mage::getSingleton('adminhtml/session_quote')->getQuote() : self::getCheckout()->getQuote();
|
120 |
+
}
|
121 |
+
|
122 |
+
/**
|
123 |
+
* @param string $trx_id
|
124 |
+
* @return Boku_Paymentgateway_Model_Payment_Transaction | null
|
125 |
+
*/
|
126 |
+
public static function getTransaction($trx_id){
|
127 |
+
return Mage::getSingleton(self::APP_ROOT.'/payment_transaction')->getTransaction($trx_id);
|
128 |
+
}
|
129 |
+
|
130 |
+
/**
|
131 |
+
* @return string | null
|
132 |
+
*/
|
133 |
+
public static function getPhone(){
|
134 |
+
if (($m = self::getQuote()) && ($m = $m->getBillingAddress()) && ($m = $m->getTelephone()))
|
135 |
+
return $m;
|
136 |
+
return null;
|
137 |
+
}
|
138 |
+
|
139 |
+
public static function getSession(){
|
140 |
+
return Mage::getSingleton(self::APP_ROOT.'/'.(self::isAdmin() ? 'adminSession' : 'session'));
|
141 |
+
}
|
142 |
+
|
143 |
+
/**
|
144 |
+
* Creates order payment/transaction records and updates order paid values
|
145 |
+
* amount and total need to be in the same currency as the order and transaction
|
146 |
+
*
|
147 |
+
* @param array $data - {trx_id, amount, currency, total}
|
148 |
+
* @return Mage_Sales_Model_Order_Payment|null
|
149 |
+
*/
|
150 |
+
public static function createPayment($data){
|
151 |
+
try{
|
152 |
+
$trx_id = $data['trx_id'];
|
153 |
+
if (is_null($transaction = self::getTransaction($trx_id)))
|
154 |
+
throw new Exception('Transaction '.$trx_id.' not found');
|
155 |
+
return $transaction->addPayment($data);
|
156 |
+
}catch(Exception $e){
|
157 |
+
self::logErr(__METHOD__.' - '.$e->getMessage());
|
158 |
+
return null;
|
159 |
+
}
|
160 |
+
}
|
161 |
+
|
162 |
+
/**
|
163 |
+
* Creates order payment/transaction records and updates order refund values
|
164 |
+
* amount needs to be in the same currency as the order and transaction
|
165 |
+
*
|
166 |
+
* @param array $data - {trx_id, amount, currency}
|
167 |
+
* @return Mage_Sales_Model_Order_Payment|null
|
168 |
+
*/
|
169 |
+
public static function createRefund($data){
|
170 |
+
try{
|
171 |
+
$trx_id = $data['trx_id'];
|
172 |
+
if (is_null($transaction = self::getTransaction($trx_id)))
|
173 |
+
throw new Exception('Transaction '.$trx_id.' not found');
|
174 |
+
return $transaction->addRefund($data);
|
175 |
+
}catch(Exception $e){
|
176 |
+
self::logErr(__METHOD__.' - '.$e->getMessage());
|
177 |
+
return null;
|
178 |
+
}
|
179 |
+
}
|
180 |
+
|
181 |
+
/**
|
182 |
+
* @param Mage_Sales_Model_Order $order
|
183 |
+
* @return Mage_Sales_Model_Order_Invoice|null
|
184 |
+
*/
|
185 |
+
public static function generateInvoice($order){
|
186 |
+
try{
|
187 |
+
$invoice = $order->prepareInvoice()
|
188 |
+
->setRequestedCaptureCase(Mage_Sales_Model_Order_Invoice::NOT_CAPTURE)
|
189 |
+
->setState(Mage_Sales_Model_Order_Invoice::STATE_PAID)
|
190 |
+
->addComment('Auto-Generated by Boku')
|
191 |
+
->register();
|
192 |
+
Mage::getModel('core/resource_transaction')
|
193 |
+
->addObject($invoice)
|
194 |
+
->addObject($invoice->getOrder())
|
195 |
+
->save();
|
196 |
+
$invoice->sendEmail(true);
|
197 |
+
}catch(Exception $e2){self::logErr(__METHOD__.' - '.$e->getMessage());}
|
198 |
+
return isset($invoice) ? $invoice : null;
|
199 |
+
}
|
200 |
+
|
201 |
+
/**
|
202 |
+
* Runs outstanding actions related to Boku callbacks
|
203 |
+
* Because of the asynchronous nature of Boku callbacks we might need a cron job to run this
|
204 |
+
* Otherwise we could force completion when we view an order in the admin
|
205 |
+
*
|
206 |
+
* @param string $trx_id - if null then looks at all transactions
|
207 |
+
*/
|
208 |
+
public static function completeOutstanding($trx_id = null){
|
209 |
+
foreach(array('event','chargeback','transaction') as $c)
|
210 |
+
Mage::getSingleton(self::APP_ROOT.'/payment_'.$c)->completeOutstanding($trx_id);
|
211 |
+
}
|
212 |
+
|
213 |
+
/**
|
214 |
+
* Used for creating or verifying the signature field in Boku api calls
|
215 |
+
*
|
216 |
+
* @param array $data
|
217 |
+
* @return string
|
218 |
+
*/
|
219 |
+
public static function getCompressedParameterString(&$data){
|
220 |
+
ksort($data);
|
221 |
+
$t = '';
|
222 |
+
foreach($data as $k=>$v){
|
223 |
+
$v = trim((string) $v);
|
224 |
+
if ($v != '') $t .= trim($k).$v;
|
225 |
+
}
|
226 |
+
return $t;
|
227 |
+
}
|
228 |
+
|
229 |
+
/**
|
230 |
+
* Add the Boku sig field to the params and add or updates the timestamp field
|
231 |
+
* These fields are required for all Boku api calls.
|
232 |
+
*
|
233 |
+
* @param array $params
|
234 |
+
*/
|
235 |
+
public static function addSignature(&$params){
|
236 |
+
$api_key = self::getConfig('api_security_key');
|
237 |
+
$params['timestamp'] = str_pad(time(), 10, '0', STR_PAD_LEFT);
|
238 |
+
$t = self::getCompressedParameterString($params);
|
239 |
+
$params['sig'] = md5($t.$api_key);
|
240 |
+
}
|
241 |
+
|
242 |
+
/**
|
243 |
+
* Build a Boku URL - adds the timestamp and sig parameters
|
244 |
+
*
|
245 |
+
* @param string $url
|
246 |
+
* @param array $params
|
247 |
+
* @return string
|
248 |
+
*/
|
249 |
+
public static function buildURL($url, $params = array()){
|
250 |
+
if (($i = strpos($url, '?')) != false){
|
251 |
+
$query = substr($url, $i + 1);
|
252 |
+
$url = substr($url, 0, $i);
|
253 |
+
foreach(explode('&', $query) as $p){
|
254 |
+
$pa = explode('=', $p);
|
255 |
+
$k = urldecode($pa[0]);
|
256 |
+
if (!array_key_exists($k, $params))
|
257 |
+
$params[$k] = urldecode($pa[1]);
|
258 |
+
}
|
259 |
+
}
|
260 |
+
self::addSignature($params);
|
261 |
+
$url .= '?';
|
262 |
+
foreach($params as $k=>$v)
|
263 |
+
$url .= urlencode($k).'='.urlencode($v).'&';
|
264 |
+
return $url;
|
265 |
+
}
|
266 |
+
|
267 |
+
/* function getRemoteIp() {
|
268 |
+
$data = function_exists('apache_request_headers') ? apache_request_headers() : $_SERVER;
|
269 |
+
|
270 |
+
foreach (array(
|
271 |
+
'X-Forwarded-For',
|
272 |
+
'HTTP_CLIENT_IP',
|
273 |
+
'HTTP_X_FORWARDED',
|
274 |
+
'HTTP_X_CLUSTER_CLIENT_IP',
|
275 |
+
'HTTP_FORWARDED_FOR',
|
276 |
+
'HTTP_FORWARDED',
|
277 |
+
'REMOTE_ADDR',
|
278 |
+
) as $key)
|
279 |
+
if (array_key_exists($key, $data) && filter_var($data[$key], FILTER_VALIDATE_IP, FILTER_FLAG_IPV4))
|
280 |
+
return $data[$key];
|
281 |
+
return $_SERVER['REMOTE_ADDR'];
|
282 |
+
}
|
283 |
+
*/
|
284 |
+
/**
|
285 |
+
* checks the validity of the sig parameter in the Boku callback url
|
286 |
+
* $data can be full url, just the query part or array of query parameters
|
287 |
+
*
|
288 |
+
* @param mixed $data
|
289 |
+
* @return boolean
|
290 |
+
*/
|
291 |
+
public static function verifySignature($data){
|
292 |
+
if (!is_array($data)){
|
293 |
+
if (!is_string($data)) return false;
|
294 |
+
if (strpos($data, 'sig=') === false) return false;
|
295 |
+
$params = array();
|
296 |
+
if (($i = strpos($data, '?')) !== false)
|
297 |
+
$data = substr($data, $i + 1);
|
298 |
+
foreach(explode('&', $data) as $p){
|
299 |
+
$pa = explode('=', $p);
|
300 |
+
$k = urldecode($pa[0]);
|
301 |
+
if (!array_key_exists($k, $params))
|
302 |
+
$params[$k] = trim(urldecode($pa[1]));
|
303 |
+
}
|
304 |
+
}elseif(!array_key_exists('sig', $params = $data))
|
305 |
+
return false;
|
306 |
+
$api_key = self::getConfig('api_security_key');
|
307 |
+
$sig = $params['sig'];
|
308 |
+
unset($params['sig']);
|
309 |
+
$t = self::getCompressedParameterString($params);
|
310 |
+
return strcasecmp($sig, md5($t.$api_key)) == 0;
|
311 |
+
}
|
312 |
+
|
313 |
+
public static function getUrl($route = null, $params = null){
|
314 |
+
$store = self::getStore();
|
315 |
+
if (empty($params))
|
316 |
+
$params = array('_store'=>$store->getId());
|
317 |
+
else
|
318 |
+
$params['_store'] = $store->getId();
|
319 |
+
return Mage::getUrl($route, $params);
|
320 |
+
}
|
321 |
+
|
322 |
+
/**
|
323 |
+
* Urls for Boku prepare call
|
324 |
+
*
|
325 |
+
* @return string url
|
326 |
+
*/
|
327 |
+
public static function getCallbackUrl(){
|
328 |
+
$url = self::getConfig('url/callback');
|
329 |
+
if (empty($url))
|
330 |
+
$url = self::getUrl(self::APP_ROOT.'/api');
|
331 |
+
return $url;
|
332 |
+
}
|
333 |
+
public static function getSuccessUrl(){
|
334 |
+
return self::getUrl(self::APP_ROOT.'/standard/success');
|
335 |
+
}
|
336 |
+
public static function getFailUrl(){
|
337 |
+
return self::getUrl(self::APP_ROOT.'/standard/cancel');
|
338 |
+
}
|
339 |
+
|
340 |
+
/**
|
341 |
+
* @return Mage_Core_Model_Store | Mage_Core_Model_Website
|
342 |
+
*/
|
343 |
+
public static function getScopeObject(){
|
344 |
+
$session = self::getSession();
|
345 |
+
$obj = $session->getScopeObject();
|
346 |
+
if (!empty($obj)) return $obj;
|
347 |
+
$params = Mage::app()->getRequest()->getParams();
|
348 |
+
if (isset($params['store']))
|
349 |
+
$obj = Mage::app()->getStore($params['store']);
|
350 |
+
elseif (isset($params['website']))
|
351 |
+
$obj = Mage::app()->getWebsite($params['website']);
|
352 |
+
else
|
353 |
+
$obj = Mage::app()->getStore();
|
354 |
+
$session->setScopeObject($obj);
|
355 |
+
return $obj;
|
356 |
+
}
|
357 |
+
|
358 |
+
/**
|
359 |
+
* @return Mage_Core_Model_Store
|
360 |
+
*/
|
361 |
+
public static function getStore(){
|
362 |
+
$obj = self::getScopeObject();
|
363 |
+
if ($obj instanceof Mage_Core_Model_Website){
|
364 |
+
$store = $obj->getDefaultStore();
|
365 |
+
if (!empty($store)) $obj = $store;
|
366 |
+
}
|
367 |
+
if (!($obj instanceof Mage_Core_Model_Store))
|
368 |
+
$obj = Mage::app()->getStore();
|
369 |
+
return $obj;
|
370 |
+
}
|
371 |
+
|
372 |
+
/**
|
373 |
+
* Sets the current config scope to a particular store.
|
374 |
+
* clears the scope if $store_id == null
|
375 |
+
*
|
376 |
+
* @param int|string $store_id
|
377 |
+
*/
|
378 |
+
public static function setStore($store_id){
|
379 |
+
if (is_null($store_id))
|
380 |
+
self::getSession()->unsScopeObject();
|
381 |
+
elseif (self::getStore()->getId() != $store_id)
|
382 |
+
self::getSession()->setScopeObject(Mage::app()->getStore($store_id));
|
383 |
+
}
|
384 |
+
|
385 |
+
/**
|
386 |
+
* Get config data specific to this plugin and current store context
|
387 |
+
*
|
388 |
+
* @return string
|
389 |
+
*/
|
390 |
+
public static function getConfig($key){
|
391 |
+
return self::getStore()->getConfig(self::CONFIG_ROOT.'/'.$key);
|
392 |
+
}
|
393 |
+
|
394 |
+
public static function log($msg, $type = Zend_Log::INFO){
|
395 |
+
Mage::log($msg, $type, self::APP_ROOT.'.log');
|
396 |
+
}
|
397 |
+
public static function logErr($msg){
|
398 |
+
self::log($msg, Zend_Log::ERR);
|
399 |
+
}
|
400 |
+
}
|
app/code/community/Boku/Paymentgateway/Model/AdminSession.php
ADDED
@@ -0,0 +1,18 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* Boku transaction admin session data store
|
4 |
+
*
|
5 |
+
* @category Payment gateway
|
6 |
+
* @package boku_paymentgateway
|
7 |
+
* @copyright Copyright (c) Boku (http://www.boku.com/)
|
8 |
+
* @author MDH <mdh@treatid.me.uk>
|
9 |
+
*/
|
10 |
+
|
11 |
+
class Boku_Paymentgateway_Model_AdminSession extends Mage_Core_Model_Session_Abstract
|
12 |
+
{
|
13 |
+
const APP_ROOT = 'boku';
|
14 |
+
|
15 |
+
public function __construct(){
|
16 |
+
$this->init(self::APP_ROOT.'admin');
|
17 |
+
}
|
18 |
+
}
|
app/code/community/Boku/Paymentgateway/Model/Cron.php
ADDED
@@ -0,0 +1,18 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* Boku model for any cron bits
|
4 |
+
*
|
5 |
+
* @category Payment gateway
|
6 |
+
* @package boku_paymentgateway
|
7 |
+
* @copyright Copyright (c) Boku (http://www.boku.com/)
|
8 |
+
* @author MDH <mdh@treatid.me.uk>
|
9 |
+
*/
|
10 |
+
|
11 |
+
class Boku_Paymentgateway_Model_Cron
|
12 |
+
{
|
13 |
+
const APP_ROOT = 'boku';
|
14 |
+
|
15 |
+
public function run(){
|
16 |
+
Mage::helper(self::APP_ROOT)->completeOutstanding();
|
17 |
+
}
|
18 |
+
}
|
app/code/community/Boku/Paymentgateway/Model/Mapped/Abstract.php
ADDED
@@ -0,0 +1,57 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* Simple extension of core model abtract to accommodate field mapping
|
4 |
+
* $_field_map is an array of from=>to mappings.
|
5 |
+
*
|
6 |
+
* @category Payment gateway
|
7 |
+
* @package boku_paymentgateway
|
8 |
+
* @copyright Copyright (c) Boku (http://www.boku.com/)
|
9 |
+
* @author MDH <mdh@treatid.me.uk>
|
10 |
+
*/
|
11 |
+
|
12 |
+
abstract class Boku_Paymentgateway_Model_Mapped_Abstract extends Mage_Core_Model_Abstract
|
13 |
+
{
|
14 |
+
const APP_ROOT = 'boku';
|
15 |
+
|
16 |
+
protected $_field_map = array();
|
17 |
+
|
18 |
+
protected function _mapField($field){
|
19 |
+
if (!empty($field) && array_key_exists($field = str_replace('-', '_', $field), $this->_field_map))
|
20 |
+
$field = $this->_field_map[$field];
|
21 |
+
return $field;
|
22 |
+
}
|
23 |
+
/**
|
24 |
+
* Warning: if a field is mapped to another field then the other with be replaced
|
25 |
+
*/
|
26 |
+
protected function &_map(&$data){
|
27 |
+
if (is_array($data)){
|
28 |
+
foreach ($data as $field=>&$value)
|
29 |
+
if (($mapped_field = $this->_mapField($field)) != $field)
|
30 |
+
$data[$mapped_field] = $value;
|
31 |
+
}else
|
32 |
+
$data = $this->_mapField($data);
|
33 |
+
return $data;
|
34 |
+
}
|
35 |
+
public function map($data){return $this->_map($data);}
|
36 |
+
|
37 |
+
public function load($id, $field=null){return parent::load($id, $this->_map($field));}
|
38 |
+
public function addData(array $arr){return parent::addData($this->_map($arr));}
|
39 |
+
public function setData($key, $value=null){return parent::setData($this->_map($key), $value);}
|
40 |
+
public function unsetData($key=null){return parent::unsetData($this->_map($key));}
|
41 |
+
public function unsetOldData($key=null){return parent::unsetOldData($this->_map($key));}
|
42 |
+
public function getData($key='', $index=null){return parent::getData($this->_map($key), $index);}
|
43 |
+
public function setDataUsingMethod($key, $args=array()){return parent::setDataUsingMethod($this->_map($key), $args=array());}
|
44 |
+
public function getDataUsingMethod($key, $args=null){return parent::getDataUsingMethod($this->_map($key), $args);}
|
45 |
+
public function getDataSetDefault($key, $default){return parent::getDataSetDefault($this->_map($key), $default);}
|
46 |
+
public function hasData($key=''){return parent::hasData($this->_map($key));}
|
47 |
+
|
48 |
+
/* public function toArray(array $arrAttributes = array()){return parent::toArray($arrAttributes);}
|
49 |
+
public function toXml(array $arrAttributes = array(), $rootName = 'item', $addOpenTag=false, $addCdata=true){return parent::toXml($arrAttributes, $rootName, $addOpenTag, $addCdata);}
|
50 |
+
*/
|
51 |
+
public function __get($var){return parent::__get($this->_map($var));}
|
52 |
+
public function __set($var, $value){parent::__set($this->_map($var), $value);}
|
53 |
+
public function getOrigData($key=null){return parent::getOrigData($this->_map($key));}
|
54 |
+
public function setOrigData($key=null, $data=null){return parent::setOrigData($this->_map($key), $data);}
|
55 |
+
public function isDirty($field=null){return parent::isDirty($this->_map($field));}
|
56 |
+
public function flagDirty($field, $flag=true){return parent::flagDirty($this->_map($field), $flag);}
|
57 |
+
}
|
app/code/community/Boku/Paymentgateway/Model/Payment/Callback.php
ADDED
@@ -0,0 +1,19 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* @category Payment gateway
|
4 |
+
* @package boku_paymentgateway
|
5 |
+
* @copyright Copyright (c) Boku (http://www.boku.com/)
|
6 |
+
* @author MDH <mdh@treatid.me.uk>
|
7 |
+
*/
|
8 |
+
|
9 |
+
Class Boku_Paymentgateway_Model_Payment_Callback extends Boku_Paymentgateway_Model_Mapped_Abstract{
|
10 |
+
|
11 |
+
/**
|
12 |
+
* Initialize resource model
|
13 |
+
*/
|
14 |
+
protected function _construct(){
|
15 |
+
$this->_init(self::APP_ROOT.'/payment_callback');
|
16 |
+
return parent::_construct();
|
17 |
+
}
|
18 |
+
|
19 |
+
}
|
app/code/community/Boku/Paymentgateway/Model/Payment/Chargeback.php
ADDED
@@ -0,0 +1,70 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* @category Payment gateway
|
4 |
+
* @package boku_paymentgateway
|
5 |
+
* @copyright Copyright (c) Boku (http://www.boku.com/)
|
6 |
+
* @author MDH <mdh@treatid.me.uk>
|
7 |
+
*/
|
8 |
+
|
9 |
+
Class Boku_Paymentgateway_Model_Payment_Chargeback extends Boku_Paymentgateway_Model_Mapped_Abstract{
|
10 |
+
|
11 |
+
/**
|
12 |
+
* Initialize resource model
|
13 |
+
*/
|
14 |
+
protected function _construct(){
|
15 |
+
$this->_init(self::APP_ROOT.'/payment_chargeback');
|
16 |
+
return parent::_construct();
|
17 |
+
}
|
18 |
+
|
19 |
+
/**
|
20 |
+
* Attempts to creates Mage_Sales_Model_Order_Payment
|
21 |
+
* If successful or unneccessary then the handled flag is set to true
|
22 |
+
*
|
23 |
+
* @return boolean
|
24 |
+
*/
|
25 |
+
public function complete(){
|
26 |
+
if ($this->getHandled()) return true;
|
27 |
+
$helper = Mage::helper(self::APP_ROOT);
|
28 |
+
try{
|
29 |
+
$currency = $this->getCurrency();
|
30 |
+
$refund = $helper->createRefund(array(
|
31 |
+
'trx_id'=>$this->getTrxId(),
|
32 |
+
'amount'=>$helper->getFloatPrice($this->getChargebackamount(), $currency),
|
33 |
+
'currency'=>$currency,
|
34 |
+
));
|
35 |
+
if (empty($refund)) throw new Exception('Failed to create refund.');
|
36 |
+
|
37 |
+
$this->setHandled(true)->save();
|
38 |
+
}catch(Exception $e){$helper->logErr(__METHOD__.' - '.$e->getMessage()); return false;}
|
39 |
+
return true;
|
40 |
+
}
|
41 |
+
|
42 |
+
/**
|
43 |
+
* runs complete on any uncompleted records
|
44 |
+
*
|
45 |
+
* @param string $trx_id - if null then looks at all transactions
|
46 |
+
*/
|
47 |
+
public function completeOutstanding($trx_id = null){
|
48 |
+
$c = $this->getCollection()->addFieldToFilter('handled', 0);
|
49 |
+
if (!is_null($trx_id)) $c->addFieldToFilter('trx_id', $trx_id);
|
50 |
+
foreach($c->load() as $model) $model->complete();
|
51 |
+
}
|
52 |
+
|
53 |
+
/**
|
54 |
+
* Creates a new chargeback record.
|
55 |
+
* Fails if one already exists for the particular trx-id (only one allowed)
|
56 |
+
*
|
57 |
+
* @param array &$idata
|
58 |
+
* @return Boku_Paymentgateway_Model_Payment_Chargeback
|
59 |
+
*/
|
60 |
+
public static function create(&$idata){
|
61 |
+
$model = new self();
|
62 |
+
$data = $model->map($idata);
|
63 |
+
$trx_id = $data['trx_id'];
|
64 |
+
$id = $model->load($trx_id, 'trx_id')->getId();
|
65 |
+
if (!empty($id))
|
66 |
+
throw new Exception(__METHOD__.' - A chargeback is already present for transaction '.$trx_id.' (only one allowed).');
|
67 |
+
$model->setData($data)->save()->complete();
|
68 |
+
return $model;
|
69 |
+
}
|
70 |
+
}
|
app/code/community/Boku/Paymentgateway/Model/Payment/Event.php
ADDED
@@ -0,0 +1,86 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* Record of Boku event callbacks created by Boku_Paymentgateway_ApiController
|
4 |
+
*
|
5 |
+
* @category Payment gateway
|
6 |
+
* @package boku_paymentgateway
|
7 |
+
* @copyright Copyright (c) Boku (http://www.boku.com/)
|
8 |
+
* @author MDH <mdh@treatid.me.uk>
|
9 |
+
*/
|
10 |
+
|
11 |
+
Class Boku_Paymentgateway_Model_Payment_Event extends Boku_Paymentgateway_Model_Mapped_Abstract{
|
12 |
+
|
13 |
+
const PSMS_MT_SUB = 1;
|
14 |
+
const PSMS_MT_DEL = 2;
|
15 |
+
const PSMS_MO_REC = 3;
|
16 |
+
const PSMS_MO_NON_REC = 4;
|
17 |
+
|
18 |
+
/**
|
19 |
+
* Initialize resource model
|
20 |
+
*/
|
21 |
+
protected function _construct(){
|
22 |
+
$this->_init(self::APP_ROOT.'/payment_event');
|
23 |
+
return parent::_construct();
|
24 |
+
}
|
25 |
+
/**
|
26 |
+
* Attempts to creates Mage_Sales_Model_Order_Payment
|
27 |
+
* If successful or unneccessary then the handled flag is set to true
|
28 |
+
*
|
29 |
+
* @return boolean
|
30 |
+
*/
|
31 |
+
public function complete(){
|
32 |
+
if ($this->getHandled()) return true;
|
33 |
+
$helper = Mage::helper(self::APP_ROOT);
|
34 |
+
try{
|
35 |
+
switch ($this->getEventCode()){
|
36 |
+
case self::PSMS_MT_DEL:
|
37 |
+
case self::PSMS_MO_REC:
|
38 |
+
$currency = $this->getCurrency();
|
39 |
+
$payment = $helper->createPayment(array(
|
40 |
+
'trx_id'=>$this->getTrxId(),
|
41 |
+
'amount'=>$helper->getFloatPrice($this->getMessageCost(), $currency),
|
42 |
+
'currency'=>$currency,
|
43 |
+
'total'=>$helper->getFloatPrice($this->getPaid(), $currency),
|
44 |
+
));
|
45 |
+
if (empty($payment)) throw new Exception('Failed to create payment.');
|
46 |
+
}
|
47 |
+
$this->setHandled(true)->save();
|
48 |
+
}catch(Exception $e){$helper->logErr(__METHOD__.' - '.$e->getMessage()); return false;}
|
49 |
+
return true;
|
50 |
+
}
|
51 |
+
|
52 |
+
/**
|
53 |
+
* runs complete on any uncompleted records
|
54 |
+
*
|
55 |
+
* @param string $trx_id - if null then looks at all transactions
|
56 |
+
*/
|
57 |
+
public function completeOutstanding($trx_id = null){
|
58 |
+
$helper = Mage::helper(self::APP_ROOT);
|
59 |
+
$c = $this->getCollection()->addFieldToFilter('handled', 0);
|
60 |
+
if (!is_null($trx_id)) $c->addFieldToFilter('trx_id', $trx_id);
|
61 |
+
$failed = 0;
|
62 |
+
foreach ($c->load() as $model){
|
63 |
+
$transaction = $helper->getTransaction($model->getTrxId());
|
64 |
+
if (empty($transaction)) {$failed++; continue;}
|
65 |
+
$helper->setStore($transaction->getStoreId());
|
66 |
+
if (!$model->complete()) $failed++;
|
67 |
+
}
|
68 |
+
if ($failed) $helper->log(__METHOD__.': '.$failed.' failed.');
|
69 |
+
}
|
70 |
+
|
71 |
+
/**
|
72 |
+
* Creates a new event record
|
73 |
+
* WARNING we should check whether this event has already been logged
|
74 |
+
*
|
75 |
+
* @param array $data
|
76 |
+
* @return Boku_Paymentgateway_Model_Payment_Event
|
77 |
+
*/
|
78 |
+
public static function create(&$idata){
|
79 |
+
$model = new self();
|
80 |
+
$data = $model->map($idata);
|
81 |
+
if (isset($data['reference_currency']) && isset($data['paid']) && isset($data['reference_paid']))
|
82 |
+
try{$data['exchange'] = ((float) $data['paid']) / $data['reference_paid'];}catch(Exception $e){}
|
83 |
+
$model->setData($data)->save()->complete();
|
84 |
+
return $model;
|
85 |
+
}
|
86 |
+
}
|
app/code/community/Boku/Paymentgateway/Model/Payment/Standard.php
ADDED
@@ -0,0 +1,76 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* Boku standard checkout module
|
4 |
+
*
|
5 |
+
* @category Payment gateway
|
6 |
+
* @package boku_paymentgateway
|
7 |
+
* @copyright Copyright (c) Boku (http://www.boku.com/)
|
8 |
+
* @author MDH <mdh@treatid.me.uk>
|
9 |
+
*/
|
10 |
+
|
11 |
+
class Boku_Paymentgateway_Model_Payment_Standard extends Mage_Payment_Model_Method_Abstract
|
12 |
+
{
|
13 |
+
const APP_ROOT = 'boku';
|
14 |
+
|
15 |
+
protected $_code = self::APP_ROOT;
|
16 |
+
protected $_formBlockType = 'boku/payment_standard_form';
|
17 |
+
|
18 |
+
protected $_canUseForMultishipping = true;
|
19 |
+
protected $_isGateway = true;
|
20 |
+
protected $_isInitializeNeeded = true;
|
21 |
+
|
22 |
+
// NOT POSSIBLE YET
|
23 |
+
protected $_canUseInternal = false;
|
24 |
+
|
25 |
+
/**
|
26 |
+
* This makes sure that the config settings have values
|
27 |
+
* Note: there is no guarantee that the values are correct !
|
28 |
+
*
|
29 |
+
* @see Mage_Payment_Model_Method_Abstract::canUseCheckout()
|
30 |
+
* @return bool
|
31 |
+
*/
|
32 |
+
public function canUseCheckout(){
|
33 |
+
$helper = Mage::helper(self::APP_ROOT);
|
34 |
+
$merchant_id = $helper->getConfig('merchant_id');
|
35 |
+
$api_security_key = $helper->getConfig('api_security_key');
|
36 |
+
$service_id = $helper->getConfig('service_id');
|
37 |
+
return !(empty($merchant_id) || empty($api_security_key) || empty($service_id));
|
38 |
+
}
|
39 |
+
|
40 |
+
/**
|
41 |
+
* Check whether payment method is applicable to quote
|
42 |
+
* Note may get called multiple times during the payment process (by separate ajax requests)
|
43 |
+
*
|
44 |
+
* @param $currency
|
45 |
+
* @return bool
|
46 |
+
*/
|
47 |
+
public function canUseForCurrency($currency){
|
48 |
+
$helper = Mage::helper(self::APP_ROOT);
|
49 |
+
$model = $helper->getQuote();
|
50 |
+
return Mage::getSingleton(self::APP_ROOT.'/prices')
|
51 |
+
->isAvailable($model->getGrandTotal(), $model->getQuoteCurrencyCode(), $helper->getCountryCode());
|
52 |
+
}
|
53 |
+
|
54 |
+
/**
|
55 |
+
* Called by Mage_Sales_Model_Order_Payment::place
|
56 |
+
* is used instead of authorize and capture functions when $_isInitializeNeeded is true
|
57 |
+
*
|
58 |
+
* @param string $action
|
59 |
+
* @param Varien_Object $state
|
60 |
+
*/
|
61 |
+
public function initialize($action, $state){
|
62 |
+
if ($action == Boku_Paymentgateway_Model_System_Config::PAYMENT_ACTION_AUTH)
|
63 |
+
Mage::getSingleton(self::APP_ROOT.'/payment_transaction')->initiate();
|
64 |
+
return $this;
|
65 |
+
}
|
66 |
+
|
67 |
+
/**
|
68 |
+
* Return Order placed redirect url
|
69 |
+
* Called by Mage_Checkout_Model_Type_Onepage::saveOrder
|
70 |
+
*
|
71 |
+
* @return string
|
72 |
+
*/
|
73 |
+
public function getOrderPlaceRedirectUrl(){
|
74 |
+
return Mage::helper(self::APP_ROOT)->getUrl(self::APP_ROOT.'/standard/prepare');
|
75 |
+
}
|
76 |
+
}
|
app/code/community/Boku/Paymentgateway/Model/Payment/Transaction.php
ADDED
@@ -0,0 +1,364 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* Overall Boku transaction record.
|
4 |
+
* Initially populated by Boku_Paymentgateway_Model_Payment_Standard when an order is submitted
|
5 |
+
* Updated again by Boku_Paymentgateway_ApiController when the transaction is complete
|
6 |
+
*
|
7 |
+
* @category Payment gateway
|
8 |
+
* @package boku_paymentgateway
|
9 |
+
* @copyright Copyright (c) Boku (http://www.boku.com/)
|
10 |
+
* @author MDH <mdh@treatid.me.uk>
|
11 |
+
*/
|
12 |
+
|
13 |
+
Class Boku_Paymentgateway_Model_Payment_Transaction extends Boku_Paymentgateway_Model_Mapped_Abstract{
|
14 |
+
|
15 |
+
private $_order = null;
|
16 |
+
|
17 |
+
/**
|
18 |
+
* Initialize resource model
|
19 |
+
*/
|
20 |
+
protected function _construct(){
|
21 |
+
$this->_init(self::APP_ROOT.'/payment_transaction');
|
22 |
+
return parent::_construct();
|
23 |
+
}
|
24 |
+
|
25 |
+
/**
|
26 |
+
* @return null|Mage_Sales_Model_Order
|
27 |
+
*/
|
28 |
+
public function getOrder(){
|
29 |
+
if (is_null($this->_order)){
|
30 |
+
$id = $this->getOrderId();
|
31 |
+
if (empty($id)){
|
32 |
+
$model = Mage::getModel('sales/order')->load($this->getQuoteId(), 'quote_id');
|
33 |
+
if ($model->getId()){
|
34 |
+
$model->addStatusHistoryComment('Boku TRX-ID: '.$this->getTrxId());
|
35 |
+
$this->setOrderId($model->getId())->save();
|
36 |
+
$this->_order = $model;
|
37 |
+
}
|
38 |
+
}else{
|
39 |
+
$this->_order = Mage::getModel('sales/order')->load($id);
|
40 |
+
if (!$this->_order->getId()) $this->_order = null;
|
41 |
+
}
|
42 |
+
}
|
43 |
+
return $this->_order;
|
44 |
+
}
|
45 |
+
/**
|
46 |
+
* @return null|Mage_Sales_Model_Quote
|
47 |
+
*/
|
48 |
+
public function getQuote(){
|
49 |
+
$model = Mage::getModel('sales/quote')->load($this->getQuoteId());
|
50 |
+
return $model->getId() ? $model : null;
|
51 |
+
}
|
52 |
+
|
53 |
+
/**
|
54 |
+
* @param array $data - {amount, currency, total}
|
55 |
+
* @return Mage_Sales_Model_Order_Payment|null
|
56 |
+
*/
|
57 |
+
public function addPayment(&$data){
|
58 |
+
return $this->_addPayment($data);
|
59 |
+
}
|
60 |
+
/**
|
61 |
+
* @param array $data - {amount, currency}
|
62 |
+
* @return Mage_Sales_Model_Order_Payment|null
|
63 |
+
*/
|
64 |
+
public function addRefund(&$data){
|
65 |
+
return $this->_addPayment($data, true);
|
66 |
+
}
|
67 |
+
/**
|
68 |
+
* Creates order payment/transaction records and updates order paid/refunded values
|
69 |
+
* Fails if the currency differs from the order currency
|
70 |
+
*
|
71 |
+
* @param array $data - {amount, currency[, total]}
|
72 |
+
* @param boolean $refund
|
73 |
+
* @return Mage_Sales_Model_Order_Payment|null
|
74 |
+
*/
|
75 |
+
protected function _addPayment(&$data, $refund = false){
|
76 |
+
$helper = Mage::helper(self::APP_ROOT);
|
77 |
+
$trx_id = $this->getId();
|
78 |
+
$order = $this->getOrder();
|
79 |
+
try{
|
80 |
+
if (empty($order))
|
81 |
+
throw new Exception('Order not found for trx_id:'.$trx_id);
|
82 |
+
if (($currency = $data['currency']) != $order->getOrderCurrencyCode())
|
83 |
+
throw new Exception('Currency invalid: '.$currency.' != '.$order->getOrderCurrencyCode());
|
84 |
+
$order_to_base_rate = 1/$order->getBaseToOrderRate();
|
85 |
+
$amount = $data['amount'];
|
86 |
+
$payment = Mage::getModel('sales/order_payment')->setData(array(
|
87 |
+
'method'=>self::APP_ROOT,
|
88 |
+
'amount_ordered'=>$order->getGrandTotal(),
|
89 |
+
'base_amount_ordered'=>$order->getBaseGrandTotal(),
|
90 |
+
));
|
91 |
+
if ($refund)
|
92 |
+
$payment->addData(array(
|
93 |
+
'amount_refunded'=>$amount,
|
94 |
+
'base_amount_refunded'=>$amount * $order_to_base_rate,
|
95 |
+
));
|
96 |
+
else
|
97 |
+
$payment->addData(array(
|
98 |
+
'amount_paid'=>$amount,
|
99 |
+
'base_amount_paid'=>$amount * $order_to_base_rate,
|
100 |
+
));
|
101 |
+
|
102 |
+
$order->addPayment($payment);
|
103 |
+
$payment->save();
|
104 |
+
$transaction = Mage::getModel('sales/order_payment_transaction');
|
105 |
+
$transaction
|
106 |
+
->setOrderPaymentObject($payment)
|
107 |
+
->setTxnId($trx_id)
|
108 |
+
->setTxnType($refund ? $transaction::TYPE_REFUND : $transaction::TYPE_PAYMENT)
|
109 |
+
->setAdditionalInformation('source', 'Boku '.($refund ? 'refund' : 'payment').' confirmed')
|
110 |
+
->save()
|
111 |
+
->close();
|
112 |
+
if ($refund){
|
113 |
+
$order_refund_total = $order->getTotalRefunded() + $amount;
|
114 |
+
$order
|
115 |
+
->setTotalRefunded($order_refund_total)
|
116 |
+
->setBaseTotalRefunded($order_refund_total * $order_to_base_rate)
|
117 |
+
->save();
|
118 |
+
}else{
|
119 |
+
$total = $data['total'];
|
120 |
+
if ($order->getTotalPaid() < $total)
|
121 |
+
$order
|
122 |
+
->setTotalPaid($total)
|
123 |
+
->setBaseTotalPaid($total * $order_to_base_rate)
|
124 |
+
->save();
|
125 |
+
}
|
126 |
+
if ($amount > 0)
|
127 |
+
$order->addStatusHistoryComment(($refund ? 'Refund' : 'Payment').' received: '.$currency.' '.$amount, false)
|
128 |
+
->setIsVisibleOnFront(false)
|
129 |
+
->setIsCustomerNotified(false)
|
130 |
+
->save();
|
131 |
+
}catch(Exception $e){
|
132 |
+
$helper->logErr(__METHOD__.' - '.$e->getMessage());
|
133 |
+
if (isset($transaction)) $transaction->delete();
|
134 |
+
if (isset($payment)) $payment->delete();
|
135 |
+
return null;
|
136 |
+
}
|
137 |
+
return $order->getPayment();
|
138 |
+
}
|
139 |
+
|
140 |
+
/**
|
141 |
+
* Changes the order status and cancels if appropriate
|
142 |
+
* If an api billingresult occurs before all api events have been received then
|
143 |
+
* we may create a dummy payment of 0 to update the order payment values.
|
144 |
+
* If the total order value has been paid we will optionally generate an invoice.
|
145 |
+
*
|
146 |
+
* @return boolean
|
147 |
+
*/
|
148 |
+
public function complete($data = null){
|
149 |
+
if ($this->getHandled()) return true;
|
150 |
+
|
151 |
+
if (!empty($data)){
|
152 |
+
$this->_map($data);
|
153 |
+
if (array_key_exists('reference_currency', $data)){
|
154 |
+
$rc = $this->getReferenceCurrency();
|
155 |
+
if (!empty($rc) && $data['reference_currency'] != $rc)
|
156 |
+
unset($data['reference_currency']);
|
157 |
+
elseif (!isset($data['exchange']) && isset($data['paid']) && isset($data['reference_paid']))
|
158 |
+
try{$data['exchange'] = ((float) $data['paid']) / $data['reference_paid'];}catch(Exception $e){}
|
159 |
+
}
|
160 |
+
if (array_key_exists('timestamp', $data)){
|
161 |
+
$data['result_timestamp'] = $data['timestamp'];
|
162 |
+
unset($data['timestamp']);
|
163 |
+
}
|
164 |
+
if (array_key_exists('country', $data))
|
165 |
+
$data['country'] = strtoupper($data['country']);
|
166 |
+
$this->addData($data)->save();
|
167 |
+
}
|
168 |
+
|
169 |
+
$result_code = $this->getResultCode();
|
170 |
+
if (is_null($result_code)) return false;
|
171 |
+
if (is_null($order = $this->getOrder())) return false;
|
172 |
+
|
173 |
+
$helper = Mage::helper(self::APP_ROOT);
|
174 |
+
|
175 |
+
//Add dummy payment if necessary
|
176 |
+
$currency = $this->getCurrency();
|
177 |
+
$paid = $helper->getFloatPrice($this->getPaid(), $currency);
|
178 |
+
if ($paid > $order->getTotalPaid()){
|
179 |
+
$payment_data = array(
|
180 |
+
'amount'=>0,
|
181 |
+
'currency'=>$currency,
|
182 |
+
'total'=>$paid,
|
183 |
+
);
|
184 |
+
$payment = $this->addPayment($payment_data);
|
185 |
+
}
|
186 |
+
try{
|
187 |
+
switch ($result_code){
|
188 |
+
case 0:
|
189 |
+
switch ($order->getState()){
|
190 |
+
case $order::STATE_NEW:
|
191 |
+
case $order::STATE_PENDING_PAYMENT:
|
192 |
+
$order->setState($order::STATE_PROCESSING)->save();
|
193 |
+
}
|
194 |
+
$order->addStatusHistoryComment('Boku Transaction Completed Successfully');
|
195 |
+
|
196 |
+
if ($helper->getConfig('auto_invoice')
|
197 |
+
&& ($order->getTotalPaid() - $order->getTotalRefunded()) == $order->getGrandTotal()
|
198 |
+
&& $order->canInvoice())
|
199 |
+
$helper->generateInvoice($order);
|
200 |
+
break;
|
201 |
+
default:
|
202 |
+
$order->addStatusHistoryComment($this->getResultMsg());
|
203 |
+
if ($order->canCancel() && $order->getTotalPaid() == 0){
|
204 |
+
$order->cancel()->save();
|
205 |
+
$this->setCancelled(true)->save();
|
206 |
+
}else{
|
207 |
+
switch ($order->getState()){
|
208 |
+
case $order::STATE_NEW:
|
209 |
+
case $order::STATE_PENDING_PAYMENT:
|
210 |
+
$order->setState($order::STATE_PROCESSING)->save();
|
211 |
+
}
|
212 |
+
}
|
213 |
+
break;
|
214 |
+
}
|
215 |
+
$this->setHandled(true)->save();
|
216 |
+
}catch(Exception $e){$helper->logErr(__METHOD__.' - '.$e->getMessage()); return false;}
|
217 |
+
return true;
|
218 |
+
}
|
219 |
+
|
220 |
+
/**
|
221 |
+
* runs complete on any incomplete transactions
|
222 |
+
*
|
223 |
+
* @param string $trx_id - if null then looks at all transactions
|
224 |
+
*/
|
225 |
+
public function completeOutstanding($trx_id = null){
|
226 |
+
$helper = Mage::helper(self::APP_ROOT);
|
227 |
+
$c = $this->getCollection()
|
228 |
+
->addFieldToFilter('handled', 0)
|
229 |
+
->addFieldToFilter('result_code', array('notnull' => true))
|
230 |
+
->addFieldToFilter('order_id', array('notnull' => true));
|
231 |
+
if (!is_null($trx_id))
|
232 |
+
$c->addFieldToFilter('trx_id', $trx_id);
|
233 |
+
$failed = 0;
|
234 |
+
foreach($c->load() as $model){
|
235 |
+
$helper->setStore($model->getStoreId());
|
236 |
+
if (!$model->complete()) $failed++;
|
237 |
+
}
|
238 |
+
if ($failed) $helper->log(__METHOD__.': '.$failed.' failed.');
|
239 |
+
}
|
240 |
+
|
241 |
+
/**
|
242 |
+
* Initiates the payment process.
|
243 |
+
* If successful we create a new boku transaction record.
|
244 |
+
*
|
245 |
+
* @param Mage_Sales_Model_Quote $quote
|
246 |
+
*/
|
247 |
+
public static function initiate(Mage_Sales_Model_Quote $quote = null){
|
248 |
+
$helper = Mage::helper(self::APP_ROOT);
|
249 |
+
if (empty($quote)) $quote = $helper->getQuote();
|
250 |
+
try{
|
251 |
+
$response = self::_initiate($quote);
|
252 |
+
if (empty($response) || $response['result-code'] != 0)
|
253 |
+
throw new Exception('Invalid Response');
|
254 |
+
|
255 |
+
$trx_id = $response['trx-id'];
|
256 |
+
if (empty($trx_id) || empty($response['buy-url']))
|
257 |
+
throw new Exception($response['result-msg']);
|
258 |
+
|
259 |
+
if (!is_null(self::getTransaction($response['trx-id'])))
|
260 |
+
throw new Exception('Unexpected duplicate trx-id:'.$trx_id);
|
261 |
+
|
262 |
+
$quote_id = $quote->getId();
|
263 |
+
$currency = $quote->getQuoteCurrencyCode();
|
264 |
+
$data = array(
|
265 |
+
'trx-id'=>$trx_id,
|
266 |
+
'test'=>$helper->getConfig('mode'),
|
267 |
+
'store_id'=>$helper->getStore()->getId(),
|
268 |
+
'quote_id'=>$quote_id,
|
269 |
+
'country'=>$helper->getCountryCode(),
|
270 |
+
'currency'=>$currency,
|
271 |
+
'amount'=>$helper->getIntegerPrice($quote->getGrandTotal(), $currency),
|
272 |
+
'reference_currency'=>$quote->getBaseCurrencyCode(),
|
273 |
+
'timestamp'=>time(),
|
274 |
+
);
|
275 |
+
$transaction = self::getTransaction($data, true);
|
276 |
+
if (is_null($transaction))
|
277 |
+
throw new Exception('Create transaction trx-id:'.$trx_id.' failed');
|
278 |
+
|
279 |
+
$helper->getSession()->addData(array(
|
280 |
+
'trx-id'=>$trx_id,
|
281 |
+
'quote_id'=>$quote_id,
|
282 |
+
'buy-url'=>$response['buy-url'],
|
283 |
+
));
|
284 |
+
}catch(Exception $e){
|
285 |
+
$helper->logErr(__METHOD__.': '.$e->getMessage().(!empty($response) ? "\n".json_encode($response, JSON_PRETTY_PRINT) : ''));
|
286 |
+
Mage::throwException($helper->__('Failed to initiate the Boku payment transaction.'));
|
287 |
+
}
|
288 |
+
}
|
289 |
+
|
290 |
+
/**
|
291 |
+
* Initiates a payment by calling the "prepare" Boku API
|
292 |
+
*
|
293 |
+
* @param Mage_Sales_Model_Quote $quote
|
294 |
+
* @return null|array
|
295 |
+
*/
|
296 |
+
protected static function _initiate(Mage_Sales_Model_Quote $quote){
|
297 |
+
$helper = Mage::helper(self::APP_ROOT);
|
298 |
+
$num = $quote->getItemsCount();
|
299 |
+
$currency = $quote->getQuoteCurrencyCode();
|
300 |
+
if (!($order_id = $quote->getReservedOrderId()))
|
301 |
+
$order_id = reserveOrderId()->getReservedOrderId();
|
302 |
+
|
303 |
+
$params = array(
|
304 |
+
'merchant-id'=>$helper->getConfig('merchant_id'),
|
305 |
+
'service-id'=>$helper->getConfig('service_id'),
|
306 |
+
'country'=>$helper->getCountryCode(),
|
307 |
+
'consumer-id'=>$quote->getId(),
|
308 |
+
'desc'=>$num.' '.$helper->__('item'.($num > 0 ? 's' : '')),
|
309 |
+
'currency'=>$currency,
|
310 |
+
'price-inc-salestax'=>$helper->getIntegerPrice($quote->getGrandTotal(), $currency),
|
311 |
+
'callback-url'=>$helper->getCallbackUrl(),
|
312 |
+
'fwdurl'=>$helper->getSuccessUrl(),
|
313 |
+
'fail-fwdurl'=>$helper->getFailUrl(),
|
314 |
+
'param'=>$order_id,
|
315 |
+
);
|
316 |
+
$phone = $helper->getPhone();
|
317 |
+
if (!empty($phone)) $params['msisdn'] = str_replace(' ', '', $phone);
|
318 |
+
$smn = $helper->getConfig('sub_merchant_name');
|
319 |
+
if (!empty($smn)) $params['sub-merchant-name'] = $smn;
|
320 |
+
if ($helper->getConfig('mode')) $params['test'] = 1;
|
321 |
+
|
322 |
+
$url = $helper->getConfig('url/prepare');
|
323 |
+
$client = new Zend_Http_Client($helper->buildUrl($url, $params));
|
324 |
+
try {
|
325 |
+
$response = $client->request();
|
326 |
+
if ($response->isSuccessful()){
|
327 |
+
if (!Boku_Paymentgateway_Model_Xml::isValidXml($response->getBody()))
|
328 |
+
throw new Exception('Bad XML fetched from '.$url);
|
329 |
+
$xml = new Boku_Paymentgateway_Model_Xml($response->getBody());
|
330 |
+
return $xml->asArray();
|
331 |
+
}else
|
332 |
+
throw new Exception('Http Failed: '.$response->getMessage());
|
333 |
+
}catch(Exception $e){$helper->logErr(__METHOD__.': '.$e->getMessage());}
|
334 |
+
return null;
|
335 |
+
}
|
336 |
+
|
337 |
+
/**
|
338 |
+
* Gets the $data['trx-id'] transaction record
|
339 |
+
*
|
340 |
+
* @param array|string $data
|
341 |
+
* @param boolean $create_if_none (default:false)
|
342 |
+
* @return Boku_Paymentgateway_Model_Payment_Transaction|null
|
343 |
+
*/
|
344 |
+
public static function getTransaction(&$data, $create_if_none = false){
|
345 |
+
if (is_array($data)){
|
346 |
+
if (!array_key_exists('trx-id', $data)) return null;
|
347 |
+
$id = $data['trx-id'];
|
348 |
+
}else
|
349 |
+
$id = $data;
|
350 |
+
$model = new self();
|
351 |
+
$id = $model->load($id)->getId();
|
352 |
+
if (empty($id)){
|
353 |
+
if ($create_if_none && is_array($data)){
|
354 |
+
try{
|
355 |
+
$model->setData($data)->save();
|
356 |
+
}catch(Exception $e){
|
357 |
+
$model = null;
|
358 |
+
}
|
359 |
+
}else
|
360 |
+
$model = null;
|
361 |
+
}
|
362 |
+
return $model;
|
363 |
+
}
|
364 |
+
}
|
app/code/community/Boku/Paymentgateway/Model/Prices.php
ADDED
@@ -0,0 +1,386 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* Boku standard checkout module
|
4 |
+
*
|
5 |
+
* @category Payment gateway
|
6 |
+
* @package boku_paymentgateway
|
7 |
+
* @copyright Copyright (c) Boku (http://www.boku.com/)
|
8 |
+
* @author MDH <mdh@treatid.me.uk>
|
9 |
+
*/
|
10 |
+
|
11 |
+
class Boku_Paymentgateway_Model_Prices
|
12 |
+
{
|
13 |
+
const APP_ROOT = 'boku';
|
14 |
+
|
15 |
+
protected $price_list_timeout = 300;
|
16 |
+
|
17 |
+
/**
|
18 |
+
* @param ISO-4217 $currency
|
19 |
+
* @return int
|
20 |
+
*/
|
21 |
+
public function getCurrencyPrecision($currency){
|
22 |
+
$prices = $this->getPrices($currency);
|
23 |
+
if (is_array($prices)){
|
24 |
+
$prices = $this->getCache();
|
25 |
+
$country = Mage::helper(self::APP_ROOT)->getCountryCode();
|
26 |
+
try {
|
27 |
+
return $prices['country'][$country][$currency]['currency']['currency-decimal-places'];
|
28 |
+
} catch (Exception $e){}
|
29 |
+
}
|
30 |
+
$formatted_price = Mage::app()->getLocale()->currency($currency)->toCurrency(0, array('display'=>Zend_Currency::NO_SYMBOL));
|
31 |
+
$pieces = preg_split('/[^0-9]/' , $formatted_price);
|
32 |
+
return strlen($pieces[count($pieces) - 1]);
|
33 |
+
}
|
34 |
+
/**
|
35 |
+
* @param float $value
|
36 |
+
* @param ISO-4217 $currency
|
37 |
+
* @return int
|
38 |
+
*/
|
39 |
+
public function getIntegerPrice($value, $currency){
|
40 |
+
return (int) ($value * pow(10, $this->getCurrencyPrecision($currency)));
|
41 |
+
}
|
42 |
+
/**
|
43 |
+
* Convert a value expressed in the fractional currency unit to the normal float value
|
44 |
+
*
|
45 |
+
* @param int $price
|
46 |
+
* @param string (ISO 4217) $currency
|
47 |
+
* @return float
|
48 |
+
*/
|
49 |
+
public function getFloatPrice($price, $currency){
|
50 |
+
return $price / pow(10, $this->getCurrencyPrecision($currency));
|
51 |
+
}
|
52 |
+
|
53 |
+
/**
|
54 |
+
* Is the required price-point possible
|
55 |
+
* returns false or an array of networks for which it is available
|
56 |
+
*
|
57 |
+
* @param int $value (default: basket total)
|
58 |
+
* @param ISO-4217 $currency (default: store currency)
|
59 |
+
* @param ISO-3166-1-alpha-2 $country (default: see getPrices)
|
60 |
+
* @return boolean|array
|
61 |
+
*/
|
62 |
+
public function isAvailable($value = null, $currency = null, $country = null){
|
63 |
+
$helper = Mage::helper(self::APP_ROOT);
|
64 |
+
|
65 |
+
if (empty($currency)) $currency = $helper->getCurrencyCode();
|
66 |
+
if (empty($currency)) return false;
|
67 |
+
if (empty($country)) $country = $helper->getCountryCode();
|
68 |
+
if (empty($value)) $value = $helper->getQuote()->getGrandTotal();
|
69 |
+
$int_price = $this->getIntegerPrice($value, $currency);
|
70 |
+
|
71 |
+
$prices = $this->getPrices($currency, $country);
|
72 |
+
$available = false;
|
73 |
+
$pp_found = false;
|
74 |
+
if (is_array($prices)){
|
75 |
+
foreach($prices as $k=>&$v){
|
76 |
+
if (array_key_exists('increment', $v)){
|
77 |
+
if ($int_price >= $v['min-price'] && $int_price <= $v['max-price']
|
78 |
+
&& ($v['increment'] == 0 || !(($int_price - $v['min-price']) % $v['increment']))){
|
79 |
+
$available = (bool) $v['status'];
|
80 |
+
$pp_found = true;
|
81 |
+
break;
|
82 |
+
}
|
83 |
+
}elseif (array_key_exists('amount', $v)){
|
84 |
+
if ($int_price == $v['amount']){
|
85 |
+
$available = !$v['status'] ? false : (isset($v['network']) ? $v['network'] : true);
|
86 |
+
$pp_found = true;
|
87 |
+
break;
|
88 |
+
}
|
89 |
+
}
|
90 |
+
}
|
91 |
+
}
|
92 |
+
if (!$available && !$pp_found)
|
93 |
+
$available = $this->getAvailableNetworks($currency, $country, $int_price);
|
94 |
+
if (is_array($available))
|
95 |
+
$helper->getSession()->setNetworks($available);
|
96 |
+
else
|
97 |
+
$helper->getSession()->unsNetworks();
|
98 |
+
|
99 |
+
if (!$available)
|
100 |
+
$helper->log(__METHOD__."($value,$currency,$country) is".($available ? '' : ' NOT').' available for your Boku service '.$helper->getConfig('service_id'), ($available ? Zend_Log::INFO : Zend_Log::WARN));
|
101 |
+
return $available;
|
102 |
+
}
|
103 |
+
|
104 |
+
/**
|
105 |
+
* Gets array of price-point data for particular country/currency
|
106 |
+
*
|
107 |
+
* @param ISO-4217 $currency (default: store currency)
|
108 |
+
* @param ISO-3166-1-alpha-2 $country (default: store country)
|
109 |
+
* @return array|null
|
110 |
+
*/
|
111 |
+
public function getPrices($currency = null, $country = null, $fetch = false){
|
112 |
+
$helper = Mage::helper(self::APP_ROOT);
|
113 |
+
|
114 |
+
if (empty($currency)) $currency = $helper->getCurrencyCode();
|
115 |
+
if (empty($country)) $country = $helper->getCountryCode();
|
116 |
+
|
117 |
+
if (!$fetch){
|
118 |
+
$prices = $this->getCache();
|
119 |
+
try {
|
120 |
+
$prices = $prices['country'][$country][$currency]['price-points'];
|
121 |
+
$fetch = !is_array($prices);
|
122 |
+
} catch (Exception $e){$fetch = true;}
|
123 |
+
}
|
124 |
+
|
125 |
+
if ($fetch){
|
126 |
+
$prices = $this->fetchPrices($currency, $country);
|
127 |
+
$this->addToCache($prices);
|
128 |
+
try {
|
129 |
+
if (!empty($country)){
|
130 |
+
$prices = $prices['country'][$country][$currency]['price-points'];
|
131 |
+
if (!is_array($prices)) $prices = null;
|
132 |
+
}else{
|
133 |
+
$p = null;
|
134 |
+
foreach($prices['country'] as $c)
|
135 |
+
if (array_key_exists($currency, $c) && is_array($c[$currency])){
|
136 |
+
$p = $c[$currency]['price-points']; break;
|
137 |
+
}
|
138 |
+
$prices = $p;
|
139 |
+
}
|
140 |
+
} catch (Exception $e){$prices = null;}
|
141 |
+
}
|
142 |
+
if (is_null($prices))
|
143 |
+
$helper->log(__METHOD__."($currency,$country): No price data found", Zend_Log::WARN);
|
144 |
+
return $prices;
|
145 |
+
}
|
146 |
+
|
147 |
+
/**
|
148 |
+
* Fetches a list of available phone networks for given country, currency and price.
|
149 |
+
* Also adds the price info to the cached price list.
|
150 |
+
* If the price is not available then it is also added to the cache as unavailable.
|
151 |
+
*
|
152 |
+
* @param ISO-4217 $currency
|
153 |
+
* @param ISO-3166-1-alpha-2 $country
|
154 |
+
* @param int $price
|
155 |
+
* @return array|null
|
156 |
+
*/
|
157 |
+
private function getAvailableNetworks($currency, $country, $price){
|
158 |
+
$helper = Mage::helper(self::APP_ROOT);
|
159 |
+
$data = $this->fetchPrices($currency, $country, $price);
|
160 |
+
$networks = false;
|
161 |
+
try{
|
162 |
+
if (!empty($data)){
|
163 |
+
$p = &$data['country'][$country][$currency]['price-points'][0];
|
164 |
+
$networks = $p['network'];
|
165 |
+
}else
|
166 |
+
$p = array(
|
167 |
+
'status'=>0,
|
168 |
+
'min-price'=>$price,
|
169 |
+
'max-price'=>$price,
|
170 |
+
'increment'=>0,
|
171 |
+
);
|
172 |
+
$pl = array();
|
173 |
+
$pl['country'][$country][$currency]['price-points'][] = $p;
|
174 |
+
$this->addToCache($pl);
|
175 |
+
}catch(Exception $e){}
|
176 |
+
return $networks;
|
177 |
+
}
|
178 |
+
|
179 |
+
/**
|
180 |
+
* Recursive merge of 2 arrays. a1 is modified and returned
|
181 |
+
* if a2 key is an integer then append to a1
|
182 |
+
* elseif a2 and a1 values are both arrays then merge
|
183 |
+
* else replace
|
184 |
+
*
|
185 |
+
* @param array &$a1
|
186 |
+
* @param array &$a2
|
187 |
+
* @return array
|
188 |
+
*/
|
189 |
+
private function &arrayMerge(&$a1, &$a2){
|
190 |
+
foreach ($a2 as $k=>&$v)
|
191 |
+
if (is_integer($k))
|
192 |
+
$a1[] = $a2[$k];
|
193 |
+
elseif (is_array($v) && isset($a1[$k]) && is_array($a1[$k]))
|
194 |
+
$this->arrayMerge($a1[$k], $v);
|
195 |
+
else $a1[$k] = $v;
|
196 |
+
return $a1;
|
197 |
+
}
|
198 |
+
|
199 |
+
/**
|
200 |
+
* fetches price data from the cache
|
201 |
+
* if the cache has timed out then clears the cache and returns null
|
202 |
+
*
|
203 |
+
* @return array|null
|
204 |
+
*/
|
205 |
+
private function getCache(){
|
206 |
+
$session = Mage::helper(self::APP_ROOT)->getSession();
|
207 |
+
$plt = $session->getPriceListTimestamp();
|
208 |
+
if (is_integer($plt)){
|
209 |
+
if ((time() - $plt) <= $this->price_list_timeout)
|
210 |
+
return $session->getPriceList();
|
211 |
+
$this->clearCache();
|
212 |
+
}
|
213 |
+
return null;
|
214 |
+
}
|
215 |
+
/**
|
216 |
+
* adds price data to the cache
|
217 |
+
* if the cache was empty then sets the timestamp
|
218 |
+
*
|
219 |
+
* @param array
|
220 |
+
*/
|
221 |
+
private function addToCache(&$d){
|
222 |
+
if (!is_array($d)) return;
|
223 |
+
$session = Mage::helper(self::APP_ROOT)->getSession();
|
224 |
+
$pl = $session->getPriceList();
|
225 |
+
if (!is_integer($session->getPriceListTimestamp()) || !is_array($pl))
|
226 |
+
$session->setPriceListTimestamp(time());
|
227 |
+
$session->setPriceList(is_array($pl) ? $this->arrayMerge($pl, $d) : $d);
|
228 |
+
}
|
229 |
+
private function clearCache(){
|
230 |
+
$session = Mage::helper(self::APP_ROOT)->getSession();
|
231 |
+
$session->unsPriceList();
|
232 |
+
$session->unsPriceListTimestamp();
|
233 |
+
}
|
234 |
+
|
235 |
+
/**
|
236 |
+
* Fetches price data from Boku
|
237 |
+
* If $price is not provided then it will fetch price-list otherwise print-info.
|
238 |
+
*
|
239 |
+
* @param ISO-4217 $currency
|
240 |
+
* @param ISO-3166-1-alpha-2 $country
|
241 |
+
* @param int $price (default: null)
|
242 |
+
* @return array|null
|
243 |
+
*/
|
244 |
+
public function fetchPrices($currency, $country, $price = null){
|
245 |
+
$helper = Mage::helper(self::APP_ROOT);
|
246 |
+
$price_url = $helper->getConfig(is_null($price) ? 'url/pricelist' : 'url/priceinfo');
|
247 |
+
$service_id = $helper->getConfig('service_id');
|
248 |
+
$params = array(
|
249 |
+
'merchant-id'=>$helper->getConfig('merchant_id'),
|
250 |
+
'service-id'=>$service_id,
|
251 |
+
'country'=>$country,
|
252 |
+
'currency'=>$currency,
|
253 |
+
'reference-currency'=>$helper->getBaseCurrencyCode(),
|
254 |
+
// 'show-all-networks'=>'true',
|
255 |
+
);
|
256 |
+
if (!is_null($price))
|
257 |
+
$params = array_merge($params, array(
|
258 |
+
'price'=>$price,
|
259 |
+
'show-all-networks'=>'true',
|
260 |
+
));
|
261 |
+
|
262 |
+
$client = new Zend_Http_Client($helper->buildUrl($price_url, $params));
|
263 |
+
try{
|
264 |
+
$response = $client->request();
|
265 |
+
if ($response->isSuccessful()){
|
266 |
+
if (!Boku_Paymentgateway_Model_Xml::isValidXml($response->getBody()))
|
267 |
+
throw new Exception('Bad XML fetched from '.$price_url);
|
268 |
+
$prices = new Boku_Paymentgateway_Model_Xml($response->getBody());
|
269 |
+
$prices = $prices->asArray();
|
270 |
+
if ($prices['response-code'] != 0){
|
271 |
+
$msg = $prices['response-message'];
|
272 |
+
switch($prices['response-code']){
|
273 |
+
case 33: $msg .= ' ('.$currency.')'; break;
|
274 |
+
case 34: $msg .= ' ('.$service_id.')'; break;
|
275 |
+
case 36: $msg .= ' ('.$country.')'; break;
|
276 |
+
}
|
277 |
+
throw new Exception($msg);
|
278 |
+
}
|
279 |
+
self::collapsePriceArray($prices);
|
280 |
+
if (!array_key_exists('country', $prices))
|
281 |
+
throw new Exception('No price-point data retrieved');
|
282 |
+
self::sectionCurrencies($prices);
|
283 |
+
return $prices;
|
284 |
+
}else
|
285 |
+
throw new Exception('Http Failed: '.$response->getMessage());
|
286 |
+
}catch(Exception $e){$helper->logErr(__METHOD__."($currency,$country,$price): ".$e->getMessage());}
|
287 |
+
return null;
|
288 |
+
}
|
289 |
+
|
290 |
+
/**
|
291 |
+
* Shifts price data into currency sections and removes some repeated data.
|
292 |
+
*
|
293 |
+
* @param array &$data (by reference)
|
294 |
+
* @return array
|
295 |
+
*/
|
296 |
+
private static function §ionCurrencies(&$data){
|
297 |
+
unset($data['format']);
|
298 |
+
unset($data['reference-currency']);
|
299 |
+
foreach($data['country'] as &$country){
|
300 |
+
$first = true;
|
301 |
+
foreach(array_keys($country) as $k){
|
302 |
+
$pp = $country[$k];
|
303 |
+
unset($country[$k]);
|
304 |
+
$currency = $pp['currency'];
|
305 |
+
unset($pp['currency']);
|
306 |
+
if ($first)
|
307 |
+
$country[$currency]['currency'] = array(
|
308 |
+
'currency-decimal-places'=>$pp['currency-decimal-places'],
|
309 |
+
'reference-currency'=>$pp['reference-currency'],
|
310 |
+
'exchange'=>$pp['exchange'],
|
311 |
+
);
|
312 |
+
unset($pp['currency-decimal-places']);
|
313 |
+
unset($pp['reference-currency']);
|
314 |
+
unset($pp['exchange']);
|
315 |
+
$country[$currency]['price-points'][] = $pp;
|
316 |
+
$first = false;
|
317 |
+
}
|
318 |
+
}
|
319 |
+
return $data;
|
320 |
+
}
|
321 |
+
|
322 |
+
/**
|
323 |
+
* Simplifies and cleans up the output from Boku_Paymentgateway_Model_Xml::asArray()
|
324 |
+
* Intended to work with Boku price-list and price-info responses.
|
325 |
+
*
|
326 |
+
* @param array &$data (by reference)
|
327 |
+
* @return array
|
328 |
+
*/
|
329 |
+
private static function &collapsePriceArray(&$data){
|
330 |
+
//strip useless data
|
331 |
+
if (isset($data['@string'])) unset($data['@string']);
|
332 |
+
|
333 |
+
if (count($data) > 1 && isset($data['@code'])){
|
334 |
+
$na = array();
|
335 |
+
$code = '@'.$data['@code'];
|
336 |
+
unset($data['@code']);
|
337 |
+
foreach($data as $k=>&$v) $na[$k] = $v;
|
338 |
+
$data = array($code=>$na);
|
339 |
+
}
|
340 |
+
|
341 |
+
//do recursion
|
342 |
+
foreach($data as $k=>&$v)
|
343 |
+
if (is_array($v))
|
344 |
+
self::collapsePriceArray($v);
|
345 |
+
|
346 |
+
//
|
347 |
+
foreach($data as $k=>&$v){
|
348 |
+
if (!(is_array($v) && is_numeric($k))) continue;
|
349 |
+
$na = 0;
|
350 |
+
foreach($v as $vk=>&$vv)
|
351 |
+
if (substr((string) $vk, 0, 1) == '@'){
|
352 |
+
if (++$na > 1) break;
|
353 |
+
$ak = $vk;
|
354 |
+
$av = $vv;
|
355 |
+
}
|
356 |
+
if ($na == 1 && !is_array($av) && !array_key_exists($av, $data)){
|
357 |
+
unset($v[$ak]);
|
358 |
+
$data[$av] = $v;
|
359 |
+
unset($data[$k]);
|
360 |
+
}
|
361 |
+
}
|
362 |
+
|
363 |
+
//remove @ from start of attribute keys
|
364 |
+
foreach($data as $k=>&$v)
|
365 |
+
if (substr((string) $k, 0, 1) == '@'){
|
366 |
+
$data[substr((string) $k, 1)] = $v;
|
367 |
+
unset($data[$k]);
|
368 |
+
}
|
369 |
+
|
370 |
+
//collapse single element arrays into their parent
|
371 |
+
foreach($data as $k=>&$v)
|
372 |
+
if (is_array($v) && count($v) == 1){
|
373 |
+
foreach($v as $vk=>&$vv){
|
374 |
+
if (is_numeric($vk) || $vk == 'name'
|
375 |
+
|| (($vk == 'continuous-price' || $vk == 'discrete-price') && !array_key_exists('status', $vv)))
|
376 |
+
$v = $vv;
|
377 |
+
elseif (is_numeric($k) && !array_key_exists($vk, $data)){
|
378 |
+
$data[$vk] = $vv;
|
379 |
+
unset($data[$k]);
|
380 |
+
}
|
381 |
+
break;
|
382 |
+
}
|
383 |
+
}
|
384 |
+
return $data;
|
385 |
+
}
|
386 |
+
}
|
app/code/community/Boku/Paymentgateway/Model/Resource/Payment/Callback.php
ADDED
@@ -0,0 +1,20 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* Callback records
|
4 |
+
*
|
5 |
+
* @category Payment gateway
|
6 |
+
* @package boku_paymentgateway
|
7 |
+
* @copyright Copyright (c) Boku (http://www.boku.com/)
|
8 |
+
* @author MDH <mdh@treatid.me.uk>
|
9 |
+
*/
|
10 |
+
|
11 |
+
Class Boku_Paymentgateway_Model_Resource_Payment_Callback extends Mage_Core_Model_Resource_Db_Abstract{
|
12 |
+
|
13 |
+
/**
|
14 |
+
* Initialize main table and the primary key field name
|
15 |
+
*/
|
16 |
+
protected function _construct(){
|
17 |
+
$this->_init('boku/payment_callback', 'id');
|
18 |
+
}
|
19 |
+
|
20 |
+
}
|
app/code/community/Boku/Paymentgateway/Model/Resource/Payment/Callback/Collection.php
ADDED
@@ -0,0 +1,20 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* Callback collection
|
4 |
+
*
|
5 |
+
* @category Payment gateway
|
6 |
+
* @package boku_paymentgateway
|
7 |
+
* @copyright Copyright (c) Boku (http://www.boku.com/)
|
8 |
+
* @author MDH <mdh@treatid.me.uk>
|
9 |
+
*/
|
10 |
+
|
11 |
+
class Boku_Paymentgateway_Model_Resource_Payment_Callback_Collection extends Mage_Core_Model_Resource_Db_Collection_Abstract{
|
12 |
+
|
13 |
+
/**
|
14 |
+
* Initialize collection items factory class
|
15 |
+
*/
|
16 |
+
protected function _construct(){
|
17 |
+
$this->_init('boku/payment_callback');
|
18 |
+
parent::_construct();
|
19 |
+
}
|
20 |
+
}
|
app/code/community/Boku/Paymentgateway/Model/Resource/Payment/Chargeback.php
ADDED
@@ -0,0 +1,19 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* Chargeback records
|
4 |
+
*
|
5 |
+
* @category Payment gateway
|
6 |
+
* @package boku_paymentgateway
|
7 |
+
* @copyright Copyright (c) Boku (http://www.boku.com/)
|
8 |
+
* @author MDH <mdh@treatid.me.uk>
|
9 |
+
*/
|
10 |
+
|
11 |
+
Class Boku_Paymentgateway_Model_Resource_Payment_Chargeback extends Mage_Core_Model_Resource_Db_Abstract{
|
12 |
+
|
13 |
+
/**
|
14 |
+
* Initialize main table and the primary key field name
|
15 |
+
*/
|
16 |
+
protected function _construct(){
|
17 |
+
$this->_init('boku/payment_chargeback', 'id');
|
18 |
+
}
|
19 |
+
}
|
app/code/community/Boku/Paymentgateway/Model/Resource/Payment/Chargeback/Collection.php
ADDED
@@ -0,0 +1,20 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* Chargeback collection
|
4 |
+
*
|
5 |
+
* @category Payment gateway
|
6 |
+
* @package boku_paymentgateway
|
7 |
+
* @copyright Copyright (c) Boku (http://www.boku.com/)
|
8 |
+
* @author MDH <mdh@treatid.me.uk>
|
9 |
+
*/
|
10 |
+
|
11 |
+
class Boku_Paymentgateway_Model_Resource_Payment_Chargeback_Collection extends Mage_Core_Model_Resource_Db_Collection_Abstract{
|
12 |
+
|
13 |
+
/**
|
14 |
+
* Initialize collection items factory class
|
15 |
+
*/
|
16 |
+
protected function _construct(){
|
17 |
+
$this->_init('boku/payment_chargeback');
|
18 |
+
parent::_construct();
|
19 |
+
}
|
20 |
+
}
|
app/code/community/Boku/Paymentgateway/Model/Resource/Payment/Event.php
ADDED
@@ -0,0 +1,19 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* Event records
|
4 |
+
*
|
5 |
+
* @category Payment gateway
|
6 |
+
* @package boku_paymentgateway
|
7 |
+
* @copyright Copyright (c) Boku (http://www.boku.com/)
|
8 |
+
* @author MDH <mdh@treatid.me.uk>
|
9 |
+
*/
|
10 |
+
|
11 |
+
Class Boku_Paymentgateway_Model_Resource_Payment_Event extends Mage_Core_Model_Resource_Db_Abstract{
|
12 |
+
|
13 |
+
/**
|
14 |
+
* Initialize main table and the primary key field name
|
15 |
+
*/
|
16 |
+
protected function _construct(){
|
17 |
+
$this->_init('boku/payment_event', 'id');
|
18 |
+
}
|
19 |
+
}
|
app/code/community/Boku/Paymentgateway/Model/Resource/Payment/Event/Collection.php
ADDED
@@ -0,0 +1,20 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* Event collection
|
4 |
+
*
|
5 |
+
* @category Payment gateway
|
6 |
+
* @package boku_paymentgateway
|
7 |
+
* @copyright Copyright (c) Boku (http://www.boku.com/)
|
8 |
+
* @author MDH <mdh@treatid.me.uk>
|
9 |
+
*/
|
10 |
+
|
11 |
+
class Boku_Paymentgateway_Model_Resource_Payment_Event_Collection extends Mage_Core_Model_Resource_Db_Collection_Abstract{
|
12 |
+
|
13 |
+
/**
|
14 |
+
* Initialize collection items factory class
|
15 |
+
*/
|
16 |
+
protected function _construct(){
|
17 |
+
$this->_init('boku/payment_event');
|
18 |
+
parent::_construct();
|
19 |
+
}
|
20 |
+
}
|
app/code/community/Boku/Paymentgateway/Model/Resource/Payment/Transaction.php
ADDED
@@ -0,0 +1,22 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* Transaction records
|
4 |
+
* Root for recording all Boku transaction data
|
5 |
+
*
|
6 |
+
* @category Payment gateway
|
7 |
+
* @package boku_paymentgateway
|
8 |
+
* @copyright Copyright (c) Boku (http://www.boku.com/)
|
9 |
+
* @author MDH <mdh@treatid.me.uk>
|
10 |
+
*/
|
11 |
+
|
12 |
+
Class Boku_Paymentgateway_Model_Resource_Payment_Transaction extends Mage_Core_Model_Resource_Db_Abstract{
|
13 |
+
|
14 |
+
protected $_isPkAutoIncrement = false;
|
15 |
+
|
16 |
+
/**
|
17 |
+
* Initialize main table and the primary key field name
|
18 |
+
*/
|
19 |
+
protected function _construct(){
|
20 |
+
$this->_init('boku/payment_transaction', 'trx_id');
|
21 |
+
}
|
22 |
+
}
|
app/code/community/Boku/Paymentgateway/Model/Resource/Payment/Transaction/Collection.php
ADDED
@@ -0,0 +1,20 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* Transaction collection
|
4 |
+
*
|
5 |
+
* @category Payment gateway
|
6 |
+
* @package boku_paymentgateway
|
7 |
+
* @copyright Copyright (c) Boku (http://www.boku.com/)
|
8 |
+
* @author MDH <mdh@treatid.me.uk>
|
9 |
+
*/
|
10 |
+
|
11 |
+
class Boku_Paymentgateway_Model_Resource_Payment_Transaction_Collection extends Mage_Core_Model_Resource_Db_Collection_Abstract{
|
12 |
+
|
13 |
+
/**
|
14 |
+
* Initialize collection items factory class
|
15 |
+
*/
|
16 |
+
protected function _construct(){
|
17 |
+
$this->_init('boku/payment_transaction');
|
18 |
+
parent::_construct();
|
19 |
+
}
|
20 |
+
}
|
app/code/community/Boku/Paymentgateway/Model/Resource/Setup.php
ADDED
@@ -0,0 +1,12 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* Main Module configuration
|
4 |
+
*
|
5 |
+
* @category Payment gateway
|
6 |
+
* @package boku_paymentgateway
|
7 |
+
* @copyright Copyright (c) Boku (http://www.boku.com/)
|
8 |
+
* @author MDH <mdh@treatid.me.uk>
|
9 |
+
*/
|
10 |
+
class Boku_Paymentgateway_Model_Resource_Setup extends Mage_Core_Model_Resource_Setup
|
11 |
+
{
|
12 |
+
}
|
app/code/community/Boku/Paymentgateway/Model/Session.php
ADDED
@@ -0,0 +1,18 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* Boku transaction session data store
|
4 |
+
*
|
5 |
+
* @category Payment gateway
|
6 |
+
* @package boku_paymentgateway
|
7 |
+
* @copyright Copyright (c) Boku (http://www.boku.com/)
|
8 |
+
* @author MDH <mdh@treatid.me.uk>
|
9 |
+
*/
|
10 |
+
|
11 |
+
class Boku_Paymentgateway_Model_Session extends Mage_Core_Model_Session_Abstract
|
12 |
+
{
|
13 |
+
const APP_ROOT = 'boku';
|
14 |
+
|
15 |
+
public function __construct(){
|
16 |
+
$this->init(self::APP_ROOT);
|
17 |
+
}
|
18 |
+
}
|
app/code/community/Boku/Paymentgateway/Model/System/Config.php
ADDED
@@ -0,0 +1,71 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* System config options
|
4 |
+
*
|
5 |
+
* @category Payment gateway
|
6 |
+
* @package boku_paymentgateway
|
7 |
+
* @copyright Copyright (c) Boku (http://www.boku.com/)
|
8 |
+
* @author MDH <mdh@treatid.me.uk>
|
9 |
+
*/
|
10 |
+
class Boku_Paymentgateway_Model_System_Config
|
11 |
+
{
|
12 |
+
const APP_ROOT = 'boku';
|
13 |
+
|
14 |
+
const ABORT = 0;
|
15 |
+
const CHARGE_MIN = 1;
|
16 |
+
const CHARGE_MAX = 1;
|
17 |
+
const MULTIPLE = 2;
|
18 |
+
const ROUND_UP = 1;
|
19 |
+
const ROUND_DOWN = 2;
|
20 |
+
|
21 |
+
const NONE = 0;
|
22 |
+
const MIN = 1;
|
23 |
+
const AVG = 2;
|
24 |
+
const MAX = 3;
|
25 |
+
|
26 |
+
const LIVE = 0;
|
27 |
+
const TEST = 1;
|
28 |
+
|
29 |
+
const PAYMENT_ACTION_AUTH = 'Authorization';
|
30 |
+
|
31 |
+
public function getPaymentBelowMinOptions(){
|
32 |
+
$helper = Mage::helper(self::APP_ROOT);
|
33 |
+
return array(
|
34 |
+
self::ABORT =>$helper->__('Exclude Boku'),
|
35 |
+
self::CHARGE_MIN =>$helper->__('Charge Minimum'),
|
36 |
+
);
|
37 |
+
}
|
38 |
+
public function getPaymentAboveMaxOptions(){
|
39 |
+
$helper = Mage::helper(self::APP_ROOT);
|
40 |
+
return array(
|
41 |
+
self::ABORT =>$helper->__('Exclude Boku'),
|
42 |
+
self::CHARGE_MAX =>$helper->__('Charge Maximum'),
|
43 |
+
self::MULTIPLE =>$helper->__('Use Multiple Submissions'),
|
44 |
+
);
|
45 |
+
}
|
46 |
+
public function getPaymentUnavailableOptions(){
|
47 |
+
$helper = Mage::helper(self::APP_ROOT);
|
48 |
+
return array(
|
49 |
+
self::ABORT =>$helper->__('Exclude Boku'),
|
50 |
+
self::ROUND_UP =>$helper->__('Round-up (Exclude Boku if not possible)'),
|
51 |
+
self::ROUND_DOWN =>$helper->__('Round-down (Exclude Boku if not possible)'),
|
52 |
+
);
|
53 |
+
}
|
54 |
+
public function getCommissionOptions(){
|
55 |
+
$helper = Mage::helper(self::APP_ROOT);
|
56 |
+
return array(
|
57 |
+
self::NONE =>$helper->__('No'),
|
58 |
+
self::MIN =>$helper->__('Minimum'),
|
59 |
+
self::AVG =>$helper->__('Average'),
|
60 |
+
self::MAX =>$helper->__('Maximum'),
|
61 |
+
);
|
62 |
+
}
|
63 |
+
public function getModeOptions(){
|
64 |
+
$helper = Mage::helper(self::APP_ROOT);
|
65 |
+
return array(
|
66 |
+
self::TEST =>$helper->__('Test'),
|
67 |
+
self::LIVE =>$helper->__('Live'),
|
68 |
+
);
|
69 |
+
}
|
70 |
+
}
|
71 |
+
?>
|
app/code/community/Boku/Paymentgateway/Model/Test.php
ADDED
@@ -0,0 +1,72 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* Boku Tests
|
4 |
+
*
|
5 |
+
* @category Payment gateway
|
6 |
+
* @package boku_paymentgateway
|
7 |
+
* @copyright Copyright (c) Boku (http://www.boku.com/)
|
8 |
+
* @author MDH <mdh@treatid.me.uk>
|
9 |
+
*/
|
10 |
+
|
11 |
+
class Boku_Paymentgateway_Model_Test
|
12 |
+
{
|
13 |
+
const APP_ROOT = 'boku';
|
14 |
+
|
15 |
+
/**
|
16 |
+
* Attempts to fetch price-list data from Boku
|
17 |
+
* returns info/results for process
|
18 |
+
*
|
19 |
+
* @return array
|
20 |
+
*/
|
21 |
+
public function testConnection(){
|
22 |
+
$helper = Mage::helper(self::APP_ROOT);
|
23 |
+
|
24 |
+
$price_url = $helper->getConfig('url/pricelist');
|
25 |
+
$merchant_id = $helper->getConfig('merchant_id');
|
26 |
+
$service_id = $helper->getConfig('service_id');
|
27 |
+
$api_key = $helper->getConfig('api_security_key');
|
28 |
+
$out = array("Attempting to fetch price-point data from $price_url");
|
29 |
+
try{
|
30 |
+
if (empty($merchant_id) || empty($service_id) || empty($api_key)){
|
31 |
+
if (empty($merchant_id)) $out[] = 'Merchant Id not set';
|
32 |
+
if (empty($service_id)) $out[] = 'Service Id not set';
|
33 |
+
if (empty($api_key)) $out[] = 'API Security Key not set';
|
34 |
+
throw new Exception('Boku payment settings incomplete.');
|
35 |
+
}
|
36 |
+
|
37 |
+
$currency = $helper->getCurrencyCode();
|
38 |
+
$country = $helper->getCountryCode();
|
39 |
+
$params = array(
|
40 |
+
'merchant-id'=>$merchant_id,
|
41 |
+
'service-id'=>$service_id,
|
42 |
+
'currency'=>$currency,
|
43 |
+
'country'=>$country,
|
44 |
+
'reference-currency'=>$helper->getBaseCurrencyCode(),
|
45 |
+
);
|
46 |
+
$client = new Zend_Http_Client($helper->buildUrl($price_url, $params));
|
47 |
+
$response = $client->request();
|
48 |
+
if ($response->isSuccessful()){
|
49 |
+
if (!Boku_Paymentgateway_Model_Xml::isValidXml($response->getBody()))
|
50 |
+
throw new Exception('Bad XML fetched from '.$price_url);
|
51 |
+
$prices = new Boku_Paymentgateway_Model_Xml($response->getBody());
|
52 |
+
$prices = $prices->asArray();
|
53 |
+
if ($prices['response-code'] != 0){
|
54 |
+
$msg = $prices['response-message'];
|
55 |
+
switch($prices['response-code']){
|
56 |
+
case 28: $msg .= ' (This is probably caused by incorrect values for your Merchant Id, Service Id or API Security Key)'; break;
|
57 |
+
case 33: $msg .= ' ('.$currency.')'; break;
|
58 |
+
case 34: if (!empty($service_id)) $msg .= ' ('.$service_id.')'; break;
|
59 |
+
case 36: if (!empty($country)) $msg .= ' ('.$currency.')'; break;
|
60 |
+
}
|
61 |
+
throw new Exception($msg);
|
62 |
+
}
|
63 |
+
$out[] = "Connection Successful";
|
64 |
+
}else
|
65 |
+
throw new Exception('Http Failed: '.$response->getMessage());
|
66 |
+
}catch(Exception $e){
|
67 |
+
$out[] = $e->getMessage();
|
68 |
+
}
|
69 |
+
return $out;
|
70 |
+
}
|
71 |
+
|
72 |
+
}
|
app/code/community/Boku/Paymentgateway/Model/Xml.php
ADDED
@@ -0,0 +1,100 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* XML object
|
4 |
+
*
|
5 |
+
* @category Payment gateway
|
6 |
+
* @package boku_paymentgateway
|
7 |
+
* @copyright Copyright (c) Boku (http://www.boku.com/)
|
8 |
+
* @author MDH <mdh@treatid.me.uk>
|
9 |
+
*/
|
10 |
+
|
11 |
+
class Boku_Paymentgateway_Model_Xml extends SimpleXMLElement
|
12 |
+
{
|
13 |
+
/**
|
14 |
+
* Returns this element and it's children as a condensed array
|
15 |
+
*
|
16 |
+
* @param bool $is_canonical - whether to ignore attributes
|
17 |
+
* @return array|string
|
18 |
+
*/
|
19 |
+
public function asArray($is_canonical = false){
|
20 |
+
return self::condenseArray(self::_asArray($this, $is_canonical));
|
21 |
+
}
|
22 |
+
|
23 |
+
/**
|
24 |
+
* Returns the element and it's children as an array
|
25 |
+
* attributes names are prefixed by '@' - slight warning: these could be overwritten by children with the same names
|
26 |
+
*
|
27 |
+
* @param SimpleXMLElement
|
28 |
+
* @param bool $is_canonical - whether to ignore attributes
|
29 |
+
* @return array|string
|
30 |
+
*/
|
31 |
+
protected static function _asArray(SimpleXMLElement $element, $is_canonical = false){
|
32 |
+
$result = array();
|
33 |
+
if (!$is_canonical)
|
34 |
+
foreach ($element->attributes() as $name=>$value)
|
35 |
+
$result['@'.$name] = (string) $value;
|
36 |
+
|
37 |
+
if (self::hasChildren($element)){
|
38 |
+
foreach ($element->children() as $name=>$child)
|
39 |
+
$result[$name][] = self::_asArray($child, $is_canonical);
|
40 |
+
|
41 |
+
} elseif (empty($result))
|
42 |
+
$result = (string) $element;
|
43 |
+
elseif (!empty((string) $element))
|
44 |
+
$result[0] = (string) $element;
|
45 |
+
return $result;
|
46 |
+
}
|
47 |
+
|
48 |
+
/**
|
49 |
+
* Does a SimpleXMLElement have any children ?
|
50 |
+
*
|
51 |
+
* @param SimpleXMLElement $element
|
52 |
+
* @return boolean
|
53 |
+
*/
|
54 |
+
public static function hasChildren(SimpleXMLElement $element){
|
55 |
+
if ($children = $element->children())
|
56 |
+
foreach ($children as $child)
|
57 |
+
return true;
|
58 |
+
return false;
|
59 |
+
}
|
60 |
+
|
61 |
+
/**
|
62 |
+
* Collapses all single element arrays to their parents
|
63 |
+
*
|
64 |
+
* @param array $data
|
65 |
+
* @return array
|
66 |
+
*/
|
67 |
+
protected static function condenseArray($data){
|
68 |
+
if (!is_array($data) || empty($data)) return $data;
|
69 |
+
if (count($data) == 1 && isset($data[0]))
|
70 |
+
return self::condenseArray($data[0]);
|
71 |
+
foreach($data as &$child)
|
72 |
+
$child = self::condenseArray($child);
|
73 |
+
return $data;
|
74 |
+
}
|
75 |
+
|
76 |
+
/**
|
77 |
+
* Unfortunately SimpleXMLElement can fail badly on invalid xml so here is a validation function
|
78 |
+
* returns false if any errors are encountered the errors are logged to system.log
|
79 |
+
*
|
80 |
+
* @param string $xml
|
81 |
+
* @return boolean
|
82 |
+
*/
|
83 |
+
public static function isValidXml($xml){
|
84 |
+
libxml_use_internal_errors(true);
|
85 |
+
|
86 |
+
$doc = simplexml_load_string($xml);
|
87 |
+
if (!$doc){
|
88 |
+
$errors = libxml_get_errors();
|
89 |
+
$lines = explode("\n", $xml);
|
90 |
+
foreach($errors as $error){
|
91 |
+
$line = $lines[$error->line - 1];
|
92 |
+
$column = $error->column;
|
93 |
+
Mage::logErr(__METHOD__.': '.$error->line.'/'.$error->column.' - '.$error->message.' - '.substr($line, 0, $column - 1));
|
94 |
+
}
|
95 |
+
libxml_clear_errors();
|
96 |
+
return false;
|
97 |
+
}
|
98 |
+
return true;
|
99 |
+
}
|
100 |
+
}
|
app/code/community/Boku/Paymentgateway/controllers/Adminhtml/BokuController.php
ADDED
@@ -0,0 +1,16 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* Admin controller
|
4 |
+
*
|
5 |
+
* @category Payment gateway
|
6 |
+
* @package boku_paymentgateway
|
7 |
+
* @copyright Copyright (c) Boku (http://www.boku.com/)
|
8 |
+
* @author MDH <mdh@treatid.me.uk>
|
9 |
+
*/
|
10 |
+
class Boku_Paymentgateway_Adminhtml_BokuController extends Mage_Adminhtml_Controller_Action
|
11 |
+
{
|
12 |
+
public function testAction(){
|
13 |
+
$this->loadLayout();
|
14 |
+
$this->renderLayout();
|
15 |
+
}
|
16 |
+
}
|
app/code/community/Boku/Paymentgateway/controllers/ApiController.php
ADDED
@@ -0,0 +1,236 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* Boku callback controller
|
4 |
+
*
|
5 |
+
* @category Payment gateway
|
6 |
+
* @package boku_paymentgateway
|
7 |
+
* @copyright Copyright (c) Boku (http://www.boku.com/)
|
8 |
+
* @author MDH <mdh@treatid.me.uk>
|
9 |
+
*/
|
10 |
+
class Boku_Paymentgateway_ApiController extends Mage_Core_Controller_Front_Action
|
11 |
+
{
|
12 |
+
const APP_ROOT = 'boku';
|
13 |
+
|
14 |
+
static $STATUS = array(
|
15 |
+
-1 => 'Unknown error code',
|
16 |
+
0 => 'OK',
|
17 |
+
5 => 'Failed - unknown trx',
|
18 |
+
20 => 'Missing or Invalid "cmd=" value',
|
19 |
+
28 => 'Invalid signature',
|
20 |
+
29 => 'Unsupported Price Point',
|
21 |
+
31 => 'Invalid Or Missing Price',
|
22 |
+
32 => 'Bad Bind Credentials',
|
23 |
+
33 => 'Invalid Or Missing Currency Code',
|
24 |
+
34 => 'Invalid Or Missing Service-Id',
|
25 |
+
35 => 'Internal Error',
|
26 |
+
36 => 'Invalid or Missing Country Code',
|
27 |
+
37 => 'Invalid Dynamic Pricing Mode',
|
28 |
+
38 => 'Invalid Dynamic-match',
|
29 |
+
39 => 'Invalid or missing Dynamic-deviation',
|
30 |
+
40 => 'Invalid or missing Dynamic-deviation-policy',
|
31 |
+
41 => 'No payment solution available',
|
32 |
+
42 => 'Country not available on requested service',
|
33 |
+
43 => 'Invalid Request',
|
34 |
+
51 => 'Expired timestamp',
|
35 |
+
52 => 'Incorrect field format',
|
36 |
+
53 => 'Invalid field value',
|
37 |
+
60 => 'Invalid "row-ref" value',
|
38 |
+
91 => 'Missing or invalid user parameter(s)',
|
39 |
+
93 => 'Unsupported network',
|
40 |
+
99 => 'Boku undergoing maintenance',
|
41 |
+
);
|
42 |
+
/**
|
43 |
+
* These are the minimum sets of parameters required for each callback.
|
44 |
+
*/
|
45 |
+
static $REQUIRED_PARAMS = array(
|
46 |
+
'common'=>array(
|
47 |
+
'trx-id',
|
48 |
+
'timestamp',
|
49 |
+
'action',
|
50 |
+
),
|
51 |
+
'billingresult'=>array(
|
52 |
+
'result-code',
|
53 |
+
'currency',
|
54 |
+
'paid',
|
55 |
+
'amount',
|
56 |
+
),
|
57 |
+
'event'=>array(
|
58 |
+
'event-code',
|
59 |
+
'currency',
|
60 |
+
'paid',
|
61 |
+
'message-cost',
|
62 |
+
),
|
63 |
+
'chargeback'=>array(
|
64 |
+
'currency',
|
65 |
+
'chargebackamount',
|
66 |
+
'paid',
|
67 |
+
'reason-id',
|
68 |
+
'refundsource',
|
69 |
+
),
|
70 |
+
);
|
71 |
+
|
72 |
+
/**
|
73 |
+
* Handler for all callbacks from Boku
|
74 |
+
*
|
75 |
+
* @input URL parameters
|
76 |
+
* @output XML
|
77 |
+
*/
|
78 |
+
public function indexAction(){
|
79 |
+
$helper = Mage::helper(self::APP_ROOT);
|
80 |
+
$helper->setStore(null);
|
81 |
+
$data = Mage::app()->getRequest()->getParams();
|
82 |
+
$response_data = $this->verifyCallback($data);
|
83 |
+
|
84 |
+
if ($response_data['status_code'] == 0){
|
85 |
+
switch($data['action']){
|
86 |
+
case 'billingresult':
|
87 |
+
case 'event':
|
88 |
+
case 'chargeback':
|
89 |
+
try{
|
90 |
+
$transaction = $helper->getTransaction($data);
|
91 |
+
if (empty($transaction))
|
92 |
+
throw new Exception('Transaction data not found for trx-id='.$data['trx-id'], 5);
|
93 |
+
}catch(Exception $e){
|
94 |
+
$code = $e->getCode();
|
95 |
+
if (empty($code)) $code = -1;
|
96 |
+
$response_data = array_merge($response_data, array(
|
97 |
+
'status_code'=>$code,
|
98 |
+
'status'=>self::$STATUS[$code],
|
99 |
+
));
|
100 |
+
$data['notes'] = $e->getMessage();
|
101 |
+
$helper->logErr(__METHOD__.' - '.$e->getMessage());
|
102 |
+
break;
|
103 |
+
}
|
104 |
+
try{
|
105 |
+
$this->{$data['action'].'Handler'}($data, $response_data);
|
106 |
+
}catch(Exception $e){
|
107 |
+
$helper->log(__CLASS__.'::'.$data['action'].' - '.$e->getMessage());
|
108 |
+
}
|
109 |
+
break;
|
110 |
+
default:
|
111 |
+
$response_data = array_merge($response_data, array(
|
112 |
+
'status_code'=>53,
|
113 |
+
'status'=>self::$STATUS[53],
|
114 |
+
'field'=>'action',
|
115 |
+
));
|
116 |
+
}
|
117 |
+
}
|
118 |
+
$data['status_code'] = $response_data['status_code'];
|
119 |
+
$data['status'] = $response_data['status'];
|
120 |
+
$this->logCallback($data);
|
121 |
+
$r = $this->getResponse();
|
122 |
+
$r->setHeader('HTTP/1.1 200 OK', '', true);
|
123 |
+
$r->setHeader('Content-Type', 'text/xml; charset=utf-8', true);
|
124 |
+
$r->setHeader('Cache-Control', 'no-cache, no-store, must-revalidate', true);
|
125 |
+
$r->setHeader('Expires', 'Expires: Sat, 1 Jan 2000 00:00:00 GMT', true);
|
126 |
+
$r->setHeader('Pragma', 'no-cache', true);
|
127 |
+
$r->setBody($this->getCallbackResponseXml($response_data)->asXML());
|
128 |
+
}
|
129 |
+
|
130 |
+
/**
|
131 |
+
* Callback from Boku at the end of the payment process
|
132 |
+
* Note:assumes that the currency is the same as original prepare call
|
133 |
+
*
|
134 |
+
* @param array $data
|
135 |
+
* @param array $response
|
136 |
+
* @return array $response
|
137 |
+
*/
|
138 |
+
protected function &billingresultHandler($data, &$response){
|
139 |
+
$helper = Mage::helper(self::APP_ROOT);
|
140 |
+
$transaction = $helper->getTransaction($data);
|
141 |
+
if (is_numeric($transaction->getResultCode()))
|
142 |
+
$helper->logErr('Unexpected extra billingresult for trx-id:'.$data['trx-id']);
|
143 |
+
else
|
144 |
+
$transaction->complete($data);
|
145 |
+
return $response;
|
146 |
+
}
|
147 |
+
|
148 |
+
/**
|
149 |
+
* Callback from Boku made for each payment
|
150 |
+
* Note:assumes that the currency is the same as original prepare call
|
151 |
+
*
|
152 |
+
* @param array $data
|
153 |
+
* @param array $response
|
154 |
+
* @return array $response
|
155 |
+
*/
|
156 |
+
protected function &eventHandler(&$data, &$response){
|
157 |
+
Mage::getSingleton(self::APP_ROOT.'/payment_event')->create($data);
|
158 |
+
return $response;
|
159 |
+
}
|
160 |
+
|
161 |
+
/**
|
162 |
+
* Callback from Boku for refunds
|
163 |
+
* Note:assumes that the currency is the same as original prepare call
|
164 |
+
*
|
165 |
+
* @param array $data
|
166 |
+
* @param array $response
|
167 |
+
* @return array $response
|
168 |
+
*/
|
169 |
+
protected function &chargebackHandler(&$data, &$response){
|
170 |
+
Mage::getSingleton(self::APP_ROOT.'/payment_chargeback')->create($data);
|
171 |
+
return $response;
|
172 |
+
}
|
173 |
+
|
174 |
+
/**
|
175 |
+
* Creates a new callback record for the $data['trx-id'] transaction
|
176 |
+
*
|
177 |
+
* @param array $data
|
178 |
+
*/
|
179 |
+
protected function logCallback(&$data){
|
180 |
+
if ($data['status_code'] == 5) $data['trx-id'] = null;
|
181 |
+
return Mage::getModel(self::APP_ROOT.'/payment_callback')->addData($data)->save();
|
182 |
+
}
|
183 |
+
|
184 |
+
/**
|
185 |
+
* Does general verification for all callbacks from Boku
|
186 |
+
* Aborts as soon as a failure is encountered.
|
187 |
+
*
|
188 |
+
* @param array $params
|
189 |
+
* @return array(status_code=>int, status=>string[, field=>string])
|
190 |
+
*/
|
191 |
+
protected function verifyCallback(&$params){
|
192 |
+
$helper = Mage::helper(self::APP_ROOT);
|
193 |
+
try{
|
194 |
+
$remote_ip = Mage::helper('core/http')->getRemoteAddr();
|
195 |
+
$valid_ips = $helper->getConfig('callback_ips');
|
196 |
+
if (!empty($valid_ips) && !in_array($remote_ip, explode(';', $valid_ips)))
|
197 |
+
throw new Exception('Invalid source IP for callback: '.$remote_ip, -1);
|
198 |
+
|
199 |
+
//Verify the validity of the callback signature
|
200 |
+
if (!$helper->verifySignature($params)) throw new Exception('sig', 28);
|
201 |
+
|
202 |
+
//Verify that primary fields exist
|
203 |
+
foreach (self::$REQUIRED_PARAMS['common'] as $field)
|
204 |
+
if (!array_key_exists($field, $params)) throw new Exception($field, $field == 'trx-id' ? 5 : 43);
|
205 |
+
|
206 |
+
//Verify callback specific fields exist
|
207 |
+
foreach (self::$REQUIRED_PARAMS[$params['action']] as $field)
|
208 |
+
if (!array_key_exists($field, $params)) throw new Exception($field, 43);
|
209 |
+
|
210 |
+
$response = array('status_code'=>0, 'status'=>self::$STATUS[0]);
|
211 |
+
|
212 |
+
}catch(Exception $e){
|
213 |
+
$helper->logErr(__METHOD__.': '.$e->getMessage().' '.self::$STATUS[$e->getCode()]."\n".json_encode($params, JSON_PRETTY_PRINT));
|
214 |
+
$status = isset(self::$STATUS[$e->getCode()]) ? self::$STATUS[$e->getCode()] : 'Unknown Status';
|
215 |
+
$response = array('status_code'=>$e->getCode(), 'status'=>$status, 'field'=>$e->getMessage());
|
216 |
+
}
|
217 |
+
$response['trx-id'] = array_key_exists('trx-id', $params) ? $params['trx-id'] : 'Unknown';
|
218 |
+
return $response;
|
219 |
+
}
|
220 |
+
|
221 |
+
/**
|
222 |
+
* Generates SimpleXML data for response.
|
223 |
+
*
|
224 |
+
* @param array $data
|
225 |
+
* @return SimpleXML
|
226 |
+
*/
|
227 |
+
protected function getCallbackResponseXml($data){
|
228 |
+
$xml = new SimpleXMLElement('<?xml version="1.0" encoding="utf-8" standalone="yes" ?><callback-ack></callback-ack>');
|
229 |
+
$xml->addChild('trx-id', $data['trx-id']);
|
230 |
+
$s = $xml->addChild('status', $data['status']);
|
231 |
+
$s->addAttribute('code', $data['status_code']);
|
232 |
+
if ($data['status_code'] == 53)
|
233 |
+
$s->addAttribute('invalidfield', $data['field']);
|
234 |
+
return $xml;
|
235 |
+
}
|
236 |
+
}
|
app/code/community/Boku/Paymentgateway/controllers/StandardController.php
ADDED
@@ -0,0 +1,106 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* Boku payment gateway controller
|
4 |
+
*
|
5 |
+
* @category Payment gateway
|
6 |
+
* @package boku_paymentgateway
|
7 |
+
* @copyright Copyright (c) Boku (http://www.boku.com/)
|
8 |
+
* @author MDH <mdh@treatid.me.uk>
|
9 |
+
*/
|
10 |
+
class Boku_Paymentgateway_StandardController extends Mage_Checkout_Controller_Action
|
11 |
+
{
|
12 |
+
const APP_ROOT = 'boku';
|
13 |
+
|
14 |
+
public function prepareAction(){
|
15 |
+
$this->loadLayout();
|
16 |
+
$this->renderLayout();
|
17 |
+
}
|
18 |
+
|
19 |
+
/**
|
20 |
+
* Called by Boku for failed transactions
|
21 |
+
* Cancels the order, detatches the order and transaction from the quote
|
22 |
+
* restores the quote to the basket.
|
23 |
+
*/
|
24 |
+
public function cancelAction(){
|
25 |
+
$helper = Mage::helper(self::APP_ROOT);
|
26 |
+
$boku_session = $helper->getSession();
|
27 |
+
$trx_id = $boku_session->getData('trx-id');
|
28 |
+
$boku_session->clear();
|
29 |
+
$data = Mage::app()->getRequest()->getParams();
|
30 |
+
try{
|
31 |
+
if (isset($data['trx-id'])){
|
32 |
+
if (empty($trx_id))
|
33 |
+
$trx_id = $data['trx-id'];
|
34 |
+
else if ($data['trx-id'] != $trx_id)
|
35 |
+
throw new Exception('trx-id:'.$data['trx-id'].' not same as session:'.$trx_id);
|
36 |
+
}else if (empty($trx_id))
|
37 |
+
throw new Exception('No trx-id param');
|
38 |
+
if (is_null($transaction = $helper->getTransaction($trx_id))) throw new Exception('Transaction '.$trx_id.' record not found.');
|
39 |
+
if ($transaction->getCancelled()) throw new Exception('Transaction '.$trx_id.' already cancelled.');
|
40 |
+
|
41 |
+
$order = $transaction->getOrder();
|
42 |
+
$quote = $transaction->getQuote();
|
43 |
+
$transaction->setCancelled(true)->setQuoteId(null)->save();
|
44 |
+
|
45 |
+
if (!is_null($quote)){
|
46 |
+
$quote->setIsActive(true)->setReservedOrderId(null)->save();
|
47 |
+
if (!is_null($order))
|
48 |
+
$order->setQuoteId(null)->save();
|
49 |
+
$session = Mage::getSingleton('checkout/session');
|
50 |
+
$session->setQuoteId($quote->getId());
|
51 |
+
$session->setFirstTimeChk('0');
|
52 |
+
Mage::getSingleton('checkout/type_onepage')->getCheckout()->unsLastQuoteId();
|
53 |
+
}
|
54 |
+
|
55 |
+
if (!is_null($order)){
|
56 |
+
// $order->addStatusHistoryComment('Boku Transaction Cancelled');
|
57 |
+
if ($order->canCancel())
|
58 |
+
$order->cancel()->save();
|
59 |
+
}
|
60 |
+
}catch(Exception $e){
|
61 |
+
$helper->logErr(__METHOD__.': '.$e->getMessage());
|
62 |
+
}
|
63 |
+
$this->loadLayout();
|
64 |
+
$this->renderLayout();
|
65 |
+
}
|
66 |
+
|
67 |
+
/**
|
68 |
+
* Called by Boku for successful transactions
|
69 |
+
* changes the order status to STATE_PENDING_PAYMENT (if STATE_NEW)
|
70 |
+
*/
|
71 |
+
public function successAction(){
|
72 |
+
$helper = Mage::helper(self::APP_ROOT);
|
73 |
+
$boku_session = $helper->getSession();
|
74 |
+
$trx_id = $boku_session->getData('trx-id');
|
75 |
+
$boku_session->clear();
|
76 |
+
$data = Mage::app()->getRequest()->getParams();
|
77 |
+
try{
|
78 |
+
if (!isset($data['trx-id'])) throw new Exception('No trx-id param');
|
79 |
+
if (empty($trx_id))
|
80 |
+
$trx_id = $data['trx-id'];
|
81 |
+
else if ($data['trx-id'] != $trx_id)
|
82 |
+
throw new Exception('trx-id:'.$data['trx-id'].' not same as session:'.$trx_id);
|
83 |
+
if (is_null($transaction = $helper->getTransaction($trx_id))) throw new Exception('Transaction '.$trx_id.' record not found.');
|
84 |
+
if ($transaction->getCancelled()) throw new Exception('Transaction '.$trx_id.' already cancelled.');
|
85 |
+
if (is_null($order = $transaction->getOrder())) throw new Exception('Order not found for '.$trx_id);
|
86 |
+
|
87 |
+
if ($order->getState() == $order::STATE_NEW)
|
88 |
+
$order->setState($order::STATE_PENDING_PAYMENT)->save();
|
89 |
+
$order->addStatusHistoryComment('Boku Transaction Initiated');
|
90 |
+
|
91 |
+
$msg = $helper->getConfig('message/success');
|
92 |
+
if (!empty($msg)) Mage::getSingleton('checkout/session')->addNotice($msg);
|
93 |
+
}catch(Exception $e){
|
94 |
+
$helper->logErr(__METHOD__.': '.$e->getMessage());
|
95 |
+
}
|
96 |
+
$this->loadLayout();
|
97 |
+
$this->renderLayout();
|
98 |
+
}
|
99 |
+
|
100 |
+
/**
|
101 |
+
* Not used in normal activity. Can be called to force completion of any outstanding callback handling.
|
102 |
+
*/
|
103 |
+
public function completeAction(){
|
104 |
+
Mage::helper(self::APP_ROOT)->completeOutstanding();
|
105 |
+
}
|
106 |
+
}
|
app/code/community/Boku/Paymentgateway/etc/adminhtml.xml
ADDED
@@ -0,0 +1,61 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?xml version="1.0"?>
|
2 |
+
<!--
|
3 |
+
/**
|
4 |
+
* Boku admin menu
|
5 |
+
*
|
6 |
+
* @category Payment gateway
|
7 |
+
* @package boku_paymentgateway
|
8 |
+
* @copyright Copyright (c) Boku (http://www.boku.com/)
|
9 |
+
* @author MDH <mdh@treatid.me.uk>
|
10 |
+
*/
|
11 |
+
-->
|
12 |
+
<config>
|
13 |
+
<menu>
|
14 |
+
<system>
|
15 |
+
<children>
|
16 |
+
<boku translate="title" module="boku">
|
17 |
+
<title>Boku</title>
|
18 |
+
<sort_order>1000</sort_order>
|
19 |
+
<children>
|
20 |
+
<settings translate="title">
|
21 |
+
<title>Configure</title>
|
22 |
+
<action>adminhtml/system_config/edit/section/payment</action>
|
23 |
+
<sort_order>1</sort_order>
|
24 |
+
</settings>
|
25 |
+
<test translate="title">
|
26 |
+
<title>Test</title>
|
27 |
+
<action>boku_admin/adminhtml_boku/test</action>
|
28 |
+
<sort_order>10</sort_order>
|
29 |
+
</test>
|
30 |
+
</children>
|
31 |
+
</boku>
|
32 |
+
</children>
|
33 |
+
</system>
|
34 |
+
</menu>
|
35 |
+
<acl>
|
36 |
+
<resources>
|
37 |
+
<all translate="title">
|
38 |
+
<title>Allow Everything</title>
|
39 |
+
</all>
|
40 |
+
<admin>
|
41 |
+
<children>
|
42 |
+
<system>
|
43 |
+
<children>
|
44 |
+
<boku>
|
45 |
+
<title>Boku</title>
|
46 |
+
<children>
|
47 |
+
<settings translate="title">
|
48 |
+
<title>Configure</title>
|
49 |
+
</settings>
|
50 |
+
<test translate="title">
|
51 |
+
<title>Test Settings</title>
|
52 |
+
</test>
|
53 |
+
</children>
|
54 |
+
</boku>
|
55 |
+
</children>
|
56 |
+
</system>
|
57 |
+
</children>
|
58 |
+
</admin>
|
59 |
+
</resources>
|
60 |
+
</acl>
|
61 |
+
</config>
|
app/code/community/Boku/Paymentgateway/etc/config.xml
ADDED
@@ -0,0 +1,177 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?xml version="1.0"?>
|
2 |
+
<!--
|
3 |
+
/**
|
4 |
+
* Main Module configuration
|
5 |
+
*
|
6 |
+
* @category Payment gateway
|
7 |
+
* @package boku_paymentgateway
|
8 |
+
* @copyright Copyright (c) Boku (http://www.boku.com/)
|
9 |
+
* @author MDH <mdh@treatid.me.uk>
|
10 |
+
*/
|
11 |
+
-->
|
12 |
+
<config>
|
13 |
+
<modules>
|
14 |
+
<Boku_Paymentgateway>
|
15 |
+
<version>0.0.4</version>
|
16 |
+
</Boku_Paymentgateway>
|
17 |
+
</modules>
|
18 |
+
|
19 |
+
<global>
|
20 |
+
<models>
|
21 |
+
<boku>
|
22 |
+
<class>Boku_Paymentgateway_Model</class>
|
23 |
+
<resourceModel>boku_resource</resourceModel>
|
24 |
+
</boku>
|
25 |
+
<boku_resource>
|
26 |
+
<class>Boku_Paymentgateway_Model_Resource</class>
|
27 |
+
<entities>
|
28 |
+
<payment_transaction>
|
29 |
+
<table>boku_transactions</table>
|
30 |
+
</payment_transaction>
|
31 |
+
<payment_callback>
|
32 |
+
<table>boku_callbacks</table>
|
33 |
+
</payment_callback>
|
34 |
+
<payment_event>
|
35 |
+
<table>boku_events</table>
|
36 |
+
</payment_event>
|
37 |
+
<payment_chargeback>
|
38 |
+
<table>boku_chargebacks</table>
|
39 |
+
</payment_chargeback>
|
40 |
+
</entities>
|
41 |
+
</boku_resource>
|
42 |
+
</models>
|
43 |
+
|
44 |
+
<resources>
|
45 |
+
<boku_setup>
|
46 |
+
<setup>
|
47 |
+
<module>Boku_Paymentgateway</module>
|
48 |
+
<class>Boku_Paymentgateway_Model_Resource_Setup</class>
|
49 |
+
</setup>
|
50 |
+
</boku_setup>
|
51 |
+
</resources>
|
52 |
+
|
53 |
+
<helpers>
|
54 |
+
<boku>
|
55 |
+
<class>Boku_Paymentgateway_Helper</class>
|
56 |
+
</boku>
|
57 |
+
</helpers>
|
58 |
+
|
59 |
+
<blocks>
|
60 |
+
<boku>
|
61 |
+
<class>Boku_Paymentgateway_Block</class>
|
62 |
+
</boku>
|
63 |
+
</blocks>
|
64 |
+
|
65 |
+
</global>
|
66 |
+
|
67 |
+
<admin>
|
68 |
+
<routers>
|
69 |
+
<!--adminhtml>
|
70 |
+
<args>
|
71 |
+
<modules>
|
72 |
+
<Boku_Paymentgateway>Boku_Paymentgateway_Adminhtml</Boku_Paymentgateway>
|
73 |
+
</modules>
|
74 |
+
</args>
|
75 |
+
</adminhtml-->
|
76 |
+
<boku_admin>
|
77 |
+
<use>admin</use>
|
78 |
+
<args>
|
79 |
+
<module>Boku_Paymentgateway</module>
|
80 |
+
<frontName>boku_admin</frontName>
|
81 |
+
</args>
|
82 |
+
</boku_admin>
|
83 |
+
</routers>
|
84 |
+
</admin>
|
85 |
+
|
86 |
+
<adminhtml>
|
87 |
+
<layout>
|
88 |
+
<updates>
|
89 |
+
<boku_paymentgateway>
|
90 |
+
<file>boku_paymentgateway.xml</file>
|
91 |
+
</boku_paymentgateway>
|
92 |
+
</updates>
|
93 |
+
</layout>
|
94 |
+
<translate>
|
95 |
+
<modules>
|
96 |
+
<Boku_Paymentgateway>
|
97 |
+
<files>
|
98 |
+
<default>Boku_Paymentgateway.csv</default>
|
99 |
+
</files>
|
100 |
+
</Boku_Paymentgateway>
|
101 |
+
</modules>
|
102 |
+
</translate>
|
103 |
+
</adminhtml>
|
104 |
+
|
105 |
+
<frontend>
|
106 |
+
<secure_url>
|
107 |
+
<boku>/boku/standard</boku>
|
108 |
+
<bokuapi>/boku/api</bokuapi>
|
109 |
+
</secure_url>
|
110 |
+
|
111 |
+
<routers>
|
112 |
+
<boku>
|
113 |
+
<use>standard</use>
|
114 |
+
<args>
|
115 |
+
<module>Boku_Paymentgateway</module>
|
116 |
+
<frontName>boku</frontName>
|
117 |
+
</args>
|
118 |
+
</boku>
|
119 |
+
</routers>
|
120 |
+
|
121 |
+
<translate>
|
122 |
+
<modules>
|
123 |
+
<Boku_Paymentgateway>
|
124 |
+
<files>
|
125 |
+
<default>Boku_Paymentgateway.csv</default>
|
126 |
+
</files>
|
127 |
+
</Boku_Paymentgateway>
|
128 |
+
</modules>
|
129 |
+
</translate>
|
130 |
+
|
131 |
+
<layout>
|
132 |
+
<updates>
|
133 |
+
<boku_paymentgateway>
|
134 |
+
<file>boku_paymentgateway.xml</file>
|
135 |
+
</boku_paymentgateway>
|
136 |
+
</updates>
|
137 |
+
</layout>
|
138 |
+
</frontend>
|
139 |
+
|
140 |
+
<default>
|
141 |
+
<payment>
|
142 |
+
<boku>
|
143 |
+
<model>boku/payment_standard</model>
|
144 |
+
<payment_action>Authorization</payment_action>
|
145 |
+
<mode>1</mode>
|
146 |
+
<active>0</active>
|
147 |
+
<auto_invoice>0</auto_invoice>
|
148 |
+
<title>Boku (Pay by Mobile)</title>
|
149 |
+
<order_status>processing</order_status>
|
150 |
+
<api_security_key backend_model="adminhtml/system_config_backend_encrypted" />
|
151 |
+
<!--payment>
|
152 |
+
NOT IMPLEMENTED
|
153 |
+
<commission_add>0</commission_add>
|
154 |
+
<below_min>0</below_min>
|
155 |
+
<above_max>0</above_max>
|
156 |
+
<unavailable>0</unavailable>
|
157 |
+
<max>0</max>
|
158 |
+
</payment-->
|
159 |
+
<url>
|
160 |
+
<pricelist>https://api2.boku.com/pricing/1.0/price-list</pricelist>
|
161 |
+
<priceinfo>https://api2.boku.com/pricing/1.0/price-info</priceinfo>
|
162 |
+
<prepare>https://api2.boku.com/billing/request?action=prepare</prepare>
|
163 |
+
</url>
|
164 |
+
</boku>
|
165 |
+
</payment>
|
166 |
+
</default>
|
167 |
+
|
168 |
+
<crontab>
|
169 |
+
<jobs>
|
170 |
+
<boku_cron>
|
171 |
+
<!-- run at midnight daily. Note cron execution must be setup on the server for this to run. -->
|
172 |
+
<schedule><cron_expr>0 0 * * *</cron_expr></schedule>
|
173 |
+
<run><model>boku/cron::run</model></run>
|
174 |
+
</boku_cron>
|
175 |
+
</jobs>
|
176 |
+
</crontab>
|
177 |
+
</config>
|
app/code/community/Boku/Paymentgateway/etc/system.xml
ADDED
@@ -0,0 +1,248 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?xml version="1.0"?>
|
2 |
+
<!--
|
3 |
+
/**
|
4 |
+
* Magento admin configuration section
|
5 |
+
* Config options for Boku module
|
6 |
+
*
|
7 |
+
* @category Payment gateway
|
8 |
+
* @package boku_paymentgateway
|
9 |
+
* @copyright Copyright (c) Boku (http://www.boku.com/)
|
10 |
+
* @author MDH <mdh@treatid.me.uk>
|
11 |
+
*/
|
12 |
+
-->
|
13 |
+
<config>
|
14 |
+
<sections>
|
15 |
+
<payment>
|
16 |
+
<groups>
|
17 |
+
<boku translate="label" module="boku">
|
18 |
+
<label>Boku (Pay by Mobile)</label>
|
19 |
+
<comment><![CDATA[<a href="https://www.boku.com/merchant-partnerships/" target="_blank">Sign up for a Boku account</a>]]></comment>
|
20 |
+
<frontend_type>text</frontend_type>
|
21 |
+
<sort_order>10</sort_order>
|
22 |
+
<show_in_default>1</show_in_default>
|
23 |
+
<show_in_website>1</show_in_website>
|
24 |
+
<show_in_store>1</show_in_store>
|
25 |
+
<fields>
|
26 |
+
<merchant_id translate="label" module="boku">
|
27 |
+
<label>Merchant ID</label>
|
28 |
+
<comment><![CDATA[This is your Boku Merchant ID.]]></comment>
|
29 |
+
<sort_order>0</sort_order>
|
30 |
+
<required>1</required>
|
31 |
+
<show_in_default>1</show_in_default>
|
32 |
+
<show_in_website>1</show_in_website>
|
33 |
+
</merchant_id>
|
34 |
+
<api_security_key translate="label" module="boku">
|
35 |
+
<label>API Security Key</label>
|
36 |
+
<comment><![CDATA[This is your Boku API security key<br> (stored as encrypted data).]]></comment>
|
37 |
+
<frontend_type>text</frontend_type>
|
38 |
+
<backend_model>adminhtml/system_config_backend_encrypted</backend_model>
|
39 |
+
<sort_order>5</sort_order>
|
40 |
+
<show_in_default>1</show_in_default>
|
41 |
+
<show_in_website>1</show_in_website>
|
42 |
+
</api_security_key>
|
43 |
+
<service_id translate="label" module="boku">
|
44 |
+
<label>Service ID</label>
|
45 |
+
<comment><![CDATA[This is your Boku service id. (Not the service name)]]></comment>
|
46 |
+
<frontend_type>text</frontend_type>
|
47 |
+
<sort_order>10</sort_order>
|
48 |
+
<show_in_default>1</show_in_default>
|
49 |
+
<show_in_website>1</show_in_website>
|
50 |
+
</service_id>
|
51 |
+
<sub_merchant_name translate="label" module="boku">
|
52 |
+
<label>Sub Merchant Name</label>
|
53 |
+
<comment><![CDATA[This appears as an identifier on the Boku payment panel.<br>If left blank then the panel uses the service name specified in your Boku account.]]></comment>
|
54 |
+
<frontend_type>text</frontend_type>
|
55 |
+
<sort_order>12</sort_order>
|
56 |
+
<show_in_default>1</show_in_default>
|
57 |
+
<show_in_website>1</show_in_website>
|
58 |
+
</sub_merchant_name>
|
59 |
+
<mode translate="label">
|
60 |
+
<label>Mode</label>
|
61 |
+
<frontend_type>select</frontend_type>
|
62 |
+
<source_model>boku/system_config::getModeOptions</source_model>
|
63 |
+
<sort_order>14</sort_order>
|
64 |
+
<show_in_default>1</show_in_default>
|
65 |
+
<show_in_website>1</show_in_website>
|
66 |
+
</mode>
|
67 |
+
<auto_invoice translate="label">
|
68 |
+
<label>Generate Invoices</label>
|
69 |
+
<comment><![CDATA[If the payment process completes and the total paid matches the order total then should we generate an invoice ? This also sends the generated invoice to the customer (if possible).]]></comment>
|
70 |
+
<frontend_type>select</frontend_type>
|
71 |
+
<source_model>adminhtml/system_config_source_yesno</source_model>
|
72 |
+
<sort_order>16</sort_order>
|
73 |
+
<show_in_default>1</show_in_default>
|
74 |
+
<show_in_website>1</show_in_website>
|
75 |
+
</auto_invoice>
|
76 |
+
<message_success translate="label" module="boku">
|
77 |
+
<label>Success Message</label>
|
78 |
+
<comment><![CDATA[Optional additional message for the payment success page.]]></comment>
|
79 |
+
<frontend_type>text</frontend_type>
|
80 |
+
<config_path>payment/boku/message/success</config_path>
|
81 |
+
<sort_order>17</sort_order>
|
82 |
+
<show_in_default>1</show_in_default>
|
83 |
+
<show_in_website>1</show_in_website>
|
84 |
+
</message_success>
|
85 |
+
<active translate="label">
|
86 |
+
<label>Enabled</label>
|
87 |
+
<frontend_type>select</frontend_type>
|
88 |
+
<source_model>adminhtml/system_config_source_yesno</source_model>
|
89 |
+
<sort_order>19</sort_order>
|
90 |
+
<show_in_default>1</show_in_default>
|
91 |
+
<show_in_website>1</show_in_website>
|
92 |
+
</active>
|
93 |
+
|
94 |
+
<heading_standard translate="label">
|
95 |
+
<label>Standard Payment Settings</label>
|
96 |
+
<frontend_model>adminhtml/system_config_form_field_heading</frontend_model>
|
97 |
+
<sort_order>20</sort_order>
|
98 |
+
<show_in_default>1</show_in_default>
|
99 |
+
<show_in_website>1</show_in_website>
|
100 |
+
</heading_standard>
|
101 |
+
<title translate="label">
|
102 |
+
<label>Title</label>
|
103 |
+
<frontend_type>text</frontend_type>
|
104 |
+
<sort_order>25</sort_order>
|
105 |
+
<show_in_default>1</show_in_default>
|
106 |
+
<show_in_website>1</show_in_website>
|
107 |
+
<show_in_store>1</show_in_store>
|
108 |
+
</title>
|
109 |
+
<allowspecific translate="label">
|
110 |
+
<label>Payment from Applicable Countries</label>
|
111 |
+
<comment><![CDATA[This country restriction is applied to the Billing Address.]]></comment>
|
112 |
+
<frontend_type>allowspecific</frontend_type>
|
113 |
+
<sort_order>35</sort_order>
|
114 |
+
<source_model>adminhtml/system_config_source_payment_allspecificcountries</source_model>
|
115 |
+
<show_in_default>1</show_in_default>
|
116 |
+
<show_in_website>1</show_in_website>
|
117 |
+
</allowspecific>
|
118 |
+
<specificcountry translate="label">
|
119 |
+
<label>Payment from Specific Countries</label>
|
120 |
+
<frontend_type>multiselect</frontend_type>
|
121 |
+
<sort_order>40</sort_order>
|
122 |
+
<source_model>adminhtml/system_config_source_country</source_model>
|
123 |
+
<show_in_default>1</show_in_default>
|
124 |
+
<show_in_website>1</show_in_website>
|
125 |
+
</specificcountry>
|
126 |
+
<min_order_total translate="label">
|
127 |
+
<label>Minimum Order Total</label>
|
128 |
+
<frontend_type>text</frontend_type>
|
129 |
+
<sort_order>45</sort_order>
|
130 |
+
<show_in_default>1</show_in_default>
|
131 |
+
<show_in_website>1</show_in_website>
|
132 |
+
</min_order_total>
|
133 |
+
<max_order_total translate="label">
|
134 |
+
<label>Maximum Order Total</label>
|
135 |
+
<comment><![CDATA[Minimum and Maximum totals will also be restricted by your Boku account settings.]]></comment>
|
136 |
+
<frontend_type>text</frontend_type>
|
137 |
+
<sort_order>50</sort_order>
|
138 |
+
<show_in_default>1</show_in_default>
|
139 |
+
<show_in_website>1</show_in_website>
|
140 |
+
</max_order_total>
|
141 |
+
<sort_order translate="label">
|
142 |
+
<label>Sort Order</label>
|
143 |
+
<frontend_type>text</frontend_type>
|
144 |
+
<sort_order>55</sort_order>
|
145 |
+
<show_in_default>1</show_in_default>
|
146 |
+
<show_in_website>1</show_in_website>
|
147 |
+
<frontend_class>validate-number</frontend_class>
|
148 |
+
</sort_order>
|
149 |
+
<!--
|
150 |
+
NOT IMPLEMENTED
|
151 |
+
<heading_extended translate="label">
|
152 |
+
<label>Extended Payment Settings</label>
|
153 |
+
<frontend_model>adminhtml/system_config_form_field_heading</frontend_model>
|
154 |
+
<sort_order>100</sort_order>
|
155 |
+
<show_in_default>1</show_in_default>
|
156 |
+
<show_in_website>1</show_in_website>
|
157 |
+
</heading_extended>
|
158 |
+
<commission_add translate="label" module="boku">
|
159 |
+
<label>Add Commission</label>
|
160 |
+
<comment><![CDATA[Add estimated Boku and Carrier commissions to the basket value for all Boku payments.]]></comment>
|
161 |
+
<frontend_type>select</frontend_type>
|
162 |
+
<source_model>boku/system_config::getCommissionOptions</source_model>
|
163 |
+
<sort_order>105</sort_order>
|
164 |
+
<show_in_default>1</show_in_default>
|
165 |
+
<show_in_website>1</show_in_website>
|
166 |
+
</commission_add>
|
167 |
+
<below_min translate="label" module="boku">
|
168 |
+
<label>Value Below Minimum</label>
|
169 |
+
<comment><![CDATA[What if the value is below the minimum possible ?]]></comment>
|
170 |
+
<frontend_type>select</frontend_type>
|
171 |
+
<source_model>boku/system_config::getPaymentBelowMinOptions</source_model>
|
172 |
+
<sort_order>110</sort_order>
|
173 |
+
<show_in_default>1</show_in_default>
|
174 |
+
<show_in_website>1</show_in_website>
|
175 |
+
</below_min>
|
176 |
+
<above_max translate="label" module="boku">
|
177 |
+
<label>Value Above Maximum</label>
|
178 |
+
<comment><![CDATA[What if the value is above the maximum possible ?]]></comment>
|
179 |
+
<frontend_type>select</frontend_type>
|
180 |
+
<source_model>boku/system_config::getPaymentAboveMaxOptions</source_model>
|
181 |
+
<sort_order>115</sort_order>
|
182 |
+
<show_in_default>1</show_in_default>
|
183 |
+
<show_in_website>1</show_in_website>
|
184 |
+
</above_max>
|
185 |
+
<unavailable translate="label" module="boku">
|
186 |
+
<label>Value Unavailable</label>
|
187 |
+
<comment><![CDATA[What if the value is in the allowed range but the price point is unavailable ? <i>(because of Carrier or your Boku admin settings)</i>]]></comment>
|
188 |
+
<frontend_type>select</frontend_type>
|
189 |
+
<source_model>boku/system_config::getPaymentUnavailableOptions</source_model>
|
190 |
+
<sort_order>120</sort_order>
|
191 |
+
<show_in_default>1</show_in_default>
|
192 |
+
<show_in_website>1</show_in_website>
|
193 |
+
</unavailable>
|
194 |
+
-->
|
195 |
+
<heading_advanced translate="label">
|
196 |
+
<label><![CDATA[Advanced Settings<br>You should <b>NOT</b> change these settings unless advised to by Boku.]]></label>
|
197 |
+
<frontend_model>adminhtml/system_config_form_field_heading</frontend_model>
|
198 |
+
<sort_order>200</sort_order>
|
199 |
+
<show_in_default>1</show_in_default>
|
200 |
+
<show_in_website>1</show_in_website>
|
201 |
+
</heading_advanced>
|
202 |
+
<url_callback translate="label" module="boku">
|
203 |
+
<label>Callback URL</label>
|
204 |
+
<comment><![CDATA[This is the url used by the Boku server to notify your server of transaction events.<br>Leave blank to use the default (e.g. <i>yourdomain</i>/boku/api), only specify if you require an unusual connection.<br>NOTE: The default value includes the store scope so you may need to be careful with a complex configuration.]]></comment>
|
205 |
+
<frontend_type>text</frontend_type>
|
206 |
+
<config_path>payment/boku/url/callback</config_path>
|
207 |
+
<sort_order>202</sort_order>
|
208 |
+
<show_in_default>1</show_in_default>
|
209 |
+
<show_in_website>1</show_in_website>
|
210 |
+
</url_callback>
|
211 |
+
<callback_ips translate="label" module="boku">
|
212 |
+
<label>Callback IPs</label>
|
213 |
+
<comment><![CDATA[For additional security you can specify a semi-colon delimited list of IP addresses allowed for callbacks. If blank then there are no restrictions.]]></comment>
|
214 |
+
<frontend_type>text</frontend_type>
|
215 |
+
<sort_order>203</sort_order>
|
216 |
+
<show_in_default>1</show_in_default>
|
217 |
+
<show_in_website>1</show_in_website>
|
218 |
+
</callback_ips>
|
219 |
+
<url_pricelist translate="label" module="boku">
|
220 |
+
<label>Pricelist URL</label>
|
221 |
+
<frontend_type>text</frontend_type>
|
222 |
+
<config_path>payment/boku/url/pricelist</config_path>
|
223 |
+
<sort_order>205</sort_order>
|
224 |
+
<show_in_default>1</show_in_default>
|
225 |
+
<show_in_website>1</show_in_website>
|
226 |
+
</url_pricelist>
|
227 |
+
<url_priceinfo translate="label" module="boku">
|
228 |
+
<label>Priceinfo URL</label>
|
229 |
+
<frontend_type>text</frontend_type>
|
230 |
+
<config_path>payment/boku/url/priceinfo</config_path>
|
231 |
+
<sort_order>206</sort_order>
|
232 |
+
<show_in_default>1</show_in_default>
|
233 |
+
<show_in_website>1</show_in_website>
|
234 |
+
</url_priceinfo>
|
235 |
+
<url_prepare translate="label" module="boku">
|
236 |
+
<label>Prepare URL</label>
|
237 |
+
<frontend_type>text</frontend_type>
|
238 |
+
<config_path>payment/boku/url/prepare</config_path>
|
239 |
+
<sort_order>210</sort_order>
|
240 |
+
<show_in_default>1</show_in_default>
|
241 |
+
<show_in_website>1</show_in_website>
|
242 |
+
</url_prepare>
|
243 |
+
</fields>
|
244 |
+
</boku>
|
245 |
+
</groups>
|
246 |
+
</payment>
|
247 |
+
</sections>
|
248 |
+
</config>
|
app/code/community/Boku/Paymentgateway/sql/boku_setup/install-0.0.1.php
ADDED
@@ -0,0 +1,146 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* Boku table creation
|
4 |
+
*
|
5 |
+
* @category Payment gateway
|
6 |
+
* @package boku_paymentgateway
|
7 |
+
* @copyright Copyright (c) Boku (http://www.boku.com/)
|
8 |
+
* @author MDH <mdh@treatid.me.uk>
|
9 |
+
*/
|
10 |
+
$installer = $this;
|
11 |
+
$installer->startSetup();
|
12 |
+
|
13 |
+
/**
|
14 |
+
* Create table 'boku/transactions'
|
15 |
+
*/
|
16 |
+
$transactions_table = 'boku/payment_transaction';
|
17 |
+
$table_name = $transactions_table;
|
18 |
+
$table = $installer->getConnection()
|
19 |
+
->newTable($installer->getTable($table_name))
|
20 |
+
->addColumn('trx_id', Varien_Db_Ddl_Table::TYPE_CHAR, 50, array(
|
21 |
+
'nullable' =>false,
|
22 |
+
'primary' =>true,
|
23 |
+
))
|
24 |
+
->addColumn('store_id', Varien_Db_Ddl_Table::TYPE_SMALLINT, null, array('unsigned'=>true,))
|
25 |
+
->addColumn('quote_id', Varien_Db_Ddl_Table::TYPE_INTEGER, null, array('unsigned'=>true,))
|
26 |
+
->addColumn('order_id', Varien_Db_Ddl_Table::TYPE_INTEGER, null, array('unsigned'=>true,))
|
27 |
+
->addColumn('test', Varien_Db_Ddl_Table::TYPE_BOOLEAN, null, array('nullable'=>false,))
|
28 |
+
->addColumn('country', Varien_Db_Ddl_Table::TYPE_CHAR, 2, array('nullable'=>false,))
|
29 |
+
->addColumn('currency', Varien_Db_Ddl_Table::TYPE_CHAR, 3, array('nullable'=>false,))
|
30 |
+
->addColumn('amount', Varien_Db_Ddl_Table::TYPE_INTEGER, null, array('nullable'=>false,))
|
31 |
+
->addColumn('timestamp', Varien_Db_Ddl_Table::TYPE_TIMESTAMP, null, array('nullable'=>false,))
|
32 |
+
->addColumn('reference_currency', Varien_Db_Ddl_Table::TYPE_CHAR, 3)
|
33 |
+
->addColumn('exchange', Varien_Db_Ddl_Table::TYPE_FLOAT)
|
34 |
+
|
35 |
+
->addColumn('paid', Varien_Db_Ddl_Table::TYPE_INTEGER, null, array('default'=>0, 'nullable'=>false,))
|
36 |
+
->addColumn('paid_inc_salestax', Varien_Db_Ddl_Table::TYPE_INTEGER, null, array('default'=>0, 'nullable'=>false,))
|
37 |
+
->addColumn('paid_ex_salestax', Varien_Db_Ddl_Table::TYPE_INTEGER, null, array('default'=>0, 'nullable'=>false,))
|
38 |
+
->addColumn('receivable_gross', Varien_Db_Ddl_Table::TYPE_INTEGER, null, array('default'=>0, 'nullable'=>false,))
|
39 |
+
->addColumn('receivable_net', Varien_Db_Ddl_Table::TYPE_INTEGER, null, array('default'=>0, 'nullable'=>false,))
|
40 |
+
->addColumn('encoded_mobile', Varien_Db_Ddl_Table::TYPE_TEXT, 20)
|
41 |
+
->addColumn('network', Varien_Db_Ddl_Table::TYPE_TEXT, 10)
|
42 |
+
->addColumn('operator_tax_treatment', Varien_Db_Ddl_Table::TYPE_TEXT, 20)
|
43 |
+
->addColumn('optin_enrolled', Varien_Db_Ddl_Table::TYPE_BOOLEAN)
|
44 |
+
->addColumn('optin_used', Varien_Db_Ddl_Table::TYPE_BOOLEAN)
|
45 |
+
|
46 |
+
->addColumn('result_code', Varien_Db_Ddl_Table::TYPE_SMALLINT, null)
|
47 |
+
->addColumn('result_msg', Varien_Db_Ddl_Table::TYPE_TEXT, 255)
|
48 |
+
->addColumn('result_timestamp', Varien_Db_Ddl_Table::TYPE_TIMESTAMP, null)
|
49 |
+
->addColumn('handled', Varien_Db_Ddl_Table::TYPE_BOOLEAN, null, array('default'=>0, 'nullable'=>false,))
|
50 |
+
->addColumn('cancelled', Varien_Db_Ddl_Table::TYPE_BOOLEAN, null, array('default'=>0, 'nullable'=>false,))
|
51 |
+
|
52 |
+
->addIndex($installer->getIdxName(
|
53 |
+
$table_name, array('trx_id'), Varien_Db_Adapter_Interface::INDEX_TYPE_UNIQUE),
|
54 |
+
array('trx_id'), array('type'=>Varien_Db_Adapter_Interface::INDEX_TYPE_UNIQUE))
|
55 |
+
->addIndex($installer->getIdxName($table_name, array('quote_id')), array('quote_id'))
|
56 |
+
->addIndex($installer->getIdxName($table_name, array('order_id')), array('order_id'))
|
57 |
+
->setComment('Boku Transactions');
|
58 |
+
$installer->getConnection()->createTable($table);
|
59 |
+
|
60 |
+
/**
|
61 |
+
* Create table 'boku/callbacks'
|
62 |
+
*/
|
63 |
+
$table_name = 'boku/payment_callback';
|
64 |
+
$table = $installer->getConnection()
|
65 |
+
->newTable($installer->getTable($table_name))
|
66 |
+
->addColumn('id', Varien_Db_Ddl_Table::TYPE_INTEGER, null, array(
|
67 |
+
'identity' =>true,
|
68 |
+
'unsigned' =>true,
|
69 |
+
'nullable' =>false,
|
70 |
+
'primary' =>true,
|
71 |
+
))
|
72 |
+
->addColumn('trx_id', Varien_Db_Ddl_Table::TYPE_CHAR, 50)
|
73 |
+
->addColumn('action', Varien_Db_Ddl_Table::TYPE_TEXT, 16, array('nullable'=>false,))
|
74 |
+
->addColumn('status_code', Varien_Db_Ddl_Table::TYPE_INTEGER, null, array('nullable'=>false,))
|
75 |
+
->addColumn('status', Varien_Db_Ddl_Table::TYPE_TEXT, 255)
|
76 |
+
->addColumn('timestamp', Varien_Db_Ddl_Table::TYPE_TIMESTAMP, null, array('nullable'=>false,))
|
77 |
+
->addColumn('notes', Varien_Db_Ddl_Table::TYPE_TEXT)
|
78 |
+
|
79 |
+
->addIndex($installer->getIdxName($table_name, array('trx_id')), array('trx_id'))
|
80 |
+
->addIndex($installer->getIdxName($table_name, array('action')), array('action'))
|
81 |
+
->addForeignKey(
|
82 |
+
$installer->getFkName($table_name, 'trx_id', $transactions_table,'trx_id'),
|
83 |
+
'trx_id', $installer->getTable($transactions_table), 'trx_id',
|
84 |
+
Varien_Db_Ddl_Table::ACTION_CASCADE, Varien_Db_Ddl_Table::ACTION_CASCADE)
|
85 |
+
->setComment('Boku Callbacks');
|
86 |
+
$installer->getConnection()->createTable($table);
|
87 |
+
|
88 |
+
/**
|
89 |
+
* Create table 'boku/events'
|
90 |
+
*/
|
91 |
+
$table_name = 'boku/payment_event';
|
92 |
+
$table = $installer->getConnection()
|
93 |
+
->newTable($installer->getTable($table_name))
|
94 |
+
->addColumn('id', Varien_Db_Ddl_Table::TYPE_INTEGER, null, array(
|
95 |
+
'identity' =>true,
|
96 |
+
'unsigned' =>true,
|
97 |
+
'nullable' =>false,
|
98 |
+
'primary' =>true,
|
99 |
+
))
|
100 |
+
->addColumn('trx_id', Varien_Db_Ddl_Table::TYPE_CHAR, 50, array('nullable'=>false,))
|
101 |
+
->addColumn('currency', Varien_Db_Ddl_Table::TYPE_CHAR, 3, array('nullable'=>false,))
|
102 |
+
->addColumn('paid', Varien_Db_Ddl_Table::TYPE_INTEGER, null, array('default'=>0, 'nullable'=>false,))
|
103 |
+
->addColumn('receivable_gross', Varien_Db_Ddl_Table::TYPE_INTEGER, null, array('default'=>0, 'nullable'=>false,))
|
104 |
+
->addColumn('message_cost', Varien_Db_Ddl_Table::TYPE_INTEGER, null, array('default'=>0, 'nullable'=>false,))
|
105 |
+
|
106 |
+
->addColumn('event_code', Varien_Db_Ddl_Table::TYPE_SMALLINT, null, array('default'=>0, 'nullable'=>false,))
|
107 |
+
->addColumn('msg', Varien_Db_Ddl_Table::TYPE_TEXT, 255)
|
108 |
+
->addColumn('handled', Varien_Db_Ddl_Table::TYPE_BOOLEAN, null, array('default'=>0, 'nullable'=>false,))
|
109 |
+
|
110 |
+
->addIndex($installer->getIdxName($table_name, array('trx_id')), array('trx_id'))
|
111 |
+
->addForeignKey(
|
112 |
+
$installer->getFkName($table_name, 'trx_id', $transactions_table,'trx_id'),
|
113 |
+
'trx_id', $installer->getTable($transactions_table), 'trx_id',
|
114 |
+
Varien_Db_Ddl_Table::ACTION_CASCADE, Varien_Db_Ddl_Table::ACTION_CASCADE)
|
115 |
+
->setComment('Boku Events');
|
116 |
+
$installer->getConnection()->createTable($table);
|
117 |
+
|
118 |
+
/**
|
119 |
+
* Create table 'boku/chargebacks'
|
120 |
+
*/
|
121 |
+
$table_name = 'boku/payment_chargeback';
|
122 |
+
$table = $installer->getConnection()
|
123 |
+
->newTable($installer->getTable($table_name))
|
124 |
+
->addColumn('id', Varien_Db_Ddl_Table::TYPE_INTEGER, null, array(
|
125 |
+
'identity' =>true,
|
126 |
+
'unsigned' =>true,
|
127 |
+
'nullable' =>false,
|
128 |
+
'primary' =>true,
|
129 |
+
))
|
130 |
+
->addColumn('trx_id', Varien_Db_Ddl_Table::TYPE_CHAR, 50, array('nullable'=>false,))
|
131 |
+
->addColumn('amount', Varien_Db_Ddl_Table::TYPE_INTEGER, null, array('default'=>0, 'nullable'=>false,))
|
132 |
+
->addColumn('chargebackamount', Varien_Db_Ddl_Table::TYPE_INTEGER, null, array('default'=>0, 'nullable'=>false,))
|
133 |
+
->addColumn('reason_id', Varien_Db_Ddl_Table::TYPE_INTEGER, null, array('default'=>0, 'nullable'=>false,))
|
134 |
+
->addColumn('reason', Varien_Db_Ddl_Table::TYPE_TEXT)
|
135 |
+
->addColumn('refundsource', Varien_Db_Ddl_Table::TYPE_TEXT, 16)
|
136 |
+
->addColumn('handled', Varien_Db_Ddl_Table::TYPE_BOOLEAN, null, array('default'=>0, 'nullable'=>false,))
|
137 |
+
|
138 |
+
->addIndex($installer->getIdxName($table_name, array('trx_id')), array('trx_id'))
|
139 |
+
->addForeignKey(
|
140 |
+
$installer->getFkName($table_name, 'trx_id', $transactions_table,'trx_id'),
|
141 |
+
'trx_id', $installer->getTable($transactions_table), 'trx_id',
|
142 |
+
Varien_Db_Ddl_Table::ACTION_CASCADE, Varien_Db_Ddl_Table::ACTION_CASCADE)
|
143 |
+
->setComment('Boku Chargebacks');
|
144 |
+
$installer->getConnection()->createTable($table);
|
145 |
+
|
146 |
+
$installer->endSetup();
|
app/code/community/Boku/Paymentgateway/sql/boku_setup/upgrade-0.0.1-0.0.2.php
ADDED
@@ -0,0 +1,45 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* Boku table updates
|
4 |
+
*
|
5 |
+
* @category Payment gateway
|
6 |
+
* @package boku_paymentgateway
|
7 |
+
* @copyright Copyright (c) Boku (http://www.boku.com/)
|
8 |
+
* @author MDH <mdh@treatid.me.uk>
|
9 |
+
*/
|
10 |
+
$installer = $this;
|
11 |
+
$installer->startSetup();
|
12 |
+
$con = $installer->getConnection();
|
13 |
+
|
14 |
+
$table_name = 'boku/payment_callback';
|
15 |
+
$table = $installer->getTable($table_name);
|
16 |
+
$con->modifyColumn($table, 'trx_id', array(
|
17 |
+
'type'=>Varien_Db_Ddl_Table::TYPE_TEXT, 'length'=>50,));
|
18 |
+
|
19 |
+
$table_name = 'boku/payment_event';
|
20 |
+
$table = $installer->getTable($table_name);
|
21 |
+
$con->addColumn($table, 'paid_inc_salestax', array(
|
22 |
+
'type'=>Varien_Db_Ddl_Table::TYPE_INTEGER, 'default'=>0, 'nullable'=>false, 'comment'=>'paid_inc_salestax'));
|
23 |
+
$con->addColumn($table, 'paid_ex_salestax', array(
|
24 |
+
'type'=>Varien_Db_Ddl_Table::TYPE_INTEGER, 'default'=>0, 'nullable'=>false, 'comment'=>'paid_ex_salestax'));
|
25 |
+
$con->addColumn($table, 'receivable_net', array(
|
26 |
+
'type'=>Varien_Db_Ddl_Table::TYPE_INTEGER, 'default'=>0, 'nullable'=>false, 'comment'=>'receivable_net'));
|
27 |
+
$con->addColumn($table, 'reference_currency', array(
|
28 |
+
'type'=>Varien_Db_Ddl_Table::TYPE_TEXT, 'length'=>3, 'comment'=>'reference_currency'));
|
29 |
+
$con->addColumn($table, 'exchange', array(
|
30 |
+
'type'=>Varien_Db_Ddl_Table::TYPE_FLOAT, 'comment'=>'exchange'));
|
31 |
+
|
32 |
+
$table_name = 'boku/payment_transaction';
|
33 |
+
$table = $installer->getTable($table_name);
|
34 |
+
$con->addColumn($table, 'exchange', array(
|
35 |
+
'type'=>Varien_Db_Ddl_Table::TYPE_FLOAT, 'comment'=>'exchange'));
|
36 |
+
$con->addForeignKey(
|
37 |
+
$installer->getFkName($table_name, 'quote_id', 'sales/quote','entity_id'),
|
38 |
+
$table, 'quote_id', $installer->getTable('sales/quote'), 'entity_id',
|
39 |
+
Varien_Db_Ddl_Table::ACTION_CASCADE, Varien_Db_Ddl_Table::ACTION_CASCADE);
|
40 |
+
$con->addForeignKey(
|
41 |
+
$installer->getFkName($table_name, 'order_id', 'sales/order','entity_id'),
|
42 |
+
$table, 'order_id', $installer->getTable('sales/order'), 'entity_id',
|
43 |
+
Varien_Db_Ddl_Table::ACTION_CASCADE, Varien_Db_Ddl_Table::ACTION_CASCADE);
|
44 |
+
|
45 |
+
$installer->endSetup();
|
app/design/adminhtml/default/default/layout/boku_paymentgateway.xml
ADDED
@@ -0,0 +1,27 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?xml version="1.0"?>
|
2 |
+
<!--
|
3 |
+
/**
|
4 |
+
* Magento backend layout
|
5 |
+
*
|
6 |
+
* @category Payment gateway
|
7 |
+
* @package boku_paymentgateway
|
8 |
+
* @copyright Copyright (c) Boku (http://www.boku.com/)
|
9 |
+
* @author MDH <mdh@treatid.me.uk>
|
10 |
+
*/
|
11 |
+
-->
|
12 |
+
<layout>
|
13 |
+
<boku_admin_adminhtml_boku_test>
|
14 |
+
<reference name="left">
|
15 |
+
<block type="adminhtml/system_config_switcher" name="adminhtml.system.config.switcher" before="-"/>
|
16 |
+
</reference>
|
17 |
+
<reference name="content">
|
18 |
+
<block type="adminhtml/template" name="boku_test" template="boku/paymentgateway/test.phtml"/>
|
19 |
+
</reference>
|
20 |
+
</boku_admin_adminhtml_boku_test>
|
21 |
+
<boku_admin_adminhtml_standard_prepare>
|
22 |
+
<reference name="content">
|
23 |
+
<block type="boku/adminhtml_payment_standard_prepare" name="adminhtml.boku.prepare" template="boku/paymentgateway/standard/prepare.phtml" />
|
24 |
+
</reference>
|
25 |
+
</boku_admin_adminhtml_standard_prepare>
|
26 |
+
|
27 |
+
</layout>
|
app/design/adminhtml/default/default/template/boku/paymentgateway/test.phtml
ADDED
@@ -0,0 +1,63 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* Admin form for testing
|
4 |
+
*
|
5 |
+
* @category Payment gateway
|
6 |
+
* @package boku_paymentgateway
|
7 |
+
* @copyright Copyright (c) Boku (http://www.boku.com/)
|
8 |
+
* @author MDH <mdh@treatid.me.uk>
|
9 |
+
*/
|
10 |
+
|
11 |
+
$helper = $this->helper('boku');
|
12 |
+
|
13 |
+
$helper->getSession()->unsScopeObject();
|
14 |
+
$store = $helper->getStore();
|
15 |
+
|
16 |
+
$country = $store->getConfig('general/country/default');
|
17 |
+
$currency = $store->getConfig('currency/options/default');
|
18 |
+
$merchant_id = $helper->getConfig('merchant_id');
|
19 |
+
$service_id = $helper->getConfig('service_id');
|
20 |
+
$api_key = $helper->getConfig('api_security_key');
|
21 |
+
|
22 |
+
$settings_incomplete = empty($merchant_id) || empty($api_key) || empty($service_id);
|
23 |
+
$test = Mage::getSingleton('boku/test')->testConnection();
|
24 |
+
if (!$settings_incomplete){
|
25 |
+
$price_info = Mage::getSingleton('boku/prices')->fetchPrices($currency, $country, 99);
|
26 |
+
$prices = Mage::getSingleton('boku/prices')->fetchPrices($currency, $country);
|
27 |
+
}
|
28 |
+
?>
|
29 |
+
<div class="content-header">
|
30 |
+
<h3 class="icon-head"><?php echo $helper->__('Boku Settings') ?></h3>
|
31 |
+
</div>
|
32 |
+
<div class="entry-edit">
|
33 |
+
<b>Merchant ID: </b><?php echo $merchant_id; ?><br>
|
34 |
+
<b>Service ID: </b><?php echo $service_id; ?><br>
|
35 |
+
<b>API Security Key: </b><?php echo ($api_key ? 'Yes ('.strlen($api_key).' chars)' : 'No'); ?><br>
|
36 |
+
<b>Country: </b><?php echo $country; ?><br>
|
37 |
+
<b>Currency: </b><?php echo $currency; ?><br>
|
38 |
+
<b>Base Currency: </b><?php echo $helper->getBaseCurrencyCode(); ?><br>
|
39 |
+
<b>Boku pricelist URL: </b><?php echo $helper->getConfig('url/pricelist'); ?><br>
|
40 |
+
<b>Callback URL: </b><?php echo $helper->getCallbackUrl(); ?><br>
|
41 |
+
</div>
|
42 |
+
|
43 |
+
<div class="messages">
|
44 |
+
<div class="content-header">
|
45 |
+
<h3 class="icon-head"><?php echo $helper->__('Boku Connection Test') ?></h3>
|
46 |
+
</div>
|
47 |
+
<?php echo implode('<br>', $test); ?>
|
48 |
+
|
49 |
+
<?php if (!$settings_incomplete): ?>
|
50 |
+
<div class="content-header">
|
51 |
+
<h3 class="icon-head"><?php echo $helper->__('Boku Price Point Data') ?></h3>
|
52 |
+
</div>
|
53 |
+
<?php
|
54 |
+
if (empty($prices)){
|
55 |
+
echo $helper->__('No price data found...check your settings').'<br>';
|
56 |
+
echo $helper->__('Has your Boku service been approved by Boku ?');
|
57 |
+
}else{
|
58 |
+
echo '<pre>'.json_encode($price_info, JSON_PRETTY_PRINT).'</pre>';
|
59 |
+
echo '<pre>'.json_encode($prices, JSON_PRETTY_PRINT).'</pre>';
|
60 |
+
}
|
61 |
+
?>
|
62 |
+
<?php endif; ?>
|
63 |
+
</div>
|
app/design/frontend/base/default/layout/boku_paymentgateway.xml
ADDED
@@ -0,0 +1,37 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?xml version="1.0"?>
|
2 |
+
<!--
|
3 |
+
/**
|
4 |
+
* Boku payment layout
|
5 |
+
*
|
6 |
+
* @category Payment gateway
|
7 |
+
* @package boku_paymentgateway
|
8 |
+
* @copyright Copyright (c) Boku (http://www.boku.com/)
|
9 |
+
* @author MDH <mdh@treatid.me.uk>
|
10 |
+
*/
|
11 |
+
-->
|
12 |
+
<layout version="0.1.0">
|
13 |
+
<boku_standard_prepare>
|
14 |
+
<reference name="content">
|
15 |
+
<block type="boku/payment_standard_prepare" name="boku.prepare" template="boku/paymentgateway/standard/prepare.phtml" />
|
16 |
+
</reference>
|
17 |
+
</boku_standard_prepare>
|
18 |
+
|
19 |
+
<boku_standard_cancel>
|
20 |
+
<reference name="root">
|
21 |
+
<action method="setTemplate"><template>page/empty.phtml</template></action>
|
22 |
+
</reference>
|
23 |
+
<reference name="content">
|
24 |
+
<block type="boku/payment_standard_cancel" name="boku.cancel" template="boku/paymentgateway/standard/cancel.phtml" />
|
25 |
+
</reference>
|
26 |
+
</boku_standard_cancel>
|
27 |
+
|
28 |
+
<boku_standard_success>
|
29 |
+
<reference name="root">
|
30 |
+
<action method="setTemplate"><template>page/empty.phtml</template></action>
|
31 |
+
</reference>
|
32 |
+
<reference name="content">
|
33 |
+
<block type="boku/payment_standard_success" name="boku.success" template="boku/paymentgateway/standard/success.phtml" />
|
34 |
+
</reference>
|
35 |
+
</boku_standard_success>
|
36 |
+
|
37 |
+
</layout>
|
app/design/frontend/base/default/template/boku/paymentgateway/standard/cancel.phtml
ADDED
@@ -0,0 +1,13 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* After failed Boku buy-url submission (via Prepare block)
|
4 |
+
*
|
5 |
+
* @category Payment gateway
|
6 |
+
* @package boku_paymentgateway
|
7 |
+
* @copyright Copyright (c) Boku (http://www.boku.com/)
|
8 |
+
* @author MDH <mdh@treatid.me.uk>
|
9 |
+
*/
|
10 |
+
?>
|
11 |
+
<script type="text/javascript">
|
12 |
+
parent.location = "<?php echo $this->getRedirectUrl(); ?>";
|
13 |
+
</script>
|
app/design/frontend/base/default/template/boku/paymentgateway/standard/form.phtml
ADDED
@@ -0,0 +1,14 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* Payment Form
|
4 |
+
*
|
5 |
+
* @category Payment gateway
|
6 |
+
* @package boku_paymentgateway
|
7 |
+
* @copyright Copyright (c) Boku (http://www.boku.com/)
|
8 |
+
* @author MDH <mdh@treatid.me.uk>
|
9 |
+
*/
|
10 |
+
$helper = Mage::helper('boku');
|
11 |
+
$networks = $helper->getSession()->getNetworks();
|
12 |
+
if (is_array($networks)): ?>
|
13 |
+
<p><?php echo $helper->__('Available on these networks').': '.implode(', ', $networks); ?></p>
|
14 |
+
<?php endif; ?>
|
app/design/frontend/base/default/template/boku/paymentgateway/standard/prepare.phtml
ADDED
@@ -0,0 +1,12 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* Payment Gateway
|
4 |
+
*
|
5 |
+
* @category Payment gateway
|
6 |
+
* @package boku_paymentgateway
|
7 |
+
* @copyright Copyright (c) Boku (http://www.boku.com/)
|
8 |
+
* @author MDH <mdh@treatid.me.uk>
|
9 |
+
*/
|
10 |
+
?>
|
11 |
+
<iframe id="boku_prepare" style="width:600px;height:450px;margin:0;padding:0;border:none"
|
12 |
+
src="<?php echo $this->getBuyUrl(); ?>" />
|
app/design/frontend/base/default/template/boku/paymentgateway/standard/success.phtml
ADDED
@@ -0,0 +1,13 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* After successful Boku buy-url submission (via Prepare block)
|
4 |
+
*
|
5 |
+
* @category Payment gateway
|
6 |
+
* @package boku_paymentgateway
|
7 |
+
* @copyright Copyright (c) Boku (http://www.boku.com/)
|
8 |
+
* @author MDH <mdh@treatid.me.uk>
|
9 |
+
*/
|
10 |
+
?>
|
11 |
+
<script type="text/javascript">
|
12 |
+
parent.location = "<?php echo $this->getRedirectUrl(); ?>";
|
13 |
+
</script>
|
app/etc/modules/Boku_Paymentgateway.xml
ADDED
@@ -0,0 +1,22 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?xml version="1.0"?>
|
2 |
+
<!--
|
3 |
+
/**
|
4 |
+
* Magento module for the Boku Payment Gateway
|
5 |
+
*
|
6 |
+
* @category Payment gateway
|
7 |
+
* @package boku_paymentgateway
|
8 |
+
* @copyright Copyright (c) Boku (http://www.boku.com/)
|
9 |
+
* @author MDH <mdh@treatid.me.uk>
|
10 |
+
*/
|
11 |
+
-->
|
12 |
+
<config>
|
13 |
+
<modules>
|
14 |
+
<Boku_Paymentgateway>
|
15 |
+
<active>true</active>
|
16 |
+
<codePool>community</codePool>
|
17 |
+
<depends>
|
18 |
+
<Mage_Checkout/>
|
19 |
+
</depends>
|
20 |
+
</Boku_Paymentgateway>
|
21 |
+
</modules>
|
22 |
+
</config>
|
app/locale/en_US/Boku_Paymentgateway.csv
ADDED
@@ -0,0 +1,41 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
"Boku (Pay by Mobile)","Boku (Pay by Mobile)"
|
2 |
+
"Sign up for a Boku account","Sign up for an Boku account"
|
3 |
+
"Merchant ID","Merchant ID"
|
4 |
+
"This is your Boku Merchant ID.","This is your Boku Merchant ID."
|
5 |
+
"API Security Key","API Security Key"
|
6 |
+
"This is your Boku API security key<br> (stored as encrypted data).","This is your Boku API security key<br> (stored as encrypted data)."
|
7 |
+
"Service ID","Service ID"
|
8 |
+
"This is your Boku service id. (Not the service name)","This is your Boku service id. (Not the service name)"
|
9 |
+
"Sub Merchant Name","Sub Merchant Name"
|
10 |
+
"This appears as an identifier on the Boku payment panel.<br>If left blank then the panel uses the service name specified in your Boku account.","This appears as an identifier on the Boku payment panel.<br>If left blank then the panel uses the service name specified in your Boku account."
|
11 |
+
"Mode","Mode"
|
12 |
+
"Generate Invoices","Generate Invoices"
|
13 |
+
"If the payment process completes and the total paid matches the order total then should we generate an invoice ? This also sends the generated invoice to the customer (if possible).","If the payment process completes and the total paid matches the order total then should we generate an invoice ? This also sends the generated invoice to the customer (if possible)."
|
14 |
+
"Success Message","Success Message"
|
15 |
+
"Optional additional message for the payment success page.","Optional additional message for the payment success page."
|
16 |
+
"Enabled","Enabled"
|
17 |
+
"Standard Payment Settings","Standard Payment Settings"
|
18 |
+
"Title","Title"
|
19 |
+
"Payment from Applicable Countries","Payment from Applicable Countries"
|
20 |
+
"Payment from Specific Countries","Payment from Specific Countries"
|
21 |
+
"Minimum Order Total","Minimum Order Total"
|
22 |
+
"Maximum Order Total","Maximum Order Total"
|
23 |
+
"Minimum and Maximum totals will also be restricted by your Boku account settings.","Minimum and Maximum totals will also be restricted by your Boku account settings."
|
24 |
+
"Sort Order","Sort Order"
|
25 |
+
"Advanced Settings<br>You should <b>NOT</b> change these settings unless advised to by Boku.","Advanced Settings<br>You should <b>NOT</b> change these settings unless advised to by Boku."
|
26 |
+
"Callback URL","Callback URL"
|
27 |
+
"This is the url used by the Boku server to notify your server of transaction events.<br>Leave blank to use the default (e.g. <i>yourdomain</i>/boku/api), only specify if you require an unusual connection.<br>NOTE: The default value includes the store scope so you may need to be careful with a complex configuration.","This is the url used by the Boku server to notify your server of transaction events.<br>Leave blank to use the default (e.g. <i>yourdomain</i>/boku/api), only specify if you require an unusual connection.<br>NOTE: The default value includes the store scope so you may need to be careful with a complex configuration."
|
28 |
+
"Callback IPs","Callback IPs"
|
29 |
+
"For additional security you can specify a semi-colon delimited list of IP addresses allowed for callbacks. If blank then there are no restrictions.","For additional security you can specify a semi-colon delimited list of IP addresses allowed for callbacks. If blank then there are no restrictions."
|
30 |
+
"Pricelist URL","Pricelist URL"
|
31 |
+
"Prepare URL","Prepare URL"
|
32 |
+
"Test","Test"
|
33 |
+
"Live","Live"
|
34 |
+
"Failed to initiate the Boku payment transaction.","Failed to initiate the Boku payment transaction."
|
35 |
+
"item","item"
|
36 |
+
"items","items"
|
37 |
+
"Boku Settings","Boku Settings"
|
38 |
+
"Boku pricelist Data","Boku pricelist Data"
|
39 |
+
"No price data found...check your settings","No price data found...check your settings"
|
40 |
+
"Has your Boku service been approved by Boku ?","Has your Boku service been approved by Boku ?"
|
41 |
+
"Available on these networks","Available on these networks"
|
package.xml
ADDED
@@ -0,0 +1,21 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?xml version="1.0"?>
|
2 |
+
<package>
|
3 |
+
<name>Boku_Paymentgateway</name>
|
4 |
+
<version>0.0.4</version>
|
5 |
+
<stability>stable</stability>
|
6 |
+
<license uri="https://opensource.org/licenses/osl-3.0.php">Open Software License (OSL)</license>
|
7 |
+
<channel>community</channel>
|
8 |
+
<extends/>
|
9 |
+
<summary>This is a Payment Gateway integration for Boku (Pay by mobile).</summary>
|
10 |
+
<description>Provides the Boku (Pay by mobile) payment method as an alternative to Credit Card payments.
|
11 |
+
It is intended for relatively small financial transactions and it's suitability can be discussed with a Boku representative.
|
12 |
+
http://www.boku.com/.</description>
|
13 |
+
<notes>Testing has been done on Magento versions 1.7-1.9.
|
14 |
+
There is no overloading of any classes so there should be no impact on existing functionality.</notes>
|
15 |
+
<authors><author><name>Mark Davidson-Houston</name><user>treatid</user><email>mdh@treatid.me.uk</email></author></authors>
|
16 |
+
<date>2016-03-19</date>
|
17 |
+
<time>22:08:28</time>
|
18 |
+
<contents><target name="magecommunity"><dir name="Boku"><dir name="Paymentgateway"><dir name="Block"><dir name="Payment"><dir name="Standard"><file name="Cancel.php" hash="3239e1ed8b9b05bd56e2528e2fbd2853"/><file name="Form.php" hash="034ecded7255dc97cc9c15e730eb4a3c"/><file name="Prepare.php" hash="edd001f7cd541b9477044da5d52b1fc3"/><file name="Result.php" hash="816443798640ca5fb325c3d0b579bc1f"/><file name="Success.php" hash="090f9fca4e8975b881cb807a67ef0c82"/></dir></dir></dir><dir name="Helper"><file name="Data.php" hash="43b6873dad13c1d85cecd283da6c8dab"/></dir><dir name="Model"><file name="AdminSession.php" hash="ee941bc7aaa20d10bc583c3bfaf8d5b7"/><file name="Cron.php" hash="19139a3e09c1c56c8b714f602fb87d2e"/><dir name="Mapped"><file name="Abstract.php" hash="cb9da96cd61e0cbd5a49a0177384ae59"/></dir><dir name="Payment"><file name="Callback.php" hash="fda8ca4f8c2cb5a9f71d3dfeac30b0cd"/><file name="Chargeback.php" hash="bd9750a8a89a40212c35b75cac47e030"/><file name="Event.php" hash="622313f71fcef556b0065152caed6c40"/><file name="Standard.php" hash="6f3f3cbf2f812ec8348467ca659296e1"/><file name="Transaction.php" hash="aed115b0380de5180887b8d699342d35"/></dir><file name="Prices.php" hash="a84f428964d6fc981d65b33cde022ecc"/><dir name="Resource"><dir name="Payment"><dir name="Callback"><file name="Collection.php" hash="9416f5d34cb0946fbba370562ae59727"/></dir><file name="Callback.php" hash="d78c969ce9e18d08e0edc059576bf2d1"/><dir name="Chargeback"><file name="Collection.php" hash="b9c0d89186e3b28cf528e2a9faff5b08"/></dir><file name="Chargeback.php" hash="27424fac6667df3f7989ebe5183b8337"/><dir name="Event"><file name="Collection.php" hash="de2af9ceb3bb5cb9079549d524dedd69"/></dir><file name="Event.php" hash="b876fb5589368a426edccfeac316706a"/><dir name="Transaction"><file name="Collection.php" hash="ff7f877badceb80d455a6a82a551207b"/></dir><file name="Transaction.php" hash="568d8a2197f90dea5d9e11621b8a210b"/></dir><file name="Setup.php" hash="49630e76b6e64a34856fd2aa5c650bd5"/></dir><file name="Session.php" hash="f4283f7b08b5feededd8a4cfca893ba8"/><dir name="System"><file name="Config.php" hash="abb420605c5814438b78d291aa41a892"/></dir><file name="Test.php" hash="b477546758d16fe32ad92ec8b72b01ae"/><file name="Xml.php" hash="e156f0e765838481d72d1bd93fbc8ce6"/></dir><dir name="controllers"><dir name="Adminhtml"><file name="BokuController.php" hash="11ae870c022a209f674e545b273ec659"/></dir><file name="ApiController.php" hash="85bc4ef426623fdd520976346419039a"/><file name="StandardController.php" hash="ee14a29f973af13ce0733489329f57e2"/></dir><dir name="etc"><file name="adminhtml.xml" hash="22b6f09956654014d4648cc02e73b256"/><file name="config.xml" hash="7b3b40f87dab7fcb35064eb73cd5ce8b"/><file name="system.xml" hash="0d1420ad968616cd3a0e2bcf81318e7d"/></dir><dir name="sql"><dir name="boku_setup"><file name="install-0.0.1.php" hash="bcaeb258769e0271b07fc483dcbcdb28"/><file name="upgrade-0.0.1-0.0.2.php" hash="e76438e5770e270cf69e4ba9c7c0c05e"/></dir></dir></dir></dir></target><target name="mageetc"><dir name="modules"><file name="Boku_Paymentgateway.xml" hash="ddef7a495e147af1b1333065e9d528d4"/></dir></target><target name="magedesign"><dir name="adminhtml"><dir name="default"><dir name="default"><dir name="layout"><file name="boku_paymentgateway.xml" hash="9e042d0306a5f69c1ae014e16d2498a9"/></dir><dir name="template"><dir name="boku"><dir name="paymentgateway"><file name="test.phtml" hash="c5fa68eefcac6c160e93ab8f496fe78d"/></dir></dir></dir></dir></dir></dir><dir name="frontend"><dir name="base"><dir name="default"><dir name="layout"><file name="boku_paymentgateway.xml" hash="21f632989147b0bcf2a17ed1a13575da"/></dir><dir name="template"><dir name="boku"><dir name="paymentgateway"><dir name="standard"><file name="cancel.phtml" hash="90dc0bbfa12e977150c77994440536dd"/><file name="form.phtml" hash="565c378840a33582e7be59abb611fcc2"/><file name="prepare.phtml" hash="9f936df5479b0c2ea103db50e4986df4"/><file name="success.phtml" hash="826effa3f1f5b1cdca8eb59efb459b42"/></dir></dir></dir></dir></dir></dir></dir></target><target name="magelocale"><dir><dir name="en_US"><file name="Boku_Paymentgateway.csv" hash="c67b2f4f77ce9d707c3530883b96eaf0"/></dir></dir></target></contents>
|
19 |
+
<compatible/>
|
20 |
+
<dependencies><required><php><min>5.4.0</min><max>7.0.3</max></php></required></dependencies>
|
21 |
+
</package>
|