Last active
July 25, 2020 12:16
-
-
Save sahyung/25680049eb2c601294231c996da15b58 to your computer and use it in GitHub Desktop.
Payment adapter custom for Boxbilling using Paylane gateway
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <?php | |
| /** | |
| * filepath: __DIR__/bb-library/Payment/Adapter/Paylane.php | |
| */ | |
| class Payment_Adapter_Paylane implements \Box\InjectionAwareInterface | |
| { | |
| private $config = array(); | |
| protected $di; | |
| public function setDi($di) | |
| { | |
| $this->di = $di; | |
| } | |
| public function getDi() | |
| { | |
| return $this->di; | |
| } | |
| public function __construct($config) | |
| { | |
| if(!function_exists('curl_exec')) { | |
| throw new Payment_Exception('PHP Curl extension not enabled'); | |
| } | |
| if(!isset($this->config['merchant_id'])) { | |
| throw new Payment_Exception('Payment gateway "PayLane" is not configured properly. Please update configuration parameter "PayLane Merchant Id" at "Configuration -> Payments".'); | |
| } | |
| if(!isset($this->config['salt'])) { | |
| throw new Payment_Exception('Payment gateway "PayLane" is not configured properly. Please update configuration parameter "PayLane Has Salt" at "Configuration -> Payments".'); | |
| } | |
| if (!isset($config['test_mode'])) $config['test_mode'] = false; | |
| $this->config = $config; | |
| } | |
| public static function getConfig() | |
| { | |
| return array( | |
| 'can_load_in_iframe' => true, | |
| 'supports_one_time_payments' => true, | |
| 'supports_subscriptions' => false, | |
| 'description' => 'Enter your Paylane data to start accepting payments by Paylane.', | |
| 'form' => array( | |
| 'merchant_id' => array('text', array( | |
| 'label' => 'Paylane Merchant ID', | |
| ), | |
| ), | |
| 'salt' => array('text', array( | |
| 'label' => 'Paylane Hash salt', | |
| ), | |
| ), | |
| ), | |
| ); | |
| } | |
| /** | |
| * Generate payment text | |
| * | |
| * @param Api_Admin $api_admin | |
| * @param int $invoice_id | |
| * @param bool $subscription | |
| * | |
| * @since BoxBilling v2.9.15 | |
| * | |
| * @return string - html form with auto submit javascript | |
| */ | |
| public function getHtml($api_admin, $invoice_id, $subscription) | |
| { | |
| $invoice = $api_admin->invoice_get(array('id'=>$invoice_id)); | |
| if($subscription) { | |
| $data = $this->getSubscriptionFields($invoice); | |
| } else { | |
| $data = $this->getOneTimePaymentFields($invoice); | |
| } | |
| $url = $this->serviceUrl(); | |
| return $this->_generateForm($url, $data); | |
| } | |
| public function processTransaction($api_admin, $id, $data, $gateway_id) | |
| { | |
| $ipn = $data['post']; | |
| if($this->config['test_mode']) { | |
| return json_encode($ipn); | |
| } | |
| if ($this->isIpnDuplicate($ipn)){ | |
| throw new Payment_Exception('IPN is duplicate'); | |
| } | |
| $tx = $api_admin->invoice_transaction_get(array('id'=>$id)); | |
| if(!$tx['invoice_id']) { | |
| $api_admin->invoice_transaction_update(array('id'=>$id, 'invoice_id'=>$data['get']['bb_invoice_id'])); | |
| } | |
| if(!$tx['txn_id'] && isset($ipn['id_sale'])) { | |
| $api_admin->invoice_transaction_update(array('id'=>$id, 'txn_id'=>$ipn['id_sale'])); | |
| } | |
| if(!$tx['txn_status'] && isset($ipn['status'])) { | |
| $api_admin->invoice_transaction_update(array('id'=>$id, 'txn_status'=>$ipn['status'])); | |
| } | |
| if(!$tx['amount'] && isset($ipn['amount'])) { | |
| $api_admin->invoice_transaction_update(array('id'=>$id, 'amount'=>$ipn['amount'])); | |
| } | |
| if(!$tx['currency'] && isset($ipn['currency'])) { | |
| $api_admin->invoice_transaction_update(array('id'=>$id, 'currency'=>$ipn['currency'])); | |
| } | |
| $invoice = $api_admin->invoice_get(array('id'=>$data['get']['bb_invoice_id'])); | |
| $client_id = $invoice['client']['id']; | |
| if($ipn['status'] == 'PERFORMED') { | |
| $bd = array( | |
| 'id' => $client_id, | |
| 'amount' => $ipn['amount'], | |
| 'description' => 'Paylane transaction '.$ipn['id_sale'], | |
| 'type' => 'Paylane', | |
| 'rel_id' => $ipn['id_sale'], | |
| ); | |
| $api_admin->client_balance_add_funds($bd); | |
| if($tx['invoice_id']) { | |
| $api_admin->invoice_pay_with_credits(array('id'=>$tx['invoice_id'])); | |
| } | |
| $api_admin->invoice_batch_pay_with_credits(array('client_id'=>$client_id)); | |
| } | |
| $d = array( | |
| 'id' => $id, | |
| 'error' => '', | |
| 'error_code'=> '', | |
| 'status' => 'processed', | |
| 'updated_at'=> date('Y-m-d H:i:s'), | |
| ); | |
| $api_admin->invoice_transaction_update($d); | |
| header("Location: ". $this->config['return_url']); | |
| exit; | |
| } | |
| public function isIpnDuplicate(array $ipn) | |
| { | |
| $sql = 'SELECT id | |
| FROM transaction | |
| WHERE txn_id = :transaction_id | |
| AND txn_status = :transaction_status | |
| AND amount = :transaction_amount | |
| LIMIT 2'; | |
| $bindings = array( | |
| ':transaction_id' => $ipn['ik_trn_id'], | |
| ':transaction_status' => $ipn['ik_inv_st'], | |
| ':transaction_amount' => $ipn['ik_am'], | |
| ); | |
| $rows = $this->di['db']->getAll($sql, $bindings); | |
| if (count($rows) > 1){ | |
| return true; | |
| } | |
| return false; | |
| } | |
| public function getInvoiceItemDescription(array $invoice) | |
| { | |
| $desc = ''; | |
| if (sizeof($invoice['lines']) > 0) { | |
| $desc = $invoice['lines'][0]['description']; | |
| for ($i=1; $i < sizeof($invoice['lines']); $i++) { | |
| $desc .= ", " . $invoice['lines'][$i]['description']; | |
| } | |
| } | |
| return substr($desc, 0, 10000); | |
| } | |
| /** | |
| * @see https://devzone.paylane.com/secure-form-guide/implementation/ | |
| */ | |
| public function getOneTimePaymentFields(array $invoice) | |
| { | |
| $data = array(); | |
| $data['amount'] = $this->moneyFormat($invoice['total'], $invoice['currency']); // Regular subscription price. | |
| $data['currency'] = $invoice['currency']; | |
| $data['merchant_id'] = $this->config["merchant_id"]; | |
| $data['description'] = substr($invoice['title'], 0, 20); | |
| $data['transaction_description'] = $this->getInvoiceItemDescription($invoice); | |
| $data['transaction_type'] = "S"; | |
| $data['back_url'] = $this->config['notify_url']; | |
| $data['language'] = "en"; | |
| $data['hash'] = $this->setHash($data); | |
| } | |
| public function getSubscriptionFields(array $invoice) | |
| { | |
| throw new Payment_Exception('Not implemented yet'); | |
| } | |
| /** | |
| * @param string $url | |
| */ | |
| private function _generateForm($url, $data, $method = 'post') | |
| { | |
| $form = ''; | |
| $form .= '<form name="payment_form" action="'.$url.'" method="'.$method.'">' . PHP_EOL; | |
| foreach($data as $key => $value) { | |
| $form .= sprintf('<input type="hidden" name="%s" value="%s" />', $key, $value) . PHP_EOL; | |
| } | |
| $form .= '<input class="bb-button bb-button-submit" type="submit" value="Pay with PayLane" id="payment_button"/>'. PHP_EOL; | |
| $form .= '</form>' . PHP_EOL . PHP_EOL; | |
| if(isset($this->config['auto_redirect']) && $this->config['auto_redirect']) { | |
| $form .= sprintf('<h2>%s</h2>', __('Redirecting to PayLane.com')); | |
| $form .= "<script type='text/javascript'>$(document).ready(function(){ document.getElementById('payment_button').style.display = 'none'; document.forms['payment_form'].submit();});</script>"; | |
| } | |
| return $form; | |
| } | |
| private function setHash($data) | |
| { | |
| $array = array( | |
| $this->config["salt"], | |
| $data['description'], | |
| $data['amount'], | |
| $data['currency'], | |
| "S" | |
| ); | |
| $string = implode("|", $array); | |
| return SHA1($string); | |
| } | |
| private function moneyFormat($amount, $currency) | |
| { | |
| //HUF currency do not accept decimal values | |
| if($currency == 'HUF') { | |
| return number_format($amount, 0); | |
| } | |
| return number_format($amount, 2, '.', ''); | |
| } | |
| private function serviceUrl() | |
| { | |
| return 'https://secure.paylane.com/order/cart.html'; | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment