Заказчик пожелал интегрировать некий свой сервис с платежной системой QIWI.
Поскольку для добавления своей кнопки в их терминал сервис явно не дотягивал, решено было использовать именной QIWI кошелек(это который не привязывается к номеру мобильного телефона).
Поскольку на тот момент я изучал фреймворк Yii, то первым делом решено было поискать готовое расширение. Ну а поскольку поиски не дали результатов, было решено написать свое.
Изучив все возможности взаимодействия, предоставляемые сервисом, а именно: HTTP-протокол, XML-протокол и SOAP-протокол (термины сервиса QIWI), был выбран SOAP, как наиболее удобный.
Подробнее о SOAP-сервисе QIWI вы можете прочесть в этом документе.
Хочу заметить, что это мой первый опыт написания расширений для Yii.
Под катом вы найдете исходный код самого модуля (без запчастей от QIWI, см. ссылки внизу статьи).
ext.ishop.Ishop.php
Пример выставления счета пользователю:
Документация по SOAP-сервису QIWI
Пример использования на php (на его основе собственно и сделано расширение)
Yii расширение для работы с сервисом QIWI(полный рабочий комплект с wsdl-файлами)
Поскольку для добавления своей кнопки в их терминал сервис явно не дотягивал, решено было использовать именной QIWI кошелек(это который не привязывается к номеру мобильного телефона).
Поскольку на тот момент я изучал фреймворк Yii, то первым делом решено было поискать готовое расширение. Ну а поскольку поиски не дали результатов, было решено написать свое.
Изучив все возможности взаимодействия, предоставляемые сервисом, а именно: HTTP-протокол, XML-протокол и SOAP-протокол (термины сервиса QIWI), был выбран SOAP, как наиболее удобный.
Подробнее о SOAP-сервисе QIWI вы можете прочесть в этом документе.
Хочу заметить, что это мой первый опыт написания расширений для Yii.
Под катом вы найдете исходный код самого модуля (без запчастей от QIWI, см. ссылки внизу статьи).
ext.ishop.Ishop.php
<?php
/**
* Yii Extension to work with a payment system QIWI.
* This extension allows you to interact with the service QIWI over SOAP.
*
* <p>The following functions:</p>
* <ul>
* <li>Creating an account.</li>
* <li>Cancel the account.</li>
* <li>Checking account status.</li>
* </ul>
*
* CONFIGRATION
* <code>
* 'components' => array(
* 'ishop' => array(
* 'class' => 'ext.ishop.IShop',
* 'options' => array(
* 'login' => LOGIN,
* 'password' => PASSWORD
* )
* )
* ),
* <code>
*
* <p>TERMINATION CODES</p>
* <ul>
* <li>0 Success</li>
* <li>13 Server is busy, please repeat your request later</li>
* <li>150 Authorization error (wrong login/password)</li>
* <li>215 Bill with this txn-id already exists</li>
* <li>278 Bill list maximum time range exceeded</li>
* <li>298 No such agent in the system</li>
* <li>300 Unknown error</li>
* <li>330 Encryption error</li>
* <li>370 Maximum allowed concurrent requests overlimit</li>
* </ul>
*
* <p>STATUSES REFERENCE</p>
* <ul>
* <li>50 Made</li>
* <li>52 Processing</li>
* <li>60 Payed</li>
* <li>150 Cancelled (Machine error)</li>
* <li>160 Cancelled</li>
* <li>161 Cancelled (Timeout)</li>
* </ul>
*
*
* @author nek
* @package IShop
* @example example/example.php
* @see http://ishop.qiwi.ru
* @see https://ishop.qiwi.ru/docs/OnlineStoresProtocols_SOAP_EN.pdf
*/
class IShop extends CApplicationComponent {
/**
* Shop login (ID)
* @var integer
*/
public $login;
/**
* Shop password
* @var string
*/
public $password;
/**
* Path to the wsdl document
* @var string
*/
public $wsdlPath;
public $options = array();
protected $validOptions = array(
'login' => array('type' => 'integer'),
'password' => array('type' => 'string'),
'wsdlPath' => array('type' => 'string'),
);
protected static function checkOptions($value, $validOptions) {
if (!empty($validOptions)) {
foreach ($value as $key=>$val) {
if (!array_key_exists($key, $validOptions)) {
throw new CException(Yii::t('IShop', '{k} is not a valid option', array('{k}'=>$key)));
}
$type = gettype($val);
if ((!is_array($validOptions[$key]['type']) && ($type != $validOptions[$key]['type'])) || (is_array($validOptions[$key]['type']) && !in_array($type, $validOptions[$key]['type']))) {
throw new CException(Yii::t('IShop', '{k} must be of type {t}',
array('{k}'=>$key,'{t}'=>$validOptions[$key]['type'])));
}
if (($type == 'array') && array_key_exists('elements', $validOptions[$key])) {
self::checkOptions($val, $validOptions[$key]['elements']);
}
}
}
}
protected function defaults() {
!isset($this->options['login']) ? $this->login = '' : $this->login = $this->options['login'];
!isset($this->options['password']) ? $this->password = '' : $this->password = $this->options['password'];
!isset($this->options['wsdlPath']) ? $this->wsdlPath = Yii::getPathOfAlias('ext.ishop.vendor') : $this->wsdlPath = $this->options['wsdlPath'];
}
public function init() {
if (!extension_loaded('soap')) {
throw new CException( Yii::t('Soap', 'You must have SOAP enabled in order to use this extension.') );
} else {
self::checkOptions($this->options, $this->validOptions);
$this->defaults();
}
}
/**
* Creating a bill
*
* @param string $user – user ID (MSISDN)
* @param float $amount – amount of bill
* @param string $comment – comment to the bill displayed to the user
* @param string $txn – unique bill ID
* @param boolean $create – flag to create a new user (if he’s not registered in the system yet)
* @throws CException
* @return number
*/
public function createBill( $user, $amount, $comment, $txn, $create = true ) {
if (strlen($txn) > 30) {
throw new CException(Yii::t('IShop', 'Row size can not exceed 30 bytes.'));
}
//
$service = $this->setService();
$params = new createBill();
$params->login = $this->login;
$params->password = $this->password;
$params->user = $user;
$params->amount = $amount;
$params->comment = $comment;
$params->lifetime = date('d.m.Y H:i:s', strtotime('+1 day ago'));
$params->txn = $txn;
$res = $service->createBill($params);
return (integer) $res;
}
/**
* Cancel a bill
*
* @param string $txn – unique bill ID
* @throws CException
* @return number
*/
public function cancelBill( $txn ) {
if (strlen($txn) > 30) {
throw new CException(Yii::t('IShop', 'Row size can not exceed 30 bytes.'));
}
$service = $this->setService();
$params = new cancelBill();
$params->login = $this->login;
$params->password = $this->password;
$params->txn = $txn;
$res = $service->cancelBill($params);
$return = $res->cancelBillResult;
return (integer) $return;
}
/**
* Check bill status
*
* @param string $txn – unique bill ID
* @throws CException
* @return number
*/
public function checkBill( $txn ) {
if (strlen($txn) > 30) {
throw new CException(Yii::t('IShop', 'Row size can not exceed 30 bytes.'));
}
$service = $this->setService();
$params = new checkBill();
$params->login = $this->login;
$params->password = $this->password;
$params->txn = $txn;
$res = $service->checkBill($params);
$return = $res;
return (integer) $return;
}
/**
* Update bill status
*
* @param integer $status - bill status
*/
public function updateBill( $status = 0 ) {
$server = $this->setServer();
$params = new IShopServer();
$params->updateBill($status);
return;
}
private function setService() {
Yii::import('ext.ishop.vendor.IShopServerWSService');
$service = new IShopServerWSService($this->wsdlPath.'/IShopServerWS.wsdl',array(
'location' => 'https://ishop.qiwi.ru/services/ishop',
'trace' => 1
));
return $service;
}
private function setServer() {
Yii::import('ext.ishop.vendor.IShopServer');
$server = new SoapServer($this->wsdlPath.'/IShopClientWS.wsdl', array(
'classmap' => array(
'tns:updateBill' => 'Param',
'tns:updateBillResponse' => 'Response'
)
));
$server->setClass('IShopServer');
$server->handle();
}
}
Пример выставления счета пользователю:
$user = 9181234567;
$amount = 100;
$coment = 'Test pay';
$txn = 123;
$return = Yii::app()->ishop->createBill($user, $amount, $comment, $txn);
echo $return;
Документация по SOAP-сервису QIWI
Пример использования на php (на его основе собственно и сделано расширение)
Yii расширение для работы с сервисом QIWI(полный рабочий комплект с wsdl-файлами)