Version: current

      1 <?php
      2
      3 // Способ оплаты через Яндекс.Деньги
      4 class YaMoneyPayment extends PaymentMethod {
      5     static $db = array(
      6         'TestMode' => 'Boolean',
      7         'Password' => 'Varchar(150)',
      8         'ShopID' => 'Varchar',
      9         'SCID' => 'Varchar', //Номер витрины Контрагента, выдается Оператором.
     10         'BaseURL' => 'Varchar(100)',
     11
     12     //  'UsePKCS7' => 'Boolean', // ИСпользовать ли протокол PKCS#7 (применяется при невозмодности использования https)
     13         'ConnectionType' => "Enum('HTTPS, PKCS7, EMAIL')",
     14
     15         'TestPassword' => 'Varchar(150)',
     16         'TestShopID' => 'Varchar',
     17         'TestSCID' => 'Varchar', //Номер витрины Контрагента, выдается Оператором.
     18         'TestBaseURL' => 'Varchar(100)',
     19
     20         'PaymentType' => "Enum('PC, AC, MC, GP, WM, SB, MP, AB')",  //наверно нужно не так, в админке список всех возможных типов и галочки для выбора подключенных типов для данного клиента
     21
     22         'TaxSystem' => "Enum('1, 2, 3, 4, 5, 6')", //Система налогообложения магазина (СНО)
     23
     24         'PaymentSubject' => 'Varchar', //ПРИЗНАК ПРЕДМЕТА РАСЧЕТА
     25         'PaymentMode' => 'Varchar', //ПРИЗНАК СПОСОБА РАСЧЕТА
     26     );
     27
     28     protected static $cert_file_path = '/cart_payment/pem/payment_center_2016.cer';
     29     protected static $CA_file_path = '/cart_payment/pem/yamoney_center_2014.pem';
     30
     31     static function set_cert_file_path($path) {
     32         self::$cert_file_path = $path;
     33     }
     34
     35     static function get_cert_file_path() {
     36         return Director::baseFolder() . self::$cert_file_path;
     37     }
     38
     39     static function set_CA_file_path($path) {
     40         self::$cert_file_path = $path;
     41     }
     42
     43     static function get_CA_file_path() {
     44         return Director::baseFolder() . self::$CA_file_path;
     45     }
     46
     47     static $paymentMethodIcons = array(
     48         'cart_payment/img/yandex/YaPayment_AC.png',
     49         'cart_payment/img/yandex/YaPayment_MC.png',
     50         'cart_payment/img/yandex/YaPayment_PC.png',
     51         'cart_payment/img/yandex/YaPayment_SB.png',
     52         'cart_payment/img/yandex/YaPayment_WM.png',
     53         'cart_payment/img/yandex/YaPayment_GP.png',
     54     );
     55
     56     static $defaults = array(
     57         'BaseURL' => 'https://money.yandex.ru/eshop.xml',
     58         'TestBaseURL' => 'https://demomoney.yandex.ru/eshop.xml',
     59         'PaymentType' => 'PC',
     60     );
     61
     62     static $payment_subject = array(
     63         'commodity' => 'Товар',
     64         'excise' => 'Подакцизный товар',
     65         'job' => 'Работа',
     66         'service' => 'Услуга',
     67         'gambling_bet' => 'Ставка в азартной игре',
     68         'gambling_prize' => 'Выигрыш в азартной игре',
     69         'lottery' => 'Лотерейный билет',
     70         'lottery_prize' => 'Выигрыш в лотерею',
     71         'intellectual_activity' => 'Результаты интеллектуальной деятельности',
     72         'payment' => 'Платеж',
     73         'agent_commission' => 'Агентское вознаграждение',
     74         'composite' => 'Несколько вариантов',
     75         'another' => 'Другое',
     76     );
     77
     78     static $payment_mode = array(
     79         'full_prepayment' => 'Полная предоплата',
     80         'partial_prepayment' => 'Частичная предоплата',
     81         'advance' => 'Аванс',
     82         'full_payment' => 'Полный расчет',
     83         'partial_payment' => 'Частичный расчет и кредит',
     84         'credit' => 'Кредит',
     85         'credit_payment' => 'Выплата по кредиту',
     86     );
     87
     88 /*
     89     // нужно чтобе пользователь в форме оплаты выбрал подходящий способ оплаты
     90     static $paymentTypes = array('PC', 'AC', 'MC', 'GP', 'WM', 'SB', 'MP', 'AB');
     91 */
     92     /*
     93      * Возвращаем созданный способ оплаты через Я.Кассу
     94      *
     95      * @return DataObject
     96      */
     97     static function getPaymentMethod() {
     98         return DataObject::get_one('YaMoneyPayment', 'Active = 1');
     99     }
    100
    101     // Разбираем пришедший от Яндекса orderNumber и получаем из него ID платежа
    102     static function parse_orderID($orderID) {
    103         if (strpos($orderID, '-')) {
    104             $data = explode('-', $orderID);
    105             return (int)$data[1];
    106         }
    107         return (int)$orderID;
    108     }
    109
    110     function onBeforeWrite() {
    111         parent::onBeforeWrite();
    112         if (!$this->ID || $this->isChanged('PaymentType')) {
    113             $this->Title = _t('YaMoneyPayment.db_' . $this->PaymentType);
    114         }
    115     }
    116
    117     function getPaymentTypes() {
    118         $rs = array();
    119         foreach($this->dbObject('PaymentType')->enumValues() as $type) {
    120             $rs[$type] = _t('YaMoneyPayment.db_' . $type, $type);
    121         }
    122         return $rs;
    123     }
    124
    125     function getConnectionTypes() {
    126         $rs = array();
    127         foreach($this->dbObject('ConnectionType')->enumValues() as $type) {
    128             $rs[$type] = _t('YaMoneyPayment.type_' . $type, $type);
    129         }
    130         return $rs;
    131     }
    132
    133     function getTaxSystems() {
    134         $rs = array();
    135         foreach($this->dbObject('TaxSystem')->enumValues() as $type) {
    136             $rs[$type] = _t('YaMoneyPayment.TaxSystem_' . $type, $type);
    137         }
    138         return $rs;
    139     }
    140
    141     function getPaymentHandler() {
    142         return 'YaMoneyPayment_Handler';
    143     }
    144
    145     function getCMSFields() {
    146         $fields = parent::getCMSFields();
    147         $fields->findOrMakeTab('Root.Settings', _t('PaymentMethod.tab_Settings','Settings'));
    148
    149         $fields->addFieldToTab('Root.Settings', new DropdownField('PaymentType', $this->fieldLabel('PaymentType'), $this->getPaymentTypes()));
    150         $fields->addFieldToTab('Root.Settings', new DropdownField('ConnectionType', $this->fieldLabel('ConnectionType'), $this->getConnectionTypes()));
    151         $fields->addFieldToTab('Root.Settings', new DropdownField('TaxSystem', $this->fieldLabel('TaxSystem'), $this->getTaxSystems()));
    152
    153         $fields->addFieldToTab('Root.Settings', new DropdownField('PaymentSubject', $this->fieldLabel('PaymentSubject'), self::$payment_subject, "", null, _t('YaMoneyPayment.Select')));
    154         $fields->addFieldToTab('Root.Settings', new DropdownField('PaymentMode', $this->fieldLabel('PaymentMode'), self::$payment_mode, "", null, _t('YaMoneyPayment.Select')));
    155
    156
    157         $fields->addFieldToTab('Root.Settings', new HeaderField('WorkSettings', _t('PaymentMethod.WorkSettings', 'Work Settings')));
    158         $fields->addFieldToTab('Root.Settings', $fields->dataFieldByName('Password'));
    159         $fields->addFieldToTab('Root.Settings', $fields->dataFieldByName('ShopID'));
    160         $fields->addFieldToTab('Root.Settings', $fields->dataFieldByName('SCID'));
    161         $fields->addFieldToTab('Root.Settings', $fields->dataFieldByName('BaseURL'));
    162
    163         $fields->addFieldToTab('Root.Settings', new HeaderField('TestSettings', _t('PaymentMethod.TestSettings', 'Test Settings')));
    164         $fields->addFieldToTab('Root.Settings', $fields->dataFieldByName('TestPassword'));
    165         $fields->addFieldToTab('Root.Settings', $fields->dataFieldByName('TestShopID'));
    166         $fields->addFieldToTab('Root.Settings', $fields->dataFieldByName('TestSCID'));
    167         $fields->addFieldToTab('Root.Settings', $fields->dataFieldByName('TestBaseURL'));
    168
    169         return $fields;
    170     }
    171
    172     /* Пока комментим - как-то неудобно !!
    173     public function validate() {
    174         if ($this->Active) {
    175             //if (!$this->Login)
    176                 //return new ValidationResult(false, _t('YaMoneyPayment.WrongLogin', 'Wrong Login'));
    177             if (!$this->Password)
    178                 return new ValidationResult(false, _t('YaMoneyPayment.WrongPassword', 'Wrong Password'));
    179             if (!$this->ShopID)
    180                 return new ValidationResult(false, _t('YaMoneyPayment.WrongShopID', 'Wrong ShopID'));
    181             if (!$this->SCID)
    182                 return new ValidationResult(false, _t('YaMoneyPayment.WrongSCID', 'Wrong SCID'));
    183             if (!$this->BaseURL)
    184                 return new ValidationResult(false, _t('YaMoneyPayment.WrongBaseURL', 'Wrong BaseURL'));
    185         }
    186         if ($this->TestMode) {
    187             //if (!$this->TestLogin)
    188                 //return new ValidationResult(false, _t('YaMoneyPayment.WrongTestLogin', 'Wrong Test Login'));
    189             if (!$this->TestPassword)
    190                 return new ValidationResult(false, _t('YaMoneyPayment.WrongTestPassword', 'Wrong Test Password'));
    191             if (!$this->TestShopID)
    192                 return new ValidationResult(false, _t('YaMoneyPayment.WrongTestShopID', 'Wrong Test ShopID'));
    193             if (!$this->TestSCID)
    194                 return new ValidationResult(false, _t('YaMoneyPayment.WrongSCID', 'Wrong SCID'));
    195             if (!$this->TestBaseURL)
    196                 return new ValidationResult(false, _t('YaMoneyPayment.WrongTestBaseURL', 'Wrong Test BaseURL'));
    197         }
    198         return new ValidationResult();
    199     }
    200     */
    201
    202     function Password() {
    203         return ($this->TestMode) ? $this->TestPassword : $this->Password;
    204     }
    205
    206     function ShopID() {
    207         return ($this->TestMode) ? $this->TestShopID : $this->ShopID;
    208     }
    209
    210     function SCID() {
    211         return ($this->TestMode) ? $this->TestSCID : $this->SCID;
    212     }
    213
    214     function BaseURL() {
    215         return ($this->TestMode) ? $this->TestBaseURL : $this->BaseURL;
    216     }
    217
    218     // можно вызвать повторно, у уже сформированного платежа (отправить пользователю на почту)
    219     function processPayment($payment) {
    220         if ($payment->Status != 'Failure' && $payment->Status != 'Success') {
    221             $payment->Status = 'Pending';
    222             $payment->write();
    223             //$link = $this->selectPaymentTypeLink($payment->ID);
    224             $link = $this->paymentLink($payment->ID);
    225             //return new Payment_Processing($this->getForm($payment));
    226             return new Payment_Processing($link);
    227         } else {
    228             // ??? как-то ругаемся, что нельзя обработать уже обработанный платеж (успешно или с ошибкой)
    229         }
    230     }
    231
    232     // "чистая" ссылка (URL) на оплату
    233     function getClearPaymentLink($payment) {
    234         return Director::absoluteURL(YaMoneyPayment_Handler::payment_link($payment->HashLink));
    235     }
    236
    237     /*
    238      * Форма оплаты Яндекс.Деньги
    239      *
    240      * @return Form
    241      */
    242     function getForm($payment) {
    243         if (!$payment->PaidObject())
    244             return false;
    245 //      $orderCost = $payment->PaidObject()->GrandTotal;
    246
    247         // берем не общую сумму заказа, а размер конкретного платежа. По умолчанию они совпадают, но администратор может поменять размер платежа для частичной оплаты заказа (напр. бронирование)
    248         $orderCost = $payment->Amount;
    249         $successURL = Director::absoluteURL(YaMoneyPayment_Handler::success_link());
    250         $errorURL = Director::absoluteURL(YaMoneyPayment_Handler::error_link());
    251         $html = '<form id="PaymentForm" action="'.$this->BaseURL().'" method="post" enctype="application/x-www-form-urlencoded">';
    252         $html .= '<input type="hidden" name="shopId" value="'.$this->ShopID().'" />';
    253         $html .= '<input type="hidden" name="scid" value="'.$this->SCID().'" />';
    254         $html .= '<input type="hidden" name="sum" value="'.$orderCost.'" />';
    255         $html .= '<input type="hidden" name="customerNumber" value="order_'.$payment->PaidForID.'" />'; //используем составной ID - order_OrderID
    256
    257         //!!!Обязательное поле!!!  пока непонятно (Идентификатор плательщика в ИС Контрагента. В качестве идентификатора может использоваться номер договора плательщика, логин плательщика и т. п. Возможна повторная оплата по одному и тому же идентификатору плательщика.)
    258         /*
    259         $payments = new DataObjectSet();
    260         foreach($this->getPaymentTypes() as $type=>$caption) {
    261             $tPayment = new DataObject();
    262             $tPayment->Type = $type;
    263             $tPayment->Caption = $caption;
    264             $path = 'cart_payment/img/yandex/YaPayment_' . $type . '.png';
    265
    266             $icon = new Image_Cached($path);
    267
    268             $tPayment->Icon = $icon;
    269             //$html .= '<input type="radio" name="paymentType" value="'.$type.'" id="'.$type.'">';
    270             //$html .= '<label for="'.$type.'">'.$caption.'</label><br>';
    271             $payments->push($tPayment);
    272
    273         }
    274         */
    275         //debug::show($payments);
    276
    277         $html .= '<input name="paymentType" value="'.$payment->PaymentType()->PaymentType.'" type="hidden"/>';
    278         $html .= '<input name="orderNumber" value="'.$payment->PaidForID.'-'.$payment->ID.'" type="hidden"/>';
    279
    280         // используем онлайн-кассы?
    281         if ($this->UseOnlineKassa) {
    282             $order = $payment->PaidObject();
    283             $contact = ($order->Email ? $order->Email : $order->Phone); // !!! добаваить проверку на формат телефона
    284             $checkData = array(
    285                 'customerContact' => $contact,
    286                 'taxSystem' => $this->TaxSystem,
    287             );
    288             // добавляем НДС для Атолл, если есть
    289             // пока getVAT реализован в catalog-0.9
    290             if (singleton('Product')->hasMethod('getVAT')) {
    291                 $sc = SiteConfig::current_site_config();
    292                 $items = array();
    293                 foreach($order->Items() as $item) {
    294                     $itm = array();
    295                     $itm['quantity'] = $item->Quantity;
    296                     $itm['price'] = array();
    297                     $itm['price']['amount'] = $item->ItemPrice;
    298                     $vat = $item->getProduct()->getVAT();
    299                     $itm['tax'] = $vat->YaKassaCode;
    300                     $itm['text'] = $item->Title;
    301
    302                     // доп.данные при переходе на ФФД 1.05
    303                     if (trim($this->PaymentSubject) && trim($this->PaymentMode)) {
    304                         $itm['paymentMethodType'] = $this->PaymentMode;
    305                         $itm['paymentSubjectType'] = $this->PaymentSubject;
    306                     }
    307                     $items[] = $itm;
    308                 }
    309                 if ($order->ShippingMethodID && ($shippingMethod = $order->ShippingMethod())) {
    310                     $itm = array();
    311                     $itm['quantity'] = 1;
    312                     $itm['price'] = array();
    313                     $itm['price']['amount'] = $order->ShippingTotal;
    314                     $vat = $item->getProduct()->getVAT();
    315                     $itm['tax'] = (($sc->DefaultVATID && ($defaultVAT = $sc->DefaultVAT())) ? $defaultVAT->YaKassaCode : 1); //  для доставки используем налог по умолчанию
    316                     $itm['text'] = $shippingMethod->Name;
    317                     $items[] = $itm;
    318                 }
    319                 $checkData['items'] = $items;
    320                 $html .= '<input name="ym_merchant_receipt" value=\''.json_encode($checkData, JSON_UNESCAPED_UNICODE).'\' type="hidden"/>';
    321             }
    322         }
    323         $html .= '<input name="shopSuccessURL" value="'.$successURL.'" type="hidden"/>';
    324         $html .= '<input name="shopFailURL" value="'.$errorURL.'" type="hidden"/>';
    325         $html .= '<input type="submit" value="Оплатить" />';
    326
    327         //!!! Возможно добавить поля телефон (cps_phone) и Email (cps_phone) указанные при оформлении заказа и взятые из профиля (если авторизован) !!!!
    328         $html .= '</form>';
    329         return $html;
    330
    331         /*
    332         $rs = array();
    333         $rs['HeadHtml'] = $headHtml;
    334         //$rs['PaymentTypes'] = $payments;
    335         $rs['FooterHtml'] = $footerHtml;
    336         return $rs;
    337         */
    338     }
    339
    340     //Сигнатура уведомления о изменеии статуса заказа
    341     function getRequestSignature($post) {
    342         return strtoupper(md5($post['action'].';'.$post['orderSumAmount'].';'.$post['orderSumCurrencyPaycash'].';'.$post['orderSumBankPaycash'].';'.$post['shopId'].';'.$post['invoiceId'].';'.$post['customerNumber'].';'.$this->Password()));
    343     }
    344
    345     /*
    346      * Проверка результатов совершения платежа
    347      *
    348      */
    349     function completePayment($payment) {
    350         if ($payment->Status != 'Success') {
    351             $payment->Status = 'Success';
    352             $payment->Message = _t('YaMoneyPayment.DONE', 'Заказ оплачен');
    353             $payment->write();
    354         }
    355     }
    356 }
    357
    358 /**
    359  * Handler for responses from the YaMoney
    360  */
    361 class YaMoneyPayment_Handler extends Payment_Handler {
    362
    363     static $URLSegment = 'ya_money';
    364
    365     //ссылка на форму платежа
    366     static function payment_link($hash) {
    367         return self::$URLSegment . '/payment_form?hash=' . $hash;
    368     }
    369
    370     static function success_link() {
    371         return self::$URLSegment . '/success';
    372     }
    373
    374     static function error_link() {
    375         return self::$URLSegment . '/error';
    376     }
    377
    378     function payment_form() {
    379         if (isset($_GET['hash'])) {
    380             $hash = Convert::raw2sql($_GET['hash']);
    381             $payment = DataObject::get_one('Payment', "HashLink = '$hash'");
    382             if ($payment) {
    383                 $formData = $payment->PaymentType()->getForm($payment);
    384                 if ($formData) {
    385                     return $this->customise(array(
    386                         'Form' => $formData
    387                     ))->renderWith(array('YaMoneyPayment_form'));
    388                     //  return $formData;
    389                 }
    390             }
    391         }
    392         return false;
    393     }
    394
    395     /*
    396      * Action для получения ответов от Яндекса
    397      * указывается при оформлении услуги
    398      *
    399      */
    400     function callBack($post) {
    401         $response = false;
    402         $yaPaymentMethod = YaMoneyPayment::getPaymentMethod();
    403         if (!$yaPaymentMethod) {
    404             return false;
    405         }
    406         $requestData = false;
    407
    408         switch($yaPaymentMethod->ConnectionType) {
    409             case 'PKCS7':
    410                 $requestData = $this->decrypt_proc($post->getBody());
    411                 break;
    412             case 'HTTPS':
    413                 $requestData = $post->postVars();
    414                 break;
    415         }
    416         if ($requestData && isset($requestData['action'])) { //$_POST
    417             if ($requestData) {
    418                 if ($requestData['action'] == 'checkOrder') { //$_POST
    419                     $response = $this->checkOrder($requestData);//$_POST
    420                 }
    421                 if ($requestData['action'] == 'paymentAviso') {
    422                     $response = $this->paymentAviso($requestData); //$_POST
    423                 }
    424                 if ($response) {
    425                     header("Content-Type: application/xml; charset=utf-8");
    426                     echo $response;
    427                 }
    428             }
    429         }
    430     }
    431
    432     /*
    433      * Список обязательных полей ответа от Яндекса. При подключении Контрагента по схеме XML/PKCS#7 поле md5 не нужно
    434      *
    435      * @return array
    436      */
    437     function getRequiredParams() {
    438         $params = array('action',  'shopId', 'orderNumber', 'customerNumber', 'orderSumAmount', 'paymentType', 'orderSumCurrencyPaycash', 'orderSumBankPaycash', 'invoiceId');
    439         $yaPaymentMethod = YaMoneyPayment::getPaymentMethod();
    440         if ($yaPaymentMethod) {
    441             if ($yaPaymentMethod->ConnectionType == 'HTTPS') {
    442                 $params[] = 'md5';
    443             }
    444             return $params;
    445         }
    446         return false;
    447     }
    448
    449     /*
    450      * Проверка заказа (сheckOrder)
    451      *
    452      * Запрос проверки корректности параметров заказа.
    453      * Этот шаг позволяет исключить ошибки, которые могли возникнуть при прохождении платежной формы через браузер плательщика.
    454      * В случае успешного ответа Контрагента Оператор предлагает плательщику оплатить заказ и при успехе отправляет Контрагенту «Уведомление о переводе».
    455      *
    456      */
    457     function checkOrder($post) {
    458         $code = 0;
    459         $message = '';
    460         $params = $this->getRequiredParams();
    461         if ($params) {
    462             foreach($params as $param) {
    463                 if (!isset($post[$param])) {
    464                     $code = 200;
    465                     $message = 'Не указаны все обязательные параметры';
    466                 }
    467             }
    468         } else {
    469             $code = 200;
    470             $message = 'Не указаны все обязательные параметры';
    471         }
    472         if ($post['action'] != 'checkOrder') {
    473             $code = 200;
    474             $message = 'Неправильный параметр action';
    475         }
    476         if (!$code) {
    477             if ($payment = DataObject::get_by_id('Payment', YaMoneyPayment::parse_orderID($post['orderNumber']))) {
    478                 $payment->PaymentResponse = serialize($post);
    479                 $payment->YaMoneyPaymentType = $post['paymentType'];
    480                 $payment->TransactionID = $post['invoiceId'];
    481                 $payment->write();
    482                 $paymentType = $payment->PaymentType();
    483                 if (($paymentType->ConnectionType == 'HTTPS') && $post['md5'] != $paymentType->getRequestSignature($post)) {
    484                     $code = 1;
    485                     $message = 'Проверка хэша неудачна';
    486                 }
    487                 if (!($post['shopId'] == $paymentType->ShopID()) || !($post['customerNumber'] == ('order_'.$payment->PaidForID))) {
    488                     $code = 100;
    489                     $message = 'Неверные параметры заказа';
    490                 }
    491             } else {
    492                 $code = 100;
    493                 $message = 'Неверные параметры заказа';
    494             }
    495         }
    496         if (!$code) {
    497             $response = '<?xml version="1.0" encoding="UTF-8"?>'."\n".'<checkOrderResponse performedDatetime="'.date('c').'" code="0" invoiceId="'.$post['invoiceId'].'" shopId="'.$paymentType->ShopID().'" orderSumAmount="'.$post['orderSumAmount'].'"/>'."\n";
    498         } else {
    499             $response = '<?xml version="1.0" encoding="UTF-8"?>'."\n".'<checkOrderResponse performedDatetime="'.date('c').'" code="'.$code.'" invoiceId="'.$post['invoiceId'].'" shopId="'.$paymentType->ShopID().'" message="'.$message.'"/>';
    500         }
    501         return $response;
    502     }
    503
    504
    505     /*
    506      *  Уведомление о переводе (paymentAviso)
    507      *
    508      * Уведомление Контрагента о принятом переводе.
    509      * Этот запрос обозначает факт успешного перевода денежных средств плательщика в адрес Контрагента
    510      * и обязанность Контрагента выдать товар плательщику.
    511      * Обратите внимание: на этом шаге Контрагент не может отказаться от приема перевода.
    512      *
    513      */
    514     function paymentAviso($post) {
    515         $code = 0;
    516         $message = '';
    517         $params = $this->getRequiredParams();
    518         if ($params) {
    519             foreach($params as $param) {
    520                 if (!isset($post[$param])) {
    521                     $code = 200;
    522                     $message = 'Не указаны все обязательные параметры';
    523                 }
    524             }
    525         } else {
    526             $code = 200;
    527             $message = 'Не указаны все обязательные параметры';
    528         }
    529         if ($post['action'] != 'paymentAviso') {
    530             $code = 200;
    531             $message = 'Неправильный параметр action';
    532         }
    533         if (!$code) {
    534             if ($payment = DataObject::get_by_id('Payment', YaMoneyPayment::parse_orderID($post['orderNumber']))) {
    535                 $payment->PaymentResponse = serialize($post);
    536                 $payment->YaMoneyPaymentType = $post['paymentType'];
    537                 $payment->write();
    538                 $paymentType = $payment->PaymentType();
    539                 if (($paymentType->ConnectionType == 'HTTPS') && $post['md5'] != $paymentType->getRequestSignature($post)) {
    540                     $code = 1;
    541                     $message = 'Проверка хэша неудачна';
    542                 }
    543                 if (!($post['shopId'] == $paymentType->ShopID()) || !($post['customerNumber'] == ('order_'.$payment->PaidForID))) {
    544                     $code = 100;
    545                     $message = 'Неверные параметры заказа';
    546                 }
    547             } else {
    548                 $code = 100;
    549                 $message = 'Неверные параметры заказа';
    550             }
    551         }
    552         if (!$code) {
    553             //если все ОК - оплачиваем заказ
    554             $paymentType->completePayment($payment);
    555             $response = '<?xml version="1.0" encoding="UTF-8"?>'."\n".'<paymentAvisoResponse performedDatetime="'.date('c').'" code="0" invoiceId="'.$post['invoiceId'].'" shopId="'.$paymentType->ShopID().'"/>';
    556         } else {
    557             $response = '<?xml version="1.0" encoding="UTF-8"?>'."\n".'<paymentAvisoResponse performedDatetime="'.date('c').'" code="'.$code.'" invoiceId="'.$post['invoiceId'].'" shopId="'.$paymentType->ShopID().'" message="'.$message.'"/>';
    558         }
    559         return $response;
    560     }
    561
    562     /**
    563      * Успешная оплата
    564      */
    565     function success() {
    566         if (isset($_GET['orderNumber'])) {
    567             $paymentID = YaMoneyPayment::parse_orderID($_GET['orderNumber']);
    568             if (($payment = DataObject::get_by_id('Payment', $paymentID)) && ($order = DataObject::get_by_id('Order', $payment->PaidForID))) {
    569                 $link = false;
    570                 if (class_exists('CheckoutPage')) {
    571                     $link = CheckoutPage::find_link('order/' . $order->HashLink);
    572                 }
    573                 return singleton('Page_Controller')->customise(array(
    574                     'Order' => $order,
    575                     'OrderLink' => $link,
    576                 ))->renderWith(array('YaMoneyPayment_success', 'Page' ));
    577             }
    578         }
    579     }
    580
    581     /**
    582      * НЕУспешная оплата
    583      */
    584     function error() {
    585         if (isset($_GET['orderNumber'])) {
    586             $paymentID = YaMoneyPayment::parse_orderID($_GET['orderNumber']);
    587             if (($payment = DataObject::get_by_id('Payment', $paymentID)) && ($order = DataObject::get_by_id('Order', $payment->PaidForID))) {
    588                 $link = false;
    589                 if (class_exists('CheckoutPage')) {
    590                     $link = CheckoutPage::find_link('order/' . $order->HashLink);
    591                 }
    592                 return singleton('Page_Controller')->customise(array(
    593                     'Order' => $order,
    594                     'OrderLink' => $link,
    595                 ))->renderWith(array('YaMoney_error', 'Page'));
    596             }
    597         }
    598     }
    599
    600     // Декодирование ответа Яндекса по протоколу XML/PKCS#7
    601     private function decrypt_proc($data){
    602         // $data - ответ сервера
    603         $descriptorspec = array(
    604             0 => array("pipe", "r"),
    605             1 => array("pipe", "w"),
    606             2 => array("pipe", "w"),
    607         );
    608         $yaPaymentMethod = YaMoneyPayment::getPaymentMethod();
    609         $certFilePath = YaMoneyPayment::get_cert_file_path();
    610         $CAfilePath = YaMoneyPayment::get_CA_file_path();
    611         if (!$certFilePath || !is_file($certFilePath)) {
    612             //!!! падать с ошибкой
    613             user_error(_t('YaMoneyPayment.NoCertificate', 'No certificate'), E_USER_ERROR);
    614             return false;
    615         }
    616         $process = proc_open(
    617             'openssl smime -verify -inform PEM -nointern -certfile '.$certFilePath.' -CAfile '.$CAfilePath, $descriptorspec, $pipes);
    618
    619         if (is_resource($process)) {
    620             fwrite($pipes[0], $data);
    621             fclose($pipes[0]);
    622             $xml = stream_get_contents($pipes[1]);
    623             $sm = simplexml_load_string($xml);
    624             if ($sm) {
    625                 $rrs = array();
    626                 $rrs['action'] = str_replace('Request','',$sm->getName());
    627                 foreach($sm->attributes() as $name=>$attr) {
    628                     $rrs[(string)$name] = (string)$attr;
    629                 }
    630                 fclose($pipes[1]);
    631                 $resCode = proc_close($process);
    632                 if ($resCode != 0) {
    633                     if ($resCode == 2 || $resCode == 4){
    634                         return false;
    635                     }
    636                 }
    637                 return $rrs;
    638             }
    639         }
    640         return false;
    641     }
    642 }
    643
    644
    645
    646
    647 /*
    648 ПАРАМЕТРЫ
    649 Проверка заказа (сheckOrder)
    650
    651 action  xs:normalizedString, до 16 символов   Тип запроса. Значение: «checkOrder» (без кавычек).
    652 md5 xs:normalizedString, ровно 32 шестнадцатеричных символа, в верхнем регистре    MD5-хэш параметров платежной формы, правила формирования описаны в разделе 4.4 «Правила обработки HTTP-уведомлений Контрагентом».
    653 shopId  xs:long Идентификатор Контрагента, присваиваемый Оператором.
    654 shopArticleId   xs:long Идентификатор товара, присваиваемый Оператором.
    655 invoiceId   xs:long Уникальный номер транзакции в ИС Оператора.
    656 orderNumber xs:normalizedString, до 64 символов   Номер заказа в ИС Контрагента. Передается, только если был указан в платежной форме.
    657 customerNumber  xs:normalizedString, до 64 символов   Идентификатор плательщика (присланный в платежной форме) на стороне Контрагента: номер договора, мобильного телефона и т.п.
    658 orderCreatedDatetime    xs:dateTime Момент регистрации заказа в ИС Оператора.
    659 orderSumAmount  CurrencyAmount  Стоимость заказа. Может отличаться от суммы платежа, если пользователь платил в валюте, которая отличается от указанной в платежной форме. В этом случае Оператор берет на себя все конвертации.
    660 orderSumCurrencyPaycash CurrencyCode    Код валюты для суммы заказа.
    661 orderSumBankPaycash CurrencyBank    Код процессингового центра Оператора для суммы заказа.
    662 shopSumAmount   CurrencyAmount  Сумма к выплате Контрагенту на р/с (стоимость заказа минус комиссия Оператора).
    663 shopSumCurrencyPaycash  CurrencyCode    Код валюты для shopSumAmount.
    664 shopSumBankPaycash  CurrencyBank    Код процессингового центра Оператора для shopSumAmount.
    665 paymentPayerCode    YMAccount   Номер счета в ИС Оператора, с которого производится оплата.
    666 paymentType                 Способ оплаты заказа. Список значений приведен в таблице 6.6.1.
    667
    668 */

[Raise a SilverStripe Framework issue/bug](https://github.com/silverstripe/silverstripe-framework/issues/new)
- [Raise a SilverStripe CMS issue/bug](https://github.com/silverstripe/silverstripe-cms/issues/new)
- Please use the Silverstripe Forums to ask development related questions. -