Completed
Push — trunk ( 8e4860...9a1e7c )
by SuperNova.WS
10:52
created

sn_module_payment::getPrice()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 2
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 3
dl 0
loc 2
rs 10
c 0
b 0
f 0
ccs 0
cts 0
cp 0
crap 2
1
<?php
2
3
use DBAL\db_mysql;
4
use Modules\sn_module;
5
6
/**
7
 * User: Gorlum
8
 * Date: 21.04.2015
9
 * Time: 3:49
10
 */
11
abstract class sn_module_payment extends sn_module {
12
  const DO_NOT_REDIRECT = 'DO_NOT_REDIRECT';
13
  const FIELD_SUM = 'SUM';
14
  const FIELD_CURRENCY = 'CURRENCY';
15
16
  public $versionCommitted = '#44a109#';
17
18
  public $active = false;
19
20
  public static $bonus_table = [
21
    2000    => 0,
22
    // 5000 => 0,
23
    10000   => 0,
24
    20000   => 0,
25
    50000   => 0.02,
26
    100000  => 0.05,
27
    200000  => 0.07,
28
    300000  => 0.10,
29
    400000  => 0.15,
30
    500000  => 0.20,
31
    800000  => 0.25,
32
    1000000 => 0.30,
33
    1500000 => 0.40,
34
    2000000 => 0.50,
35
    3000000 => 0.60,
36
    5000000 => 0.70,
37
  ];
38
39
  public static $payment_methods = [
40
    PAYMENT_METHOD_BANK_CARD => [
41
      /*
42
      PAYMENT_METHOD_id => array(
43
        'currency' => 'WMR', // Currency code 3 letter
44
        'image' => 'design/images/payments/emoney/webmoney.png', // Optional - image location from root. Setting image disables buttoning and name printing
45
        'name' => true, // Optional. Forces method name printing with 'image' set
46
        'button' => true, // Optional. Forces method buttoning with 'image' set
47
      ),
48
      */
49
      PAYMENT_METHOD_BANK_CARD_STANDARD         => [
50
        'currency' => 'RUB',
51
        'image'    => 'design/images/payments/card/generic.png',
52
        'button'   => true,
53
      ],
54
      PAYMENT_METHOD_BANK_CARD_LIQPAY           => [
55
        'currency' => 'UAH',
56
        'image'    => 'design/images/payments/card/liqpay.png',
57
        'button'   => true,
58
      ],
59
      PAYMENT_METHOD_BANK_CARD_EASYPAY          => [
60
        'currency' => 'UAH',
61
        'image'    => 'design/images/payments/card/easypay.png',
62
        'button'   => true,
63
      ],
64
      PAYMENT_METHOD_BANK_CARD_AMERICAN_EXPRESS => [
65
        'currency' => 'USD',
66
        'image'    => 'design/images/payments/card/american_express.png',
67
        'button'   => true,
68
      ],
69
      PAYMENT_METHOD_BANK_CARD_JCB              => [
70
        'currency' => 'USD',
71
        'image'    => 'design/images/payments/card/jcb.png',
72
        'button'   => true,
73
      ],
74
      PAYMENT_METHOD_BANK_CARD_UNIONPAY         => [
75
        'currency' => 'USD',
76
        'image'    => 'design/images/payments/card/unionpay.png',
77
        'button'   => true,
78
      ],
79
    ],
80
81
    PAYMENT_METHOD_EMONEY => [
82
      PAYMENT_METHOD_EMONEY_YANDEX       => [
83
        'currency' => 'RUB',
84
        'image'    => 'design/images/payments/emoney/yandexmoney.png',
85
        'button'   => true,
86
      ],
87
      PAYMENT_METHOD_EMONEY_QIWI         => [
88
        'currency' => 'RUB',
89
        'image'    => 'design/images/payments/emoney/qiwi.png',
90
        'button'   => true,
91
      ],
92
      PAYMENT_METHOD_EMONEY_PAYPAL       => [
93
        'currency' => 'RUB',
94
        'image'    => 'design/images/payments/emoney/paypal.png',
95
        'button'   => true,
96
      ],
97
      PAYMENT_METHOD_EMONEY_WEBMONEY_WMR => [
98
//        'currency' => 'WMR',
99
        'currency' => 'RUB',
100
        'image'    => 'design/images/payments/emoney/webmoney_wmr.gif',
101
        'button'   => true,
102
      ],
103
      PAYMENT_METHOD_EMONEY_WEBMONEY_WMZ => [
104
//        'currency' => 'WMZ',
105
        'currency' => 'RUB',
106
        'image'    => 'design/images/payments/emoney/webmoney_wmz.gif',
107
        'button'   => true,
108
      ],
109
      PAYMENT_METHOD_EMONEY_WEBMONEY_WMU => [
110
//        'currency' => 'WMU',
111
        'currency' => 'RUB',
112
        'image'    => 'design/images/payments/emoney/webmoney_wmu.gif',
113
        'button'   => true,
114
      ],
115
      PAYMENT_METHOD_EMONEY_WEBMONEY_WME => [
116
//        'currency' => 'WME',
117
        'currency' => 'RUB',
118
        'image'    => 'design/images/payments/emoney/webmoney_wme.gif',
119
        'button'   => true,
120
      ],
121
      PAYMENT_METHOD_EMONEY_WEBMONEY_WMB => [
122
//        'currency' => 'WMB',
123
        'currency' => 'RUB',
124
        'image'    => 'design/images/payments/emoney/webmoney_wmb.gif',
125
        'button'   => true,
126
      ],
127
      PAYMENT_METHOD_EMONEY_TELEMONEY    => [
128
        'currency' => 'RUB',
129
        'image'    => 'design/images/payments/emoney/telemoney.gif',
130
        'button'   => true,
131
      ],
132
      PAYMENT_METHOD_EMONEY_ELECSNET     => [
133
        'currency' => 'RUB',
134
        'image'    => 'design/images/payments/emoney/elecsnet.png',
135
        'button'   => true,
136
      ],
137
      PAYMENT_METHOD_EMONEY_EASYPAY      => [
138
        'currency' => 'RUB',
139
        'image'    => 'design/images/payments/emoney/easypay.png',
140
        'button'   => true,
141
      ],
142
      PAYMENT_METHOD_EMONEY_RUR_W1R      => [
143
        'currency' => 'RUB',
144
        'image'    => 'design/images/payments/emoney/walletone.png',
145
        'button'   => true,
146
      ],
147
      PAYMENT_METHOD_EMONEY_MAILRU       => [
148
        'currency' => 'RUB',
149
        'image'    => 'design/images/payments/emoney/mailru.gif',
150
      ],
151
    ],
152
153
    PAYMENT_METHOD_MOBILE => [
154
      PAYMENT_METHOD_MOBILE_SMS         => [
155
        'currency' => 'RUB',
156
        'image'    => 'design/images/payments/mobile/sms.png',
157
        'name'     => true,
158
        'button'   => true,
159
      ],
160
      PAYMENT_METHOD_MOBILE_PAYPAL_ZONG => [
161
        'currency' => 'USD',
162
        'image'    => 'design/images/payments/mobile/paypal_zong.png',
163
        'name'     => true,
164
        'button'   => true,
165
      ],
166
      PAYMENT_METHOD_MOBILE_XSOLLA      => [
167
        'currency' => 'RUB',
168
        'image'    => 'design/images/payments/mobile/xsolla.png',
169
        'name'     => true,
170
        'button'   => true,
171
      ],
172
173
174
      PAYMENT_METHOD_MOBILE_MEGAPHONE => [
175
        'currency' => 'RUB',
176
        'image'    => 'design/images/payments/mobile/megafon.png',
177
        'button'   => true,
178
      ],
179
      PAYMENT_METHOD_MOBILE_MTS       => [
180
        'currency' => 'RUB',
181
        'image'    => 'design/images/payments/mobile/mts.png',
182
        'button'   => true,
183
      ],
184
      PAYMENT_METHOD_MOBILE_KYIVSTAR  => [
185
        'currency' => 'UAH',
186
        'image'    => 'design/images/payments/mobile/kyivstar.png',
187
        'button'   => true,
188
      ],
189
    ],
190
191
    PAYMENT_METHOD_BANK_INTERNET => [
192
      PAYMENT_METHOD_BANK_INTERNET_PRIVAT24         => [
193
        'currency' => 'UAH',
194
        'image'    => 'design/images/payments/bank_internet/privat24.png',
195
        'button'   => true,
196
      ],
197
      PAYMENT_METHOD_BANK_INTERNET_BANK24           => [
198
        'currency' => 'UAH',
199
        'image'    => 'design/images/payments/bank_internet/bank24.png',
200
        'button'   => true,
201
      ],
202
      PAYMENT_METHOD_BANK_INTERNET_ALFA_BANK        => [
203
        'currency' => 'RUB',
204
        'image'    => 'design/images/payments/bank_internet/alfa_bank.png',
205
        'button'   => true,
206
      ],
207
      PAYMENT_METHOD_BANK_INTERNET_SBERBANK         => [
208
        'currency' => 'RUB',
209
        'image'    => 'design/images/payments/bank_internet/sberbank.png',
210
        'button'   => true,
211
      ],
212
      PAYMENT_METHOD_BANK_INTERNET_PROSMVYAZBANK    => [
213
        'currency' => 'RUB',
214
        'image'    => 'design/images/payments/bank_internet/prosmvyazbank.png',
215
        'button'   => true,
216
      ],
217
      PAYMENT_METHOD_BANK_INTERNET_HANDY_BANK       => [
218
        'currency' => 'RUB',
219
        'image'    => 'design/images/payments/bank_internet/handy_bank.png',
220
        'button'   => true,
221
      ],
222
      PAYMENT_METHOD_BANK_INTERNET_RUSSKIY_STANDART => [
223
        'currency' => 'RUB',
224
        'image'    => 'design/images/payments/bank_internet/russkiy_standart.gif',
225
      ],
226
      PAYMENT_METHOD_BANK_INTERNET_VTB24            => [
227
        'currency' => 'RUB',
228
        'image'    => 'design/images/payments/bank_internet/vtb24.gif',
229
      ],
230
      PAYMENT_METHOD_BANK_INTERNET_OCEAN_BANK       => [
231
        'currency' => 'RUB',
232
        'image'    => 'design/images/payments/bank_internet/ocean_bank.gif',
233
      ],
234
      PAYMENT_METHOD_BANK_INTERNET_007              => [
235
        'currency' => 'RUB',
236
      ],
237
      PAYMENT_METHOD_BANK_INTERNET_008              => [
238
        'currency' => 'RUB',
239
      ],
240
      PAYMENT_METHOD_BANK_INTERNET_009              => [
241
        'currency' => 'RUB',
242
      ],
243
      PAYMENT_METHOD_BANK_INTERNET_010              => [
244
        'currency' => 'RUB',
245
      ],
246
      PAYMENT_METHOD_BANK_INTERNET_011              => [
247
        'currency' => 'RUB',
248
      ],
249
      PAYMENT_METHOD_BANK_INTERNET_012              => [
250
        'currency' => 'RUB',
251
      ],
252
      PAYMENT_METHOD_BANK_INTERNET_013              => [
253
        'currency' => 'RUB',
254
      ],
255
      PAYMENT_METHOD_BANK_INTERNET_014              => [
256
        'currency' => 'RUB',
257
      ],
258
      PAYMENT_METHOD_BANK_INTERNET_015              => [
259
        'currency' => 'RUB',
260
      ],
261
      PAYMENT_METHOD_BANK_INTERNET_016              => [
262
        'currency' => 'RUB',
263
      ],
264
      PAYMENT_METHOD_BANK_INTERNET_017              => [
265
        'currency' => 'RUB',
266
      ],
267
      PAYMENT_METHOD_BANK_INTERNET_018              => [
268
        'currency' => 'RUB',
269
      ],
270
      PAYMENT_METHOD_BANK_INTERNET_019              => [
271
        'currency' => 'RUB',
272
      ],
273
      PAYMENT_METHOD_BANK_INTERNET_020              => [
274
        'currency' => 'RUB',
275
      ],
276
      PAYMENT_METHOD_BANK_INTERNET_021              => [
277
        'currency' => 'RUB',
278
      ],
279
    ],
280
281
    PAYMENT_METHOD_BANK_TRANSFER => [],
282
283
    PAYMENT_METHOD_TERMINAL => [
284
      PAYMENT_METHOD_TERMINAL_UKRAINE    => [
285
        'currency' => 'UAH',
286
        'image'    => 'design/images/payments/terminal/ukraine.png',
287
        'button'   => true,
288
        'name'     => true,
289
      ],
290
      PAYMENT_METHOD_TERMINAL_IBOX       => [
291
        'currency' => 'UAH',
292
        'image'    => 'design/images/payments/terminal/ibox.png',
293
        'button'   => true,
294
      ],
295
      PAYMENT_METHOD_TERMINAL_EASYPAY    => [
296
        'currency' => 'UAH',
297
        'image'    => 'design/images/payments/terminal/easypay.png',
298
        'button'   => true,
299
      ],
300
      PAYMENT_METHOD_TERMINAL_RUSSIA     => [
301
        'currency' => 'RUB',
302
        'image'    => 'design/images/payments/terminal/russia.png',
303
        'button'   => true,
304
        'name'     => true,
305
      ],
306
      PAYMENT_METHOD_TERMINAL_QIWI       => [
307
        'currency' => 'RUB',
308
        'image'    => 'design/images/payments/terminal/qiwi.png',
309
        'button'   => true,
310
      ],
311
      PAYMENT_METHOD_TERMINAL_ELECSNET   => [
312
        'currency' => 'RUB',
313
        'image'    => 'design/images/payments/terminal/elecsnet.png',
314
        'button'   => true,
315
      ],
316
      PAYMENT_METHOD_TERMINAL_TELEPAY    => [
317
        'currency' => 'RUB',
318
        'image'    => 'design/images/payments/terminal/telepay.png',
319
        'button'   => true,
320
      ],
321
      PAYMENT_METHOD_TERMINAL_ELEMENT    => [
322
        'currency' => 'RUB',
323
        'image'    => 'design/images/payments/terminal/element.gif',
324
      ],
325
      PAYMENT_METHOD_TERMINAL_KASSIRANET => [
326
        'currency' => 'RUB',
327
        'image'    => 'design/images/payments/terminal/kassira_net.gif',
328
        'button'   => true,
329
      ],
330
    ],
331
332
    PAYMENT_METHOD_OTHER => [
333
      PAYMENT_METHOD_OTHER_EVROSET          => [
334
        'currency' => 'RUB',
335
        'image'    => 'design/images/payments/other/evroset.gif',
336
      ],
337
      PAYMENT_METHOD_OTHER_SVYAZNOY         => [
338
        'currency' => 'RUB',
339
        'image'    => 'design/images/payments/other/svyaznoy.gif',
340
      ],
341
      PAYMENT_METHOD_OTHER_ROBOKASSA_MOBILE => [
342
        'currency' => 'RUB',
343
        'image'    => 'design/images/payments/other/robokassa_mobile.gif',
344
        'name'     => true,
345
      ],
346
    ],
347
348
    PAYMENT_METHOD_GENERIC => [
349
      PAYMENT_METHOD_GENERIC_XSOLLA => [
350
        'currency' => 'UAH',
351
        'image'    => 'design/images/payments/generic/xsolla.png',
352
        'name'     => true,
353
        'button'   => true,
354
      ],
355
356
      PAYMENT_METHOD_GENERIC_ROBOKASSA => [
357
        'currency' => 'RUB',
358
        'image'    => 'design/images/payments/generic/robokassa.jpg',
359
        // 'name' => true,
360
        'button'   => true,
361
      ],
362
    ],
363
  ];
364
365
  /**
366
   * @var Account $account
367
   */
368
  public $account = null;
369
370
  /**
371
   * @var db_mysql $db
372
   */
373
  public $db = null;
374
375
  /**
376
   * @var int
377
   */
378
  public $request_payment_id = 0;
379
  /**
380
   * Идентификатор сервера, на который производится оплата
381
   *
382
   * @var string $request_server_id
383
   */
384
  public $request_server_id = '';
385
  /**
386
   * Идентификатор платящего пользователя
387
   *
388
   * @var int
389
   */
390
  public $request_account_id = 0;
391
  /**
392
   * @var int
393
   */
394
  // public $request_mm_amount = 0;
395
  /**
396
   * @var float
397
   */
398
  // public $request_money_out = 0.0;
399
400
  /**
401
   * Внутренний идентификатор платежа
402
   *
403
   * @var int
404
   */
405
  public $payment_id = 0;
406
  public $payment_status = PAYMENT_STATUS_NONE;
407
  public $payment_provider_id = ACCOUNT_PROVIDER_NONE;
408
  public $payment_account_id = 0;
409
  public $payment_account_name = '';
410
  public $payment_user_id = 0;
411
  public $payment_user_name = '';
412
  public $payment_amount = 0;
413
  public $payment_currency = '';
414
  public $payment_dark_matter_paid = 0;
415
  public $payment_dark_matter_gained = 0;
416
  public $payment_date = SN_TIME_SQL;
417
  public $payment_comment = '';
418
  public $payment_module_name = '';
419
420
  public $payment_external_id = '';
421
  public $payment_external_date = '';
422
  public $payment_external_lots = 0;
423
  public $payment_external_amount = 0;
424
  public $payment_external_currency = '';
425
426
  public $payment_test = 0;
427
428
  public $is_exists = false;
429
  public $is_loaded = false;
430
431
  protected $description_generated = array();
432
433
  protected $debug = false;
434
435
  protected $payment_params = array(
436
//    'server_id' => 'shp_server', // Должен быть server_id
437
//    'account_id' => 'shp_id', // Должен быть user_id
438
//    'payment_id' => 'InvId', // Должен быть внутренний payment_id
439
//    'payment_dark_matter_gained' => 'shp_dm', // TODO - Реально - dark_matter_gained! Что бы учитывались акции!
440
//    'payment_external_money' => 'OutSum', // Количество денег "к оплате" от СН
441
//    'test' => 'shp_z_test', // Тестовый статус аккаунта
442
//    'payment_external_id' => '', // ИД платежа в платёжной системе
443
//    'payment_external_currency' => 'payment_currency', // Валюта платежа в платёжной системе
444
  );
445
446
  protected $result_translations = array(
447
    // Универсальный ответ на неизвестную ошибку
448
    SN_PAYMENT_REQUEST_UNDEFINED_ERROR => SN_PAYMENT_REQUEST_UNDEFINED_ERROR,
449
    // Утвердительный ответ
450
    SN_PAYMENT_REQUEST_OK              => SN_PAYMENT_REQUEST_OK,
451
  );
452
453
  /**
454
   * sn_module_payment constructor.
455
   *
456
   * @param string $filename
457
   *
458
   * @throws Exception
459
   */
460
  public function __construct($filename = __FILE__) {
461
    parent::__construct($filename);
462
463
    if (!empty($this->config['debug'])) {
464
      $this->debug = true;
465
    }
466
  }
467
468
  /**
469
   * @param array $data
470
   */
471
  public function debug($data) {
472
    if (!$this->debug) {
473
      return;
474
    }
475
476
    file_put_contents(SN_ROOT_PHYSICAL . '_' . get_called_class() . '_debug.txt', $data, FILE_APPEND);
477
  }
478
479
  /**
480
   * Компилирует запрос к платёжной системе
481
   *
482
   * @param $request
483
   *
484
   * @throws Exception
485
   */
486
  public function compile_request($request) {
487
    global $config, $lang, $user;
488
489
    if (!(SN::$auth->account instanceof Account)) {
0 ignored issues
show
introduced by
SN::auth->account is always a sub-type of Account.
Loading history...
490
      // TODO - throw new Exception($lang['pay_msg_mm_request_amount_invalid'], SN_PAYMENT_REQUEST_ERROR_UNIT_AMOUNT);
491
    }
492
    $this->account = SN::$auth->account;
493
494
    $this->db = $this->account->db;
495
496
    $this->payment_provider_id = core_auth::$main_provider->provider_id;
497
    $this->payment_account_id = $this->account->account_id;
498
    $this->payment_account_name = $this->account->account_name;
499
    $this->payment_user_id = $user['id'];
500
    $this->payment_user_name = $user['username'];
501
502
    // TODO - минимальное количество ММ к оплате
503
    $this->payment_dark_matter_paid = $request['metamatter'];
504
    $this->payment_dark_matter_gained = self::bonus_calculate($this->payment_dark_matter_paid, true);
505
506
    $this->payment_currency = $config->payment_currency_default;
507
    $this->payment_amount = self::currency_convert($this->payment_dark_matter_paid, 'MM_', $this->payment_currency);
508
509
    if (empty($this->payment_external_currency) && !empty($this->config['currency'])) {
510
      $this->payment_external_currency = $this->config['currency'];
511
    }
512
    if (empty($this->payment_external_currency)) {
513
      throw new Exception($lang['pay_error_internal_no_external_currency_set'], SN_PAYMENT_ERROR_INTERNAL_NO_EXTERNAL_CURRENCY_SET);
514
    }
515
516
    $this->payment_external_amount = self::currency_convert($this->payment_dark_matter_paid, 'MM_', $this->payment_external_currency);
517
    if ($this->payment_external_amount < 0.01) {
518
      throw new Exception($lang['pay_msg_mm_request_amount_invalid'], SN_PAYMENT_REQUEST_ERROR_UNIT_AMOUNT);
519
    }
520
521
    $this->payment_test = !empty($this->config['test']);
522
523
    $this->generate_description();
524
525
    $this->db_insert();
526
    if (!$this->is_exists) {
527
      throw new Exception($lang['pay_msg_request_error_db_payment_create'], SN_PAYMENT_REQUEST_DB_ERROR_PAYMENT_CREATE);
528
    }
529
  }
530
531
  /**
532
   * @param array $options
533
   *
534
   * @return array
535
   * @throws Exception
536
   */
537
  // OK 4.8
538
  protected function payment_request_process($options = array()) {
539
    global $lang, $config;
540
541
    if (!$this->active) {
542
      throw new Exception($lang['pay_msg_module_disabled'], SN_MODULE_DISABLED);
543
    }
544
545
    // Если есть payment_id - загружаем под него данные
546
    if (!empty($this->payment_params['payment_id'])) {
547
      $this->request_payment_id = sys_get_param_id($this->payment_params['payment_id']);
0 ignored issues
show
Documentation Bug introduced by
It seems like sys_get_param_id($this->...t_params['payment_id']) can also be of type string. However, the property $request_payment_id is declared as type integer. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
548
      if (!$this->request_payment_id) {
549
        throw new Exception($lang['pay_msg_request_payment_id_invalid'], SN_PAYMENT_REQUEST_INTERNAL_ID_WRONG);
550
      }
551
552
      if (!$this->db_get_by_id($this->request_payment_id)) {
553
        throw new Exception($lang['pay_msg_request_payment_id_invalid'], SN_PAYMENT_REQUEST_INTERNAL_ID_WRONG);
554
      }
555
556
      // Проверяем - был ли этот платеж обработан?
557
      // TODO - Статусы бывают разные. Нужен спецфлаг payment_processed
558
      if ($this->payment_status != PAYMENT_STATUS_NONE && empty($options[self::DO_NOT_REDIRECT])) {
559
        sn_db_transaction_rollback();
560
        sys_redirect(SN_ROOT_VIRTUAL . 'metamatter.php?payment_id=' . $this->payment_id);
561
        die();
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
562
      }
563
    }
564
565
    // Пытаемся получить из запроса ИД аккаунта
566
    $request_account_id = !empty($this->payment_params['account_id']) ? sys_get_param_id($this->payment_params['account_id']) : 0;
567
    // Если в запросе нет ИД аккаунта - пытаемся использовать payment_account_id
568
    if (empty($request_account_id) && !empty($this->payment_account_id)) {
569
      $request_account_id = $this->payment_account_id;
570
    }
571
    // Если теперь у нас нету ИД аккаунта ни в запросе, ни в записи таблицы - можно паниковать
572
    if (empty($request_account_id)) {
573
      // TODO - аккаунт
574
      throw new Exception($lang['pay_msg_request_user_invalid'], $this->retranslate_error(SN_PAYMENT_REQUEST_USER_NOT_FOUND, $options));
575
    }
576
    // Если нет записи в таблице - тогда берем payment_account_id из запроса
577
    if (empty($this->payment_account_id)) {
578
      $this->payment_account_id = $request_account_id;
579
    }
580
    // Если у нас отличаются ИД аккаунта в запросе и ИД аккаунта в записи - тоже можно паниковать
581
    if ($this->payment_account_id != $request_account_id) {
582
      // TODO - Поменять сообщение об ошибке
583
      throw new Exception($lang['pay_msg_request_user_invalid'], $this->retranslate_error(SN_PAYMENT_REQUEST_USER_NOT_FOUND, $options));
584
    }
585
    // Проверяем существование аккаунта с данным ИД
586
    if (!$this->account->db_get_by_id($this->payment_account_id)) {
587
      throw new Exception($lang['pay_msg_request_user_invalid'] . ' ID ' . $this->payment_account_id, $this->retranslate_error(SN_PAYMENT_REQUEST_USER_NOT_FOUND, $options));
588
    }
589
590
    // TODO Проверка на сервер_ид - как бы и не нужна, наверное?
591
    if (!empty($this->payment_params['server_id'])) {
592
      $this->request_server_id = sys_get_param_str($this->payment_params['server_id']);
593
      if (SN_ROOT_VIRTUAL != $this->request_server_id) {
594
        throw new Exception($lang['pay_msg_request_server_wrong'] . " {$this->request_server_id} вместо " . SN_ROOT_VIRTUAL, SN_PAYMENT_REQUEST_SERVER_WRONG);
595
      }
596
    }
597
598
    // Сверка количества оплаченной ММ с учётом бонусов
599
    if (!empty($this->payment_params['payment_dark_matter_gained'])) {
600
      $request_mm_amount = sys_get_param_id($this->payment_params['payment_dark_matter_gained']);
601
      if ($request_mm_amount != $this->payment_dark_matter_gained && $this->is_loaded) {
602
        throw new Exception($lang['pay_msg_mm_request_amount_invalid'] . " пришло {$request_mm_amount} ММ вместо {$this->payment_dark_matter_gained} ММ", SN_PAYMENT_REQUEST_MM_AMOUNT_INVALID);
603
      }
604
      empty($this->payment_dark_matter_gained) ? $this->payment_dark_matter_gained = $request_mm_amount : false;
605
    }
606
    if (empty($this->payment_dark_matter_paid)) {
607
      // TODO - обратный расчёт из gained
608
    }
609
610
    // Проверка наличия внешнего ИД платежа
611
    if (!empty($this->payment_params['payment_external_id'])) {
612
      $request_payment_external_id = sys_get_param_id($this->payment_params['payment_external_id']);
613
      if (empty($request_payment_external_id)) {
614
        throw new exception($lang['pay_msg_request_payment_id_invalid'], SN_PAYMENT_REQUEST_EXTERNAL_ID_WRONG);
615
      } elseif (!empty($this->payment_external_id) && $this->payment_external_id != $request_payment_external_id) {
616
        // TODO - Может быть поменять сообщение
617
        throw new exception($lang['pay_msg_request_payment_id_invalid'], SN_PAYMENT_REQUEST_EXTERNAL_ID_WRONG);
618
      }
619
      $this->payment_external_id = $request_payment_external_id;
620
    }
621
    // Сверка суммы, запрошенной СН к оплате
622
    if (!empty($this->payment_params['payment_external_money'])) {
623
      $request_money_out = sys_get_param_float($this->payment_params['payment_external_money']);
624
      if ($request_money_out != $this->payment_external_amount && $this->is_loaded) {
625
        throw new Exception($lang['pay_msg_request_payment_amount_invalid'] . " пришло {$request_money_out} денег вместо {$this->payment_external_amount} денег", SN_PAYMENT_REQUEST_CURRENCY_AMOUNT_INVALID);
626
      }
627
      empty($this->payment_external_amount) ? $this->payment_external_amount = $request_money_out : false;
628
    }
629
    // Заполняем поле валюты платёжной системы
630
    if (!empty($this->payment_params['payment_external_currency'])) {
631
      $this->payment_external_currency = sys_get_param_str($this->payment_params['payment_external_currency']);
632
      if (empty($this->payment_external_currency)) {
633
        // TODO - поменять сообщение
634
        throw new Exception($lang['pay_msg_request_payment_amount_invalid'] . " {$this->payment_external_currency}", SN_PAYMENT_REQUEST_CURRENCY_AMOUNT_INVALID);
635
      }
636
    }
637
    if (empty($this->payment_external_currency)) {
638
      $this->payment_external_currency = $this->config['currency'];
639
    }
640
641
    // Заполнение внутренней суммы и валюты из внешних данных
642
    if (empty($this->payment_currency)) {
643
      $this->payment_currency = $config->payment_currency_default;
644
    }
645
    if (empty($this->payment_amount) && !empty($this->payment_external_currency)) {
646
      $this->payment_amount = self::currency_convert($this->payment_external_amount, $this->payment_external_currency, $this->payment_currency);
647
    }
648
649
    // TODO - Тестовый режим
650
    if (!empty($this->payment_params['test'])) {
651
      $this->payment_test = $this->config['test'] || sys_get_param_int($this->payment_params['test']);
652
    }
653
654
    $this->generate_description();
655
656
//    // TODO - REMOVE
657
//    return array(
658
//      'payer' => $this->account,
659
//    );
660
  }
661
662
  /**
663
   * Точка входа для коллбэка системы платежей - вызывается из <class_name>_response.php
664
   *
665
   * @return array
666
   */
667
  // OK 4.8
668
  // TODO - Здесь должно происходить разделение на resultURL, successURL, failURL
669
  public function payment_request_response() {
670
    global $debug;
671
672
    $this->db = core_auth::$main_provider->db;
673
    $this->account = new Account($this->db);
674
675
    // TODO - REPLACE WITH INNATE CALL!
676
    sn_db_transaction_start();
677
    try {
678
      $response = $this->payment_request_process();
679
    } catch (Exception $e) {
680
      $response['result'] = $e->getCode();
681
      $response['message'] = $e->getMessage();
682
683
      $this->debug([
684
        "\n",
685
        "Kinda Error!\n",
686
        '$response => ', var_export($response, true),
687
        "\n",
688
      ]);
689
    }
690
691
    if ($response['result'] == SN_PAYMENT_REQUEST_OK) {
692
      sn_db_transaction_commit();
693
      $debug->warning('Результат операции: код ' . $response['result'] . ' сообщение "' . $response['message'] . '"', 'Успешный платёж', LOG_INFO_PAYMENT);
694
    } else {
695
      sn_db_transaction_rollback();
696
      $debug->warning('Результат операции: код ' . $response['result'] . ' сообщение "' . $response['message'] . '"', 'Ошибка платежа', LOG_INFO_PAYMENT, true);
697
    }
698
699
    // Переводим код результата из СН в код платежной системы
700
    if (is_array($this->result_translations) && !empty($this->result_translations)) {
701
      $response['result'] = isset($this->result_translations[$response['result']]) ? $this->result_translations[$response['result']] : $this->result_translations[SN_PAYMENT_REQUEST_UNDEFINED_ERROR];
702
    }
703
704
    return $response;
705
  }
706
707
  /**
708
   *
709
   *
710
   * @param string $payment_method_selected
711
   * @param string $player_currency
712
   * @param integer $metamatter
713
   *
714
   * @return array [self::FIELD_SUM => (float){sum_to_pay}, self::FIELD_CURRENCY => (str){currency_code}]. Currency code is optional. Empty if no data
715
   */
716
  public function getPrice($payment_method_selected, $player_currency, $metamatter) {
0 ignored issues
show
Unused Code introduced by
The parameter $metamatter is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

716
  public function getPrice($payment_method_selected, $player_currency, /** @scrutinizer ignore-unused */ $metamatter) {

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $payment_method_selected is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

716
  public function getPrice(/** @scrutinizer ignore-unused */ $payment_method_selected, $player_currency, $metamatter) {

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $player_currency is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

716
  public function getPrice($payment_method_selected, /** @scrutinizer ignore-unused */ $player_currency, $metamatter) {

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
717
    return [];
718
  }
719
  // Function converts money values between currencies
720
721
  /**
722
   * Внутриигровая конвертация валют
723
   *
724
   * @param        $value
725
   * @param string $currency_from
726
   * @param string $currency_to
727
   * @param int    $round
728
   *
729
   * @return float|int
730
   */
731
  public static function currency_convert($value, $currency_from = '', $currency_to = '', $round = 2) {
732
//    global $config;
733
734
    $currency_from = strtolower($currency_from);
735
    $currency_to = strtolower($currency_to);
736
737
    if ($currency_from != $currency_to) {
738
//      $config_currency_from_name = 'payment_currency_exchange_' . $currency_from;
739
//      $config_currency_to_name = 'payment_currency_exchange_' . $currency_to;
740
741
//      $exchange_from = floatval($currency_from == 'mm_' ? get_mm_cost() : $config->$config_currency_from_name);
742
//      $exchange_to = floatval($currency_to == 'mm_' ? get_mm_cost() : $config->$config_currency_to_name);
743
744
      $exchange_from = get_exchange_rate($currency_from);
745
      $exchange_to = get_exchange_rate($currency_to);
746
747
      $value = $exchange_from ? $value / $exchange_from * $exchange_to * pow(10, $round) : 0;
748
      $value = ceil($value) / pow(10, $round);
749
    }
750
751
    return $value;
752
  }
753
754
  // Function calculates bonused DM amount for bulk purchase and ($direct = false) vice versa
755
756
  /**
757
   * Рассчёт бонуса ММ
758
   *
759
   * @param            $dark_matter
760
   * @param bool|true  $direct
761
   * @param bool|false $return_bonus
762
   *
763
   * @return float|int
764
   */
765
  public static function bonus_calculate($dark_matter, $direct = true, $return_bonus = false) {
766
    $bonus = 0;
767
    $dark_matter_new = $dark_matter;
768
    if (!empty(self::$bonus_table) && $dark_matter >= self::$bonus_table[0]) {
769
      if ($direct) {
770
        foreach (self::$bonus_table as $dm_for_bonus => $multiplier) {
771
          if ($dm_for_bonus <= $dark_matter) {
772
            $dark_matter_new = $dark_matter * (1 + $multiplier);
773
            $bonus = $multiplier;
774
          } else {
775
            break;
776
          }
777
        }
778
      } else {
779
        foreach (self::$bonus_table as $dm_for_bonus => $multiplier) {
780
          $temp = $dm_for_bonus * (1 + $multiplier);
781
          if ($dark_matter >= $temp) {
782
            $dark_matter_new = round($dark_matter / (1 + $multiplier));
783
            $bonus = $multiplier;
784
          } else {
785
            break;
786
          }
787
        }
788
      }
789
    }
790
791
    return $return_bonus ? $bonus : $dark_matter_new;
792
  }
793
794
  // Дополнительная ре-трансляция адреса, если в каком-то случае платежная система ожидает нелогичный ответ
795
  // Пример: иксолла при неправильно заданном пользователе в ордере ожидает НЕПРАВИЛЬНЫЙ_ОРДЕР, а не НЕПРАВИЛЬНЫЙ_ПОЛЬЗОВАТЕЛЬ
796
  function retranslate_error($error_code, $options = array()) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
797
    return isset($options['retranslate_error'][$error_code]) ? $options['retranslate_error'][$error_code] : $error_code;
798
  }
799
800
801
  function db_insert() {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
802
    global $config;
803
804
    $this->payment_test = !empty($this->config['test']) || $this->payment_test;
805
806
    $payment = array(
807
      'payment_module_name' => $this->manifest['name'],
808
809
      'payment_status' => $this->payment_status,
810
      // 'payment_date' => $this->payment_date, // Не нужно
811
812
      'payment_provider_id'  => $this->payment_provider_id,
813
      'payment_account_id'   => $this->payment_account_id,
814
      'payment_account_name' => $this->payment_account_name,
815
      'payment_user_id'      => $this->payment_user_id,
816
      'payment_user_name'    => $this->payment_user_name,
817
818
      'payment_dark_matter_paid'   => $this->payment_dark_matter_paid,
819
      'payment_dark_matter_gained' => $this->payment_dark_matter_gained,
820
821
      'payment_amount'   => $this->payment_amount,
822
      'payment_currency' => $this->payment_currency,
823
824
      'payment_external_id'       => $this->payment_external_id, // TODO
825
      'payment_external_amount'   => $this->payment_external_amount,
826
      'payment_external_currency' => $this->payment_external_currency,
827
      'payment_external_date'     => $this->payment_external_date, // TODO
828
829
      'payment_test' => $this->payment_test ? 1 : 0, // Boolean -> int
830
831
      'payment_comment' => $this->description_generated[PAYMENT_DESCRIPTION_MAX],
832
833
      'payment_external_lots' => $this->payment_dark_matter_paid / get_mm_cost(),
834
    );
835
836
    $replace = false;
837
    if ($this->payment_id) {
838
      $payment['payment_id'] = $this->payment_id;
839
      $replace = true;
840
    }
841
842
    $query = array();
843
    foreach ($payment as $key => $value) {
844
      $value = is_string($value) ? '"' . db_escape($value) . '"' : $value;
845
      $query[] = "`{$key}` = {$value}";
846
    }
847
848
    $this->db->doquery(($replace ? 'REPLACE' : 'INSERT') . ' INTO `{{payment}}` SET ' . implode(',', $query) . ';');
849
850
    return $this->db_get_by_id($this->db->db_insert_id());
851
  }
852
853
854
  function payment_adjust_mm_new() {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
855
    if (!$this->payment_test) {
856
      // Not a test payment. Adding DM to account
857
      $this->account = new Account($this->db);
858
      $this->account->db_get_by_id($this->payment_account_id);
859
      $result = $this->account->metamatter_change(RPG_PURCHASE, $this->payment_dark_matter_gained, $this->payment_comment);
860
      if (!$result) {
861
        throw new Exception('Ошибка начисления ММ', SN_METAMATTER_ERROR_ADJUST);
862
      }
863
    }
864
  }
865
866
  function payment_cancel(&$payment) {
0 ignored issues
show
Unused Code introduced by
The parameter $payment is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

866
  function payment_cancel(/** @scrutinizer ignore-unused */ &$payment) {

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
867
    die('{НЕ РАБОТАЕТ! СООБЩИТЕ АДМИНИСТРАЦИИ!}');
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
868
    global $lang;
0 ignored issues
show
Unused Code introduced by
GlobalNode is not reachable.

This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.

Unreachable code is most often the result of return, die or exit statements that have been added for debug purposes.

function fx() {
    try {
        doSomething();
        return true;
    }
    catch (\Exception $e) {
        return false;
    }

    return false;
}

In the above example, the last return false will never be executed, because a return statement has already been met in every possible execution path.

Loading history...
869
870
    if (!isset($payment['payment_status'])) {
871
      throw new exception($lang['pay_msg_request_payment_not_found'], SN_PAYMENT_REQUEST_ORDER_NOT_FOUND);
872
    }
873
874
    if ($payment['payment_status'] == PAYMENT_STATUS_COMPLETE) {
875
      $safe_comment = db_escape($payment['payment_comment'] = $lang['pay_msg_request_payment_cancelled'] . ' ' . $payment['payment_comment']);
876
877
      if (!$payment['payment_test']) {
878
        $result = $this->account->metamatter_change(RPG_PURCHASE_CANCEL, -$payment['payment_dark_matter_gained'], $payment['payment_comment']);
879
        if (!$result) {
880
          throw new exception('Ошибка начисления ММ', SN_METAMATTER_ERROR_ADJUST);
881
        }
882
      }
883
      $payment['payment_status'] = PAYMENT_STATUS_CANCELED;
884
      doquery("UPDATE {{payment}} SET payment_status = {$payment['payment_status']}, payment_comment = '{$safe_comment}' WHERE payment_id = {$payment['payment_id']};");
0 ignored issues
show
Deprecated Code introduced by
The function doquery() has been deprecated. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

884
      /** @scrutinizer ignore-deprecated */ doquery("UPDATE {{payment}} SET payment_status = {$payment['payment_status']}, payment_comment = '{$safe_comment}' WHERE payment_id = {$payment['payment_id']};");
Loading history...
885
      throw new exception($lang['pay_msg_request_payment_cancel_complete'], SN_PAYMENT_REQUEST_OK);
886
    } elseif ($payment['payment_status'] == PAYMENT_STATUS_CANCELED) {
887
      throw new exception($lang['pay_msg_request_payment_cancelled_already'], SN_PAYMENT_REQUEST_OK);
888
    } elseif ($payment['payment_status'] == PAYMENT_STATUS_NONE) {
889
      throw new exception($lang['pay_msg_request_payment_cancel_not_complete'], SN_PAYMENT_REQUEST_PAYMENT_NOT_COMPLETE);
890
    }
891
  }
892
893
894
  protected function db_get_by_id($payment_id_unsafe) {
895
    $payment_id_internal_safe = $this->db->db_escape($payment_id_unsafe);
896
    $payment = $this->db->doQueryAndFetch(
897
      "SELECT * 
898
      FROM {{payment}} 
899
      WHERE 
900
        `payment_module_name` = '{$this->manifest['name']}' 
901
        AND `payment_id` = '{$payment_id_internal_safe}' 
902
        LIMIT 1 FOR UPDATE;"
903
    );
904
905
    return $this->db_assign_payment($payment);
906
  }
907
908
  protected function db_complete_payment() {
909
    // TODO - поле payment_processed
910
    if ($this->payment_status == PAYMENT_STATUS_NONE) {
911
      if (!defined('PAYMENT_EXPIRE_TIME') || PAYMENT_EXPIRE_TIME == 0 || empty($this->payment_date) || strtotime($this->payment_date) + PAYMENT_EXPIRE_TIME <= SN_TIME_NOW) {
0 ignored issues
show
introduced by
The condition PAYMENT_EXPIRE_TIME == 0 is always true.
Loading history...
912
        $this->payment_adjust_mm_new();
913
        $this->payment_status = PAYMENT_STATUS_COMPLETE;
914
      } else {
915
        $this->payment_status = PAYMENT_STATUS_EXPIRED;
916
      }
917
918
      $this->db_insert();
919
    }
920
  }
921
922
  protected function payment_reset() {
923
    $this->payment_id = 0;
924
    $this->payment_status = PAYMENT_STATUS_NONE;
925
926
    $this->payment_provider_id = ACCOUNT_PROVIDER_NONE;
927
    $this->payment_account_id = 0;
928
    $this->payment_account_name = '';
929
    $this->payment_user_id = 0;
930
    $this->payment_user_name = '';
931
932
    $this->payment_amount = 0;
933
    $this->payment_currency = '';
934
935
    $this->payment_dark_matter_paid = 0;
936
    $this->payment_dark_matter_gained = 0;
937
    $this->payment_date = SN_TIME_SQL;
938
    $this->payment_comment = '';
939
    $this->payment_module_name = '';
940
941
    $this->payment_external_id = '';
942
    $this->payment_external_date = '';
943
    $this->payment_external_lots = 0;
944
    $this->payment_external_amount = 0;
945
    $this->payment_external_currency = '';
946
947
    $this->payment_test = 0;
948
949
    $this->is_exists = false;
950
    $this->is_loaded = false;
951
952
    $this->description_generated = array();
953
  }
954
955
  protected function db_assign_payment($payment = null) {
956
    $this->payment_reset();
957
958
    if (is_array($payment) && isset($payment['payment_id'])) {
959
      $this->payment_id = $payment['payment_id'];
960
      $this->payment_status = $payment['payment_status'];
961
      $this->payment_date = $payment['payment_date'];
962
963
      $this->payment_provider_id = $payment['payment_provider_id'];
964
      $this->payment_account_id = $payment['payment_account_id'];
965
      $this->payment_account_name = $payment['payment_account_name'];
966
      $this->payment_user_id = $payment['payment_user_id'];
967
      $this->payment_user_name = $payment['payment_user_name'];
968
969
      $this->payment_amount = $payment['payment_amount'];
970
      $this->payment_currency = $payment['payment_currency'];
971
972
      $this->payment_dark_matter_paid = $payment['payment_dark_matter_paid'];
973
      $this->payment_dark_matter_gained = $payment['payment_dark_matter_gained'];
974
975
      $this->payment_comment = $payment['payment_comment'];
976
      $this->payment_module_name = $payment['payment_module_name'];
977
978
      $this->payment_external_id = $payment['payment_external_id'];
979
      $this->payment_external_date = $payment['payment_external_date'];
980
      $this->payment_external_lots = $payment['payment_external_lots'];
981
      $this->payment_external_amount = $payment['payment_external_amount'];
982
      $this->payment_external_currency = $payment['payment_external_currency'];
983
984
      $this->payment_test = $payment['payment_test'];
985
986
      $this->is_exists = true;
987
      $this->is_loaded = true;
988
989
      $this->generate_description();
990
991
      return true;
992
    } else {
993
      return false;
994
    }
995
  }
996
997
  protected function generate_description() {
998
    // TODO - системная локализация
999
    $this->description_generated = array(
1000
      PAYMENT_DESCRIPTION_100 => substr("{$this->payment_dark_matter_gained} ММ аккаунт [{$this->account->account_name}] ID {$this->account->account_id} на " . SN_ROOT_VIRTUAL, 0, 100),
1001
      PAYMENT_DESCRIPTION_250 => substr("Оплата {$this->payment_dark_matter_gained} ММ для аккаунта [{$this->payment_user_name}] ID {$this->payment_user_id} на сервере " . SN_ROOT_VIRTUAL, 0, 250),
1002
      PAYMENT_DESCRIPTION_MAX => ($this->payment_test ? "ТЕСТОВЫЙ ПЛАТЕЖ! " : '') .
1003
        "Платеж от аккаунта '{$this->payment_account_name}' ID {$this->payment_account_id} игрока '{$this->payment_user_name}' ID {$this->payment_user_id} на сервере " . SN_ROOT_VIRTUAL .
1004
        " сумма {$this->payment_amount} {$this->payment_currency} за {$this->payment_dark_matter_paid} ММ (начислено {$this->payment_dark_matter_gained} ММ)" .
1005
        " через '{$this->manifest['name']}' сумма {$this->payment_external_amount} {$this->payment_external_currency}",
1006
    );
1007
  }
1008
1009
}
1010