Version: current

      1 <?php
      2 /**
      3  * Класс Способ оплаты
      4  * Хранит информацию о способе оплаты, параметры подключения
      5  *
      6  * @author menedem
      7  */
      8 class PaymentMethod extends DataObject {
      9     static $db = array(
     10         'Title' => 'Varchar(200)',
     11         'Content' => 'Text',
     12         'OrderMessage' => 'HTMLText',
     13         'Active' => 'Boolean',
     14         'IconPath' => 'Varchar(255)',
     15         'IconType' => 'Int',
     16         'SubsiteID' => 'Int', // подсайт способа оплаты - чтоб показывать способы оплаты по подсайтам
     17         'UseOnlineKassa' => 'Boolean', // используем ли при оплате онлайн-кассы (типа Атолл)
     18     );
     19
     20     static $has_one = array(
     21         'Icon' => 'Image',
     22     );
     23
     24     // зачем они нужны???
     25     static $has_many = array(
     26         'Payments' => 'Payment'
     27     );
     28
     29     static $default_sort = 'ID';
     30
     31     private static $defaultPaymentObject = '';
     32
     33     function getDefaultPaymentObject() {
     34         return self::$defaultPaymentObject;
     35     }
     36     function setDefaultPaymentObject($obj) {
     37         self::$defaultPaymentObject = $obj;
     38     }
     39
     40     static $paymentMethodIcons = array(
     41     );
     42
     43     // DEPRECATED
     44     static $disabled_methods = array();
     45
     46     // DEPRECATED
     47     static function method_is_disabled($name) {
     48         return isset(self::$disabled_methods[$name]);
     49     }
     50
     51     // DEPRECATED
     52     static function set_disabled_methods($val) {
     53         self::$disabled_methods = array_combine($val, $val);
     54     }
     55
     56     // DEPRECATED
     57     static function disable_method($name) {
     58         self::$disabled_methods[$name] = $name;
     59     }
     60
     61     // DEPRECATED
     62     static function enable_method($name) {
     63         unset(self::$disabled_methods[$name]);
     64     }
     65
     66     // DEPRECATED
     67     static function get_disabled_methods() {
     68         return self::$disabled_methods;
     69     }
     70
     71     function getPaymentHandler() {
     72         return false;
     73     }
     74
     75     static $summary_fields = array('Title', 'PaymentTypeName', 'Active');
     76     static $searchable_fields = array('Title', 'Active');
     77     static $casting = array('PaymentTypeName' => 'Text');
     78
     79     protected $error;
     80
     81     function populateDefaults() {
     82         parent::populateDefaults();
     83         $this->Title = $this->i18n_singular_name();
     84         $this->Content = _t($this->ClassName . '.default_Content', '');
     85         $this->OrderMessage = _t($this->ClassName . '.default_OrderMessage', '');
     86     }
     87
     88     function fieldLabels($includerelations = true) {
     89         $labels = parent::fieldLabels($includerelations);
     90         $labels['PaymentTypeName'] = _t('PaymentMethod.PaymentTypeName', 'Type');
     91         return $labels;
     92     }
     93
     94     function PaymentTypeName() {
     95         return $this->i18n_singular_name();
     96     }
     97
     98     function CanCreate($member=null) {
     99         // if (self::method_is_disabled($this->ClassName)) return false; // НЕ ИСПОЛЬЗУЕМ, опираемся только на self::$supported_methods
    100         if (($this->ClassName != 'PaymentMethod') && !in_array($this->ClassName, self::$supported_methods)) return false;
    101         return parent::CanCreate($member);
    102     }
    103
    104     function getCMSFields() {
    105         $fields = parent::getCMSFields();
    106         $fields->removeByName('Payments');
    107
    108         $iconField = $fields->dataFieldByName('Icon');
    109
    110         $fields->removeByName('Icon');
    111         $fields->removeByName('IconPath');
    112
    113         $options = array();
    114
    115         $class = $this->class;
    116         if (count($class::$paymentMethodIcons)) {
    117             $icons = array();
    118             foreach($class::$paymentMethodIcons as $icon) {
    119                 $icons[$icon] = "<img src=\"{$icon}\">";
    120             }
    121             $options['1//' . _t('PaymentMethod.SelectFromList', 'Select From List')] = new OptionsetField('IconPath', $this->fieldLabel('IconPath'), $icons);
    122         }
    123         $options['2//' . _t('PaymentMethod.UploadIcon', 'Upload Icon')] = $iconField;
    124
    125         $type = new SelectionGroup('IconType', $options);
    126         $fields->insertAfter($type, 'Content');
    127
    128         $fields->dataFieldByName('OrderMessage')->setRows(15);
    129
    130
    131         if (class_exists('Subsite') && ($subsites = DataObject::get('Subsite'))) {
    132             $allSubsites = array(0 => _t('PaymentMethod.RussianLang'));
    133             foreach($subsites as $subsite) {
    134                 $allSubsites[$subsite->ID] = $subsite->Title;
    135             }
    136             $fields->replaceField('SubsiteID', new DropdownField('SubsiteID', $this->fieldLabel('SubsiteID'), $allSubsites));
    137         } else {
    138             $fields->removeByName('SubsiteID');
    139         }
    140
    141         return $fields;
    142     }
    143
    144     //Ссылка на страницу с формой
    145     function paymentLink($paymentID) {
    146         if ($payment = DataObject::get_by_id('Payment', $paymentID)) {
    147             if ($link = $this->getClearPaymentLink($payment)) {
    148                 return '<a class="button-link payment-link button button__marginRight form_action" href="' . $link . '">'._t('YaMoneyPayment.PayOrder','Pay Order').'</a>';
    149             }
    150         }
    151         return false;
    152     }
    153
    154     // "чистая" ссылка (URL) на оплату
    155     function getClearPaymentLink() {
    156         return false;
    157     }
    158
    159     function PaymentIcon() {
    160         $icon = false;
    161         switch ($this->IconType) {
    162             case 1:
    163                 if ($this->IconPath && is_file(BASE_PATH . "/{$this->IconPath}")) {
    164                     $icon = new Image_Cached($this->IconPath);
    165                 }
    166                 break;
    167             case 2:
    168                 if ($this->IconID && ($img = $this->Icon()) && is_file($img->FullPath)) {
    169                     $icon = $img;
    170                 }
    171                 break;
    172         }
    173         return $icon;
    174     }
    175
    176     /*
    177      * Возвращает название способа оплаты для формы их выбора.
    178      * В шаблоне ListTitle.ss можно полностью настроить внешний вид
    179      *
    180      * @return html
    181      */
    182     function ListTitle() {
    183         return $this->renderWith('ListTitle');
    184     }
    185
    186     protected static $supported_methods = array(
    187         'CustomPayment',
    188         'ChequePayment',
    189         //'YaMoneyPayment',
    190         //'UnitellerPayment',
    191         //'SberbankPayment',
    192     );
    193
    194     /**
    195      * Получение поддерживаемых способов оплаты
    196      *
    197      * @return array
    198      */
    199     public static function get_supported_methods(){
    200         return self::$supported_methods;
    201     }
    202
    203     /**
    204      * Задание поддерживаемых способов оплаты (для использования в _config.php)
    205      *
    206      * @param array $methodMap
    207      */
    208     static function set_supported_methods($methodMap) {
    209         self::$supported_methods = $methodMap;
    210     }
    211
    212     /**
    213      * Добавление поддерживаемого способа оплаты (для использования в _config.php)
    214      *
    215      * @param string $method
    216      */
    217     static function add_supported_method($method) {
    218         self::$supported_methods[] = $method;
    219     }
    220
    221     /**
    222      * Удаление поддерживаемого способа оплаты (для использования в _config.php)
    223      *
    224      * @param string $method
    225      */
    226     static function remove_supported_method($method) {
    227         $t = array();
    228         if (self::$supported_methods) {
    229             foreach(self::$supported_methods as $supportedMethod) {
    230                 if ($method != $supportedMethod) {
    231                     $t[] = $supportedMethod;
    232                 }
    233             }
    234         }
    235         self::$supported_methods = $t;
    236     }
    237
    238     /**
    239      * Возврат всех поддерживаемых способов оплаты (объектов)
    240      *
    241      * @return DataObjectSet
    242      */
    243     static function getPaymentMethods() {
    244         $subsiteID = 0;
    245         if (class_exists('Subsite')) {
    246             $subsiteID = Subsite::currentSubsiteID();
    247         }
    248         $paymentMethods = new DataObjectSet();
    249         $paymentMethodMap = array();
    250         if (count(self::$supported_methods) > 0) {
    251             $where = "(ClassName IN ('".implode("', '", self::$supported_methods)."')) AND SubsiteID = {$subsiteID}";
    252             if (Director::isLive()) // в Live режиме сайта показываем только активные платежи
    253                 $where .= ' AND Active = 1';
    254             $paymentMethods = DataObject::get("PaymentMethod", $where);
    255         }
    256         return $paymentMethods;
    257     }
    258
    259     /**
    260      * Create a new payment for an order
    261      *
    262      * @param <type> $order
    263      * @param <type> $paymentClass
    264      *
    265      * @return <type>
    266      */
    267     function createPayment($order, $paymentClass = 'Payment'){
    268         $payment = class_exists($paymentClass) ? new $paymentClass() : null;
    269         if (!($payment && $payment instanceof Payment)) {
    270             $this->error = _t("PaymentMethod.NOTPAYMENT", "'$paymentClass' isn't a valid payment method");
    271             return false;
    272         }
    273         if (($order->hasMethod('canPay')) && (!$order->canPay(Member::currentUser()))) {
    274             $this->error = _t("PaymentMethod.CANTPAY", "Order can't be paid for");
    275             return false;
    276         }
    277         $payment->MemberID = Member::currentUserID();
    278         $payment->PaymentTypeID = $this->ID;
    279         $payment->PaidForID = $order->ID;
    280         $payment->PaidForClass = $order->ClassName;
    281         $payment->Amount = $order->getPaymentSum();
    282         $payment->IP = isset($_SERVER['REMOTE_ADDR']) ? $_SERVER['REMOTE_ADDR'] : '';
    283         $payment->Message = $this->OrderMessage;
    284         $payment->write();
    285         return $payment;
    286     }
    287
    288     /**
    289      * Создает платеж и выполняет действия с ним (основная ф-ия, запускается на последнем шаге офорления заказа. Способы оплаты (занесенные в БД) выводятся в форме, пользователь выбирает нужный,
    290      * берем его экземпляр и для него создаем платежи)
    291      *
    292      * @return string - HTML для вставки на страницу (может быть просто сообщение, ссылка или форма для оплаты по картам)
    293      */
    294     function makePayment($order, $paymentClass = 'Payment'){
    295         //create payment
    296         $payment = $this->createPayment($order, $paymentClass);
    297         if(!$payment){
    298             //$this->error(_t("PaymentMethod.CANTCREATE", "Payment could not be created"));
    299             return new Payment_Failure($this->error); //??? добавить ссылку на заказ
    300         }
    301         // Process payment, get the result back
    302         $result = $this->processPayment($payment); //Возвращаем HTML
    303         $sc = SiteConfig::current_site_config();
    304         if (PaymentSiteConfig::getPaymentAfterConfirm()) { //если отложенная оплата
    305             return new Payment_Processing($sc->PaymentAfterConfirmMessage);
    306         }
    307         return $result;
    308     }
    309
    310     //"Абстрактный" метод вызова формы оплаты
    311     function getForm(){
    312         user_error("Please implement getForm() on $this->class", E_USER_ERROR);
    313     }
    314
    315     //"Абстрактный" метод обработки платежа
    316     function processPayment($order) {
    317         user_error("Please implement processPayment() on $this->class", E_USER_ERROR);
    318     }
    319 }
    320
    321 class Payment_Handler extends Controller {
    322     static $URLSegment = false;
    323
    324     function pay_link($orderID) {
    325         $class = $this->class;
    326         return Director::absoluteURL($class::$URLSegment . '/pay_order?orderID=' . $orderID);
    327     }
    328
    329     function pay_order() {
    330         if (isset($_GET['orderID'])) {
    331             $orderID = $_GET['orderID'];
    332             if ($order = DataObject::get_one(PaymentMethod::getDefaultPaymentObject(), sprintf("HashLink='%s'", Convert::raw2sql($orderID)))) {
    333                 $paymentMethod = $order->Payments()->Last()->PaymentType();
    334                 $value = false;
    335                 if ($paymentMethod) {
    336                     $link = $paymentMethod->paymentLink();
    337                 }
    338                 return $this->renderWith(
    339                     array('CheckoutPage_done', 'CheckoutPage', 'Page'),
    340                     array('Form' => false, 'Order' => $order, 'PaymentLink' => $link)
    341                 );
    342             }
    343         }
    344         // return not found!!!
    345     }
    346 }
    347
    348 abstract class Payment_Result {
    349
    350     protected $value;
    351
    352     function __construct($value = null) {
    353         $this->value = $value;
    354     }
    355
    356     function getValue() {
    357         return $this->value;
    358     }
    359
    360     abstract function isSuccess();
    361
    362     abstract function isProcessing();
    363
    364 }
    365
    366 class Payment_Success extends Payment_Result {
    367
    368     function isSuccess() {
    369         return true;
    370     }
    371
    372     function isProcessing() {
    373         return false;
    374     }
    375
    376 }
    377
    378 class Payment_Processing extends Payment_Result {
    379
    380     function isSuccess() {
    381         return false;
    382     }
    383
    384     function isProcessing() {
    385         return true;
    386     }
    387
    388 }
    389 class Payment_Failure extends Payment_Result {
    390
    391     function isSuccess() {
    392         return false;
    393     }
    394
    395     function isProcessing() {
    396         return false;
    397     }
    398 }
    399

[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. -