Обработчик платежной системы A1Pay

#
Обработчик платежной системы A1Pay
<?php
/* Оплата через A1Pay */
class system_of_pay_handler
{
   // Секретный ключ
   var $password = "qwertyuiop";
   
   // Идентификатор рублей = 1
   var $currency_id = 1;
   
   // Ключ, присваеваемый магазину системой A1Pay, при создании кнопки
   var $key = "qwertyuiop";
   
   // Запускаем обработчик платежной системы
   function Execute()
{
      // Пришло подтверждение оплаты, обработаем его
      if (isset($_REQUEST['order_id']))
      {
         $this->ProcessResult();
         return true;
      }

      // Иначе оформляем заказ и отображаем стартовую страницу для оплаты через A1Pay
      $this->ShowPurseRequest();
   }
   
   // Обработка ответа платежной системы
   function ProcessResult()
{
      // Информация о заказе
      $order_id = to_int($_REQUEST['order_id']);

      if (!$order_id)
      {
         return false;
      }

      $shop = & singleton('shop');

      $order_row = $shop->GetOrder($order_id);

      // Заказ не найден или уже оплачен
      if (!$order_row || $order_row['shop_order_status_of_pay'])
      {
         return false;
      }

      $shop_row = $shop->GetShop($order_row['shop_shops_id']);

      $a1pay_hash = to_str($_REQUEST["check"]);

      $data = array
      (
         'tid' => $_POST['tid'],
         'name' => urldecode($_POST['name']),
         'comment' => urldecode($_POST['comment']),
         'partner_id' => $_POST['partner_id'],
         'service_id' => $_POST['service_id'],
         'order_id' => $_POST['order_id'],
         'type' => $_POST['type'],
         'partner_income' => $_POST['partner_income'],
         'system_income' => $_POST['system_income']
      );
      
      $our_hash = md5(join('', array_values($data)) . $this->password);
      
      // Устанавливаем параметры, которые не зависят от совпадения хешей
      $param['id'] = $order_row['shop_order_id'];
      $param['shop_shops_id'] = $order_row['shop_shops_id'];
      
      
      $shop_row = $shop->GetShop($order_row['shop_shops_id']);
         
      /* Делаем перерасчет суммы в валюту */
      $shop_currency_id = $shop_row['shop_currency_id'];

      /* Определяем коэффициент пересчета */
      $coefficient = $shop->GetCurrencyCoefficientToShopCurrency($shop_currency_id, $this->currency_id);

      $currency_row = $shop->GetCurrency($shop_currency_id);

      $order_sum = $shop->GetOrderSum($order_id);
      
      // округляем до десятых после запятой
      $sum = round($order_sum * $coefficient, 2);
   
      // Сравниваем хэши
      if ($a1pay_hash == $our_hash)
      {
         if(to_float($_POST['partner_income']) == floatval($sum))
         {
            // суммы совпали, можно отдавать товар
            
            $param['system_information'] = "Товар оплачен через A1Pay.\n\n"
            . "Информация:\n\n"
            . "ID транзакции A1Pay: {$_POST['tid']}\n"
            . "Id партнера: {$_POST['partner_id']}\n"
            . "Id сервиса: {$_POST['service_id']}\n"
            . "Id заказа: {$_POST['order_id']}\n"
            . "Тип оплаты: {$_POST['type']}\n"
            . "\n";

            // Обновляем информацию о заказе
            $shop->InsertOrder($param);
            
            // Изменяем статус оплаты ПОСЛЕ ОБНОВЛЕНИЯ ИНФОРМАЦИ, генерируем ссылки для эл.товаров, списываем товары
            $shop->SetOrderPaymentStatus($order_id);
            
            $structure = & singleton('Structure');
            
            $structure_row = $structure->GetStructureItem(to_int($shop_row['structure_id']));

            $lib = & singleton('lib');
            
            $LA = $lib->LoadLibPropertiesValue(to_int($structure_row['lib_id']), to_int($structure_row['structure_id']));

            $order_row = $shop->GetOrder($order_id);

            // Отправляем письмо администратору о подтверждении платежа
            $shop->SendMailAboutOrder($order_row['shop_shops_id'], $order_id, $order_row['site_users_id'],
            to_str($LA['xsl_letter_to_admin']),
            to_str($LA['xsl_letter_to_user']),
            $order_row['shop_order_users_email'],
            array(
            'admin-content-type' => 'html',
            'user-content-type' => 'html',
            'admin-subject' => sprintf($GLOBALS['MSG_shops']['shop_order_confirm_admin_subject'], $order_id, $shop_row['shop_shops_name'], $order_row['shop_order_date_of_pay']),
            'user-subject' => sprintf($GLOBALS['MSG_shops']['shop_order_confirm_user_subject'], $order_id, $shop_row['shop_shops_name'], $order_row['shop_order_date_of_pay']),
            'email_from_admin' => $order_row['shop_order_users_email']));
         }
         else
         {
            $param['system_information'] = 'Сумма не совпала!';
               
               // Обновляем информацию о заказе
            $shop->InsertOrder($param);         
         }
      }
      else
      {
         $param['system_information'] = 'Хэш не совпал!';
         
         // Обновляем информацию о заказе
         $shop->InsertOrder($param);         
      }
   }
   
   function ShowPurseRequest()
   {
      $shop = & singleton('shop');
      
      $system_of_pay_id = to_int($_SESSION['system_of_pay_id']);
      
      $row_system_of_pay = $shop->GetSystemOfPay($system_of_pay_id);
      
      if ($row_system_of_pay)
      {
         $shop_id = $row_system_of_pay['shop_shops_id'];
      }
      else
      {
         return false;
      }

      /* Получаем id текущего пользователя сайта */
      if (class_exists('SiteUsers'))
      {
         /* Получаем id текущего пользователя сайта */
         $SiteUsers = & singleton('SiteUsers');
         
         $site_users_id = $SiteUsers->GetCurrentSiteUser();
      }
      else
      {
         $site_users_id = false;
      }

      // статус платежа, по умолчанию 0
      $order_row['status_of_pay'] = 0;

      // дата платежа, по умолчанию пустая строка
      $order_row['date_of_pay'] = '';

      $order_row['description'] = to_str($_SESSION['description']);
      
      // описание и системная информация, по умолчанию пустая строка
      if (to_str($_SESSION['shop_coupon_text']) != '')
      {
         $order_row['description'] .= "Купон на скидку: ".to_str($_SESSION['shop_coupon_text'])."\n";
      }

      if (!isset($_SESSION['last_order_id']))
      {
         $_SESSION['last_order_id'] = 0;
      }

      // Если заказ еще не был оформлен
      if ($_SESSION['last_order_id'] == 0)
      {
         /* Оформляем заказ */
         $order_id = $shop->ProcessOrder($shop_id, $site_users_id, $system_of_pay_id, $order_row);
      }
      else
      {
         $order_id = $_SESSION['last_order_id'];
      }

      // Оформление заказа произошло успешно
      if ($order_id > 0)
      {
         if (!class_exists('SiteUsers'))
         {
            /* Класс пользователей сайта не существует, дописываем информацию о заказчике
            в поле shop_order_description из текущей сессии */
            if ($order_row)
            {
               /* Описание заказчика */
               $order_row['description'] .= "Информация о заказчике:\n"
               ."Имя: ".to_str($_SESSION['site_users_name'])."\n"
               ."Фамилия: ".to_str($_SESSION['site_users_surname'])."\n"
               ."Отчество: ".to_str($_SESSION['site_users_patronymic'])."\n"
               ."E-Mail: ".to_str($_SESSION['site_users_email'])."\n"
               ."Телефон: ".to_str($_SESSION['site_users_phone'])."\n"
               ."Факс: ".to_str($_SESSION['site_users_fax'])."\n"
               ."Адрес: ".to_str($_SESSION['full_address'])."\n";

               /* Дополнительная информация о заказе */
               $order_row['system_information'] = to_str($_SESSION['system_information']);   

               /* Обязательно добавляем идентификатор! */
               $order_row['id'] = $order_id;

               $shop->InsertOrder($order_row);
            }
         }
         
         $order_row = $shop->GetOrder($order_id);
         
         if ($order_row)
         {
            $this->PrintOrder($order_id);
         }
         
         $shop_row = $shop->GetShop($shop_id);

         if ($_SESSION['last_order_id'] == 0)
         {
            $structure = & singleton('Structure');
            $structure_row = $structure->GetStructureItem(to_int($shop_row['structure_id']));

            $lib = new lib();
            $LA = $lib->LoadLibPropertiesValue(to_int($structure_row['lib_id']), to_int($structure_row['structure_id']));

            $date_str = date("d.m.Y H:i:s");

            if (trim(to_str($order_row['shop_order_account_number'])) != '')
            {
               $shop_order_account_number = trim(to_str($order_row['shop_order_account_number']));
            }
            else
            {
               $shop_order_account_number = $order_id;
            }
            
            /* Отправляем письмо заказчику */
            $shop->SendMailAboutOrder($shop_id,
            $order_id,
            $site_users_id,
            to_str($LA['xsl_letter_to_admin']),
            to_str($LA['xsl_letter_to_user']),
            $order_row['shop_order_users_email'],
            array('admin-content-type' => 'html',
            'user-content-type' => 'html',
            'admin-subject' => sprintf($GLOBALS['MSG_shops']['shop_order_admin_subject'], $shop_order_account_number, $shop_row['shop_shops_name'], $date_str),
            'user-subject' => sprintf($GLOBALS['MSG_shops']['shop_order_user_subject'], $shop_order_account_number, $shop_row['shop_shops_name'], $date_str),
            'email_from_admin' => $order_row['shop_order_users_email']));
         }
         
         // Сохраняем ID последнего оформленного заказа ТОЛЬКО ПОСЛЕ ОТПРАВКИ ПИСЬМА
         $_SESSION['last_order_id'] = $order_id;
      }
      else
      {
         switch ($order_id)
         {
            case -1:
               {
                  ?><div id="error">Ошибка вставки заказа в базу данных. Обратитесь к администратору.</div><?php
                  break;
               }
            case -2:
               {
                  ?><div id="error">Ошибка - не найден магазин. Обратитесь к администратору.</div><?php
                  break;
               }
            case -3:
               {
                  ?><div id="error">Ошибка - корзина пуста. Добавьте товар в корзину и оформите заказ.</div><?php
                  break;
               }
         }
      }

      return true;
   }
   
   /**
    * Метод для отображения формы заказа для печати.
    *
    * @param int $order_id идентификатор заказа
    */
   function PrintOrder($order_id)
   {
      $shop = & singleton('shop');
      
      $order_row = $shop->GetOrder($order_id);
      
      if (!$order_row)
      {
         return false;
      }
      
      if ($order_row)
      {
         $shop_row = $shop->GetShop($order_row['shop_shops_id']);
         
         /* Делаем перерасчет суммы в валюту */
         $shop_currency_id = $shop_row['shop_currency_id'];

         /* Определяем коэффициент пересчета */
         $coefficient = $shop->GetCurrencyCoefficientToShopCurrency($shop_currency_id, $this->currency_id);

         $currency_row = $shop->GetCurrency($shop_currency_id);

         $order_sum = $shop->GetOrderSum($order_id);
         
         // округляем до десятых после запятой
         $sum = round($order_sum * $coefficient, 2);
         
         ?>
         <h1>Оплата через систему A1Pay</h1>
         <p>Сумма к оплате составляет <strong><?php echo $sum?> <?php echo $currency_row['shop_currency_name']?></strong></p>
         <p>Для оплаты нажмите кнопку "Оплатить".</p>
         <p style="color: rgb(112, 112, 112);">
         Внимание! Нажимая &laquo;Оплатить&raquo; Вы подтверждаете передачу контактных данных на сервер A1Pay для оплаты.
         </p>
         <form name="form1" action="https://partner.a1pay.ru/a1lite/input" method="POST" accept-charset="windows-1251">
         <input type="hidden" name="key" value="<?php echo $this->key?>" />
         <input type="hidden" name="cost" value="<?php echo $sum?>" />
         <input type="hidden" name="name" value="Заказ №<?php echo $order_id?>" />
         <input type="hidden" name="default_email" value="" />
         <input type="hidden" name="order_id" value="<?php echo $order_id?>" />
         <input type="hidden" name="comment" value="accept_a1pay" />
         <input type="submit" name="submit" value="Оплатить <?php echo $sum?> <?php echo $currency_row['shop_currency_name']?>">
         </form>
         <?php
      }
   }
}
?>


в поля

// Секретный ключ
   var $password = "qwertyuiop";
   
   // Идентификатор рублей = 1
   var $currency_id = 1;
   
   // Ключ, присваеваемый магазину системой A1Pay, при создании кнопки
   var $key = "qwertyuiop";
, естественно, добавьте свои данные.

Также не забудьте в коде типовой динамической страницы корзины "встретить" запрос от платежной системы:

// ------------------------------------------------
// Подготовка редиректа для A1Pay
// ------------------------------------------------
if (isset($_POST['comment']) && $_POST['comment'] == 'accept_a1pay')
{
   // Получаем ID заказа
   $order_id = to_int($_POST['order_id']);

   $order_row = $shop->GetOrder($order_id);

   if ($order_row)
   {
      // Вызов обработчика платежной системы
      $shop->ExecSystemsOfPayHandler($order_row['shop_system_of_pay_id']);
   }
}
#
Re: Обработчик платежной системы A1Pay
Прошу прощения за ранее, возможно не в ту тему пишу. Есть вопрос. Не планируется ли у Вас, сделать обработчик платежной системы platron ?
#
Re: Обработчик платежной системы A1Pay
KorSa,
планируется, надеюсь в скором времени мы его сделаем. Собственно он следующий на очереди.
#
Re: Обработчик платежной системы A1Pay
Спасибо!
#
Re: Обработчик платежной системы A1Pay
Планируется ли сделать обработчик для asp.net?
#
Re: Обработчик платежной системы A1Pay
iPanda,
не планируется, но Вы можете самостоятельно проинтегрировать желаемую платежную систему. Информация по интеграции дана в руководстве пользователя.
#
Re: Обработчик платежной системы A1Pay
shushpanchik, по-моему это не все, для обработки платежа.

Кроме того, чтобы "«встретить» запрос от платежной системы", нужно еще показать пользователю, что платеж прошел.

На текущий момент в последней версии lib_7.php (позавчерашняя версия), есть такой кусок кода:

// ------------------------------------------------
// Вывод информации о статусе платежа после его совершения и перенаправления с платежной системы
// ------------------------------------------------
if (isset($_REQUEST['payment']) || (isset($_GET['action']) && ($_GET['action'] == 'PaymentSuccess' || $_GET['action'] == 'PaymentFail')))
{
   // Получаем ID заказа
   if (isset($_REQUEST['order_id']))
   {
      $order_id = to_int($_REQUEST['order_id']);
   }
   //от Яндекса
   elseif(isset($_GET['orderNumber']))
   {
      $order_id = to_int($_GET['orderNumber']);
   }
   else
   {
      $order_id = to_int($_REQUEST['InvId']);
   }

   $order_row = $shop->GetOrder($order_id);

   // Если заказ принадлежит текущему авторизированному пользователю
   if ($order_row['site_users_id'] == $site_users_id)
   {
      if (to_str($_REQUEST['payment']) == 'success' || to_str($_GET['action']) == 'PaymentSuccess')
      {
         ?><h1>Подтверждение платежа</h1>
         <p>Спасибо, информация об оплате заказа <strong>№ <?php echo $order_row['shop_order_account_number']?></strong>
получена.</p>
         <?php
      }
      else
      {
         ?><h1>Платеж не получен</h1>
         <p>К сожалению при оплате заказа <strong>№ <?php echo $order_row['shop_order_account_number']?></strong> произошла ошибка.</p>
         <?php
      }
   }
   // Для случаев, когда отключен модуль "Пользователи сайта"
   elseif ($site_users_id === false)
   {
      ?><h1>Подтверждение платежа</h1>
      <p>Благодарим за посещение нашего магазина!</p>
      <?php
   }
   else
   {
      ?><h1>Ошибка</h1>
      <p>Неверный номер заказа!</p>
      <?php
   }

   // Прерываем выполнение типовой динамической страницы
   return true;
}


Но я так понимаю, условие
if (isset($_REQUEST['payment']) || (isset($_GET['action']) && ($_GET['action'] == 'PaymentSuccess' || $_GET['action'] == 'PaymentFail')))
не сработает для этой платежной системы, и нужно ставить другое условие.
Создание сайтов в Хабаровске - http://web-alt.ru
#
Re: Обработчик платежной системы A1Pay
Вся проблема в том, что "доказательство" правильности платежа происходит в handlerXX.php , а сообщение о проведенном платеже в lib_7.php .
Поэтому я поступил следующим образом:

1. В handlerXX.php объявил константу при успешном платеже, после условия if ( to_float( $_POST['partner_income'] ) == floatval( $sum ) )
if(to_float($_POST['system_income']) == floatval($sum)) {
             // суммы совпали, можно отдавать товар
             define("success_a1pay", true);


2. В lib_7.php в главное условие добавил еще одно условие:
if (isset($_REQUEST['payment']) || (isset($_GET['action']) && ($_GET['action'] == 'PaymentSuccess' || $_GET['action'] == 'PaymentFail')) || (isset($_POST['comment']) && $_POST['comment'] == 'accept_a1pay'))


3. В lib_7.php в условие успешности платежа вставил проверку объявленной константы:
if (to_str($_REQUEST['payment']) == 'success' || to_str($_GET['action']) == 'PaymentSuccess' || defined("success_a1pay"))


Вот так заработало =)
Создание сайтов в Хабаровске - http://web-alt.ru
#
Re: Обработчик платежной системы A1Pay
web-alt,
спасибо
#
Re: Обработчик платежной системы A1Pay
Пожалуйста!

Еще два момента:

1. Не знаю как было при написании этого обработчика, но я установил себе данную платежную систему на днях. После совершения платежа, данные передаются на сайт GET запросом, а в обработчике везде стоит $_POST и несколько $_REQUEST. Думаю было бы логично везде использовать $_REQUEST.

2. Большая проблема в условии:
if (to_float ($_POST['partner_income']) == floatval ($sum))
я его заменил на:
if (to_float ($_POST['system_income']) == floatval($sum))

partner_income - какое отчисление получит партнер платежки
system_income - какое сколько пользователь заплатил в реальности.

Так как мы передаем платежной системе сумму платежа без наценки (во всяком случае пока в HostCMS это не предусмотрено), то и оплачена будет именно эта сумма. А так как комиссия может быть разной для разных способов оплаты, то partner_income всегда будет разный и никогда(!) не будет совпадать с суммой платежа.
Создание сайтов в Хабаровске - http://web-alt.ru
Авторизация