Issues (1369)

classes/sn_module_payment.php (10 issues)

1
<?php
2
3
use DBAL\db_mysql;
4
use Modules\sn_module;
5
use Payment\PaymentMethods;
6
7
/**
8
 * User: Gorlum
9
 * Date: 21.04.2015
10
 * Time: 3:49
11
 */
12
abstract class sn_module_payment extends sn_module {
13
  const DO_NOT_REDIRECT = 'DO_NOT_REDIRECT';
14
  const FIELD_SUM = 'SUM';
15
  const FIELD_CURRENCY = 'CURRENCY';
16
17
  public $versionCommitted = '#46a151#';
18
19
  public $active = false;
20
21
  public static $bonus_table = [
22
    2000    => 0,
23
    // 5000 => 0,
24
    10000   => 0,
25
    20000   => 0,
26
    50000   => 0.02,
27
    100000  => 0.05,
28
    200000  => 0.07,
29
    300000  => 0.10,
30
    400000  => 0.15,
31
    500000  => 0.20,
32
    800000  => 0.25,
33
    1000000 => 0.30,
34
    1500000 => 0.40,
35
    2000000 => 0.50,
36
    3000000 => 0.60,
37
    5000000 => 0.70,
38
  ];
39
40
  /**
41
   * @var Account $account
42
   */
43
  public $account = null;
44
45
  /**
46
   * @var db_mysql $db
47
   */
48
  public $db = null;
49
50
  /**
51
   * @var int
52
   */
53
  public $request_payment_id = 0;
54
  /**
55
   * Идентификатор сервера, на который производится оплата
56
   *
57
   * @var string $request_server_id
58
   */
59
  public $request_server_id = '';
60
  /**
61
   * Идентификатор платящего пользователя
62
   *
63
   * @var int
64
   */
65
  public $request_account_id = 0;
66
  /**
67
   * @var int
68
   */
69
  // public $request_mm_amount = 0;
70
  /**
71
   * @var float
72
   */
73
  // public $request_money_out = 0.0;
74
75
  /**
76
   * Внутренний идентификатор платежа
77
   *
78
   * @var int
79
   */
80
  public $payment_id = 0;
81
  public $payment_status = PAYMENT_STATUS_NONE;
82
  public $payment_provider_id = ACCOUNT_PROVIDER_NONE;
83
  public $payment_account_id = 0;
84
  public $payment_account_name = '';
85
  public $payment_user_id = 0;
86
  public $payment_user_name = '';
87
  public $payment_amount = 0;
88
  public $payment_currency = '';
89
  public $payment_dark_matter_paid = 0;
90
  public $payment_dark_matter_gained = 0;
91
  public $payment_date = SN_TIME_SQL;
92
  public $payment_comment = '';
93
  public $payment_module_name = '';
94
95
  public $payment_external_id = '';
96
  public $payment_external_date = '';
97
  public $payment_external_lots = 0;
98
  public $payment_external_amount = 0;
99
  public $payment_external_currency = '';
100
101
  public $payment_method = null;
102
103
  public $payment_test = 0;
104
105
  public $is_exists = false;
106
  public $is_loaded = false;
107
108
  protected $description_generated = array();
109
110
  protected $debug = false;
111
112
  protected $payment_params = array(
113
//    'server_id' => 'shp_server', // Должен быть server_id
114
//    'account_id' => 'shp_id', // Должен быть user_id
115
//    'payment_id' => 'InvId', // Должен быть внутренний payment_id
116
//    'payment_dark_matter_gained' => 'shp_dm', // TODO - Реально - dark_matter_gained! Что бы учитывались акции!
117
//    'payment_external_money' => 'OutSum', // Количество денег "к оплате" от СН
118
//    'test' => 'shp_z_test', // Тестовый статус аккаунта
119
//    'payment_external_id' => '', // ИД платежа в платёжной системе
120
//    'payment_external_currency' => 'payment_currency', // Валюта платежа в платёжной системе
121
  );
122
123
  protected $result_translations = array(
124
    // Универсальный ответ на неизвестную ошибку
125
    SN_PAYMENT_REQUEST_UNDEFINED_ERROR => SN_PAYMENT_REQUEST_UNDEFINED_ERROR,
126
    // Утвердительный ответ
127
    SN_PAYMENT_REQUEST_OK              => SN_PAYMENT_REQUEST_OK,
128
  );
129
130
  /**
131
   * sn_module_payment constructor.
132
   *
133
   * @param string $filename
134
   *
135
   * @throws Exception
136
   */
137
  public function __construct($filename = __FILE__) {
138
    parent::__construct($filename);
139
140
    if (!empty($this->config['debug'])) {
141
      $this->debug = true;
142
    }
143
  }
144
145
  /**
146
   * @param array $data
147
   */
148
  public function debug($data) {
149
    if (!$this->debug) {
150
      return;
151
    }
152
153
    file_put_contents(SN_ROOT_PHYSICAL . '_' . get_called_class() . '_debug.txt', $data, FILE_APPEND);
154
  }
155
156
  /**
157
   * Компилирует запрос к платёжной системе
158
   *
159
   * @param $request
160
   *
161
   * @throws Exception
162
   */
163
  public function compile_request($request, $payment_method_selected) {
164
    global $config, $lang, $user;
165
166
//    if (!(SN::$auth->account instanceof Account)) {
167
//      // TODO - throw new Exception($lang['pay_msg_mm_request_amount_invalid'], SN_PAYMENT_REQUEST_ERROR_UNIT_AMOUNT);
168
//    }
169
    $this->account = SN::$auth->account;
170
171
    $this->db = $this->account->db;
172
173
    $this->payment_provider_id  = core_auth::$main_provider->provider_id;
174
    $this->payment_account_id   = $this->account->account_id;
175
    $this->payment_account_name = $this->account->account_name;
176
    $this->payment_user_id      = $user['id'];
177
    $this->payment_user_name    = $user['username'];
178
179
    // TODO - минимальное количество ММ к оплате
180
    $this->payment_dark_matter_paid   = $request['metamatter'];
181
    $this->payment_dark_matter_gained = self::bonus_calculate($this->payment_dark_matter_paid, true);
182
183
    $this->payment_currency = $config->payment_currency_default;
184
    $this->payment_amount   = self::currency_convert($this->payment_dark_matter_paid, 'MM_', $this->payment_currency);
185
186
    $this->payment_method = $payment_method_selected;
187
    if (empty($this->payment_external_currency)) {
188
      $this->payment_external_currency = $this->getMethodCurrency($this->payment_method);
189
    }
190
    if (empty($this->payment_external_currency) && !empty($this->config['currency'])) {
191
      $this->payment_external_currency = $this->config['currency'];
192
    }
193
    if (empty($this->payment_external_currency)) {
194
      throw new Exception($lang['pay_error_internal_no_external_currency_set'], SN_PAYMENT_ERROR_INTERNAL_NO_EXTERNAL_CURRENCY_SET);
195
    }
196
197
    $this->payment_external_amount = self::currency_convert($this->payment_dark_matter_paid, 'MM_', $this->payment_external_currency);
198
    if ($this->payment_external_amount < 0.01) {
199
      throw new Exception($lang['pay_msg_mm_request_amount_invalid'], SN_PAYMENT_REQUEST_ERROR_UNIT_AMOUNT);
200
    }
201
202
    $this->payment_test = !empty($this->config['test']);
203
204
    $this->generate_description();
205
206
    $this->db_insert();
207
    if (!$this->is_exists) {
208
      throw new Exception($lang['pay_msg_request_error_db_payment_create'], SN_PAYMENT_REQUEST_DB_ERROR_PAYMENT_CREATE);
209
    }
210
  }
211
212
  /**
213
   * @param array $options
214
   *
215
   * @return array
216
   * @throws Exception
217
   */
218
  protected function payment_request_process($options = []) {
219
    global $lang, $config;
220
221
    if (!$this->active) {
222
      throw new Exception($lang['pay_msg_module_disabled'], SN_MODULE_DISABLED);
223
    }
224
225
    // Если есть payment_id - загружаем под него данные
226
    if (!empty($this->payment_params['payment_id'])) {
227
      $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...
228
      if (!$this->request_payment_id) {
229
        throw new Exception($lang['pay_msg_request_payment_id_invalid'], SN_PAYMENT_REQUEST_INTERNAL_ID_WRONG);
230
      }
231
232
      if (!$this->db_get_by_id($this->request_payment_id)) {
233
        throw new Exception($lang['pay_msg_request_payment_id_invalid'], SN_PAYMENT_REQUEST_INTERNAL_ID_WRONG);
234
      }
235
236
      // Проверяем - был ли этот платеж обработан?
237
      // TODO - Статусы бывают разные. Нужен спецфлаг payment_processed
238
      if ($this->payment_status != PAYMENT_STATUS_NONE && empty($options[self::DO_NOT_REDIRECT])) {
239
        db_mysql::db_transaction_rollback();
240
        sys_redirect(SN_ROOT_VIRTUAL . 'metamatter.php?payment_id=' . $this->payment_id);
241
        die();
0 ignored issues
show
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...
242
      }
243
    }
244
245
    // Пытаемся получить из запроса ИД аккаунта
246
    $request_account_id = !empty($this->payment_params['account_id']) ? sys_get_param_id($this->payment_params['account_id']) : 0;
247
    // Если в запросе нет ИД аккаунта - пытаемся использовать payment_account_id
248
    if (empty($request_account_id) && !empty($this->payment_account_id)) {
249
      $request_account_id = $this->payment_account_id;
250
    }
251
    // Если теперь у нас нету ИД аккаунта ни в запросе, ни в записи таблицы - можно паниковать
252
    if (empty($request_account_id)) {
253
      // TODO - аккаунт
254
      throw new Exception($lang['pay_msg_request_user_invalid'], $this->retranslate_error(SN_PAYMENT_REQUEST_USER_NOT_FOUND, $options));
255
    }
256
    // Если нет записи в таблице - тогда берем payment_account_id из запроса
257
    if (empty($this->payment_account_id)) {
258
      $this->payment_account_id = $request_account_id;
259
    }
260
    // Если у нас отличаются ИД аккаунта в запросе и ИД аккаунта в записи - тоже можно паниковать
261
    if ($this->payment_account_id != $request_account_id) {
262
      // TODO - Поменять сообщение об ошибке
263
      throw new Exception($lang['pay_msg_request_user_invalid'], $this->retranslate_error(SN_PAYMENT_REQUEST_USER_NOT_FOUND, $options));
264
    }
265
    // Проверяем существование аккаунта с данным ИД
266
    if (!$this->account->db_get_by_id($this->payment_account_id)) {
267
      throw new Exception($lang['pay_msg_request_user_invalid'] . ' ID ' . $this->payment_account_id, $this->retranslate_error(SN_PAYMENT_REQUEST_USER_NOT_FOUND, $options));
268
    }
269
270
    // TODO Проверка на сервер_ид - как бы и не нужна, наверное?
271
    if (!empty($this->payment_params['server_id'])) {
272
      $this->request_server_id = sys_get_param_str($this->payment_params['server_id']);
273
      if (SN_ROOT_VIRTUAL != $this->request_server_id) {
274
        throw new Exception($lang['pay_msg_request_server_wrong'] . " {$this->request_server_id} вместо " . SN_ROOT_VIRTUAL, SN_PAYMENT_REQUEST_SERVER_WRONG);
275
      }
276
    }
277
278
    // Сверка количества оплаченной ММ с учётом бонусов
279
    if (!empty($this->payment_params['payment_dark_matter_gained'])) {
280
      $request_mm_amount = sys_get_param_id($this->payment_params['payment_dark_matter_gained']);
281
      if ($request_mm_amount != $this->payment_dark_matter_gained && $this->is_loaded) {
282
        throw new Exception($lang['pay_msg_mm_request_amount_invalid'] . " пришло {$request_mm_amount} ММ вместо {$this->payment_dark_matter_gained} ММ", SN_PAYMENT_REQUEST_MM_AMOUNT_INVALID);
283
      }
284
      empty($this->payment_dark_matter_gained) ? $this->payment_dark_matter_gained = $request_mm_amount : false;
285
    }
286
//    if (empty($this->payment_dark_matter_paid)) {
287
//      // TODO - обратный расчёт из gained
288
//    }
289
290
    // Проверка наличия внешнего ИД платежа
291
    if (!empty($this->payment_params['payment_external_id'])) {
292
      $request_payment_external_id = sys_get_param_str($this->payment_params['payment_external_id']);
293
      if (empty($request_payment_external_id)) {
294
        throw new exception($lang['pay_msg_request_payment_id_invalid'], SN_PAYMENT_REQUEST_EXTERNAL_ID_WRONG);
295
      } elseif (!empty($this->payment_external_id) && $this->payment_external_id != $request_payment_external_id) {
296
        // TODO - Может быть поменять сообщение
297
        throw new exception($lang['pay_msg_request_payment_id_invalid'], SN_PAYMENT_REQUEST_EXTERNAL_ID_WRONG);
298
      }
299
      $this->payment_external_id = $request_payment_external_id;
300
    }
301
    // Сверка суммы, запрошенной СН к оплате
302
    if (!empty($this->payment_params['payment_external_money'])) {
303
      $request_money_out = sys_get_param_float($this->payment_params['payment_external_money']);
304
      if ($request_money_out != $this->payment_external_amount && $this->is_loaded) {
305
        throw new Exception($lang['pay_msg_request_payment_amount_invalid'] . " пришло {$request_money_out} денег вместо {$this->payment_external_amount} денег", SN_PAYMENT_REQUEST_CURRENCY_AMOUNT_INVALID);
306
      }
307
      empty($this->payment_external_amount) ? $this->payment_external_amount = $request_money_out : false;
308
    }
309
    // Заполняем поле валюты платёжной системы
310
    if (!empty($this->payment_params['payment_external_currency'])) {
311
      $this->payment_external_currency = sys_get_param_str($this->payment_params['payment_external_currency']);
312
      if (empty($this->payment_external_currency)) {
313
        // TODO - поменять сообщение
314
        throw new Exception($lang['pay_msg_request_payment_amount_invalid'] . " {$this->payment_external_currency}", SN_PAYMENT_REQUEST_CURRENCY_AMOUNT_INVALID);
315
      }
316
    }
317
    if (empty($this->payment_external_currency)) {
318
      $this->payment_external_currency = $this->config['currency'];
319
    }
320
321
    // Заполнение внутренней суммы и валюты из внешних данных
322
    if (empty($this->payment_currency)) {
323
      $this->payment_currency = $config->payment_currency_default;
324
    }
325
    if (empty($this->payment_amount) && !empty($this->payment_external_currency)) {
326
      $this->payment_amount = self::currency_convert($this->payment_external_amount, $this->payment_external_currency, $this->payment_currency);
327
    }
328
329
    // TODO - Тестовый режим
330
    if (!empty($this->payment_params['test'])) {
331
      $this->payment_test = $this->config['test'] || sys_get_param_int($this->payment_params['test']);
332
    }
333
334
    $this->generate_description();
335
  }
336
337
  /**
338
   * Точка входа для коллбэка системы платежей - вызывается из <class_name>_response.php
339
   *
340
   * @return array
341
   */
342
  // OK 4.8
343
  // TODO - Здесь должно происходить разделение на resultURL, successURL, failURL
344
  public function payment_request_response() {
345
    global $debug;
346
347
    $this->db      = core_auth::$main_provider->db;
348
    $this->account = new Account($this->db);
349
350
    // TODO - REPLACE WITH INNATE CALL!
351
    db_mysql::db_transaction_start();
352
    try {
353
      $response = $this->payment_request_process();
354
    } catch (Exception $e) {
355
      $response['result']  = $e->getCode();
356
      $response['message'] = $e->getMessage();
357
358
      $this->debug([
359
        "\n",
360
        "Kinda Error!\n",
361
        '$response => ', var_export($response, true),
362
        "\n",
363
      ]);
364
    }
365
366
    if ($response['result'] == SN_PAYMENT_REQUEST_OK) {
367
      db_mysql::db_transaction_commit();
368
      $debug->warning('Результат операции: код ' . $response['result'] . ' сообщение "' . $response['message'] . '"', 'Успешный платёж', LOG_INFO_PAYMENT);
369
    } else {
370
      db_mysql::db_transaction_rollback();
371
      $debug->warning('Результат операции: код ' . $response['result'] . ' сообщение "' . $response['message'] . '"', 'Ошибка платежа', LOG_INFO_PAYMENT, true);
372
    }
373
374
    // Переводим код результата из СН в код платежной системы
375
    if (is_array($this->result_translations) && !empty($this->result_translations)) {
376
      $response['result'] = isset($this->result_translations[$response['result']]) ? $this->result_translations[$response['result']] : $this->result_translations[SN_PAYMENT_REQUEST_UNDEFINED_ERROR];
377
    }
378
379
    return $response;
380
  }
381
382
  /**
383
   *
384
   *
385
   * @param string  $payment_method_selected
386
   * @param string  $player_currency
387
   * @param integer $metamatter
388
   *
389
   * @return array [self::FIELD_SUM => (float){sum_to_pay}, self::FIELD_CURRENCY => (str){currency_code}]. Currency code is optional. Empty if no data
390
   */
391
  public function getPrice($payment_method_selected, $player_currency, $metamatter) {
0 ignored issues
show
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

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

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

391
  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...
392
    return [];
393
  }
394
  // Function converts money values between currencies
395
396
  /**
397
   * Внутриигровая конвертация валют
398
   *
399
   * @param        $value
400
   * @param string $currency_from
401
   * @param string $currency_to
402
   * @param int    $round
403
   *
404
   * @return float|int
405
   */
406
  public static function currency_convert($value, $currency_from = '', $currency_to = '', $round = 2) {
407
//    global $config;
408
409
    $currency_from = strtolower($currency_from);
410
    $currency_to   = strtolower($currency_to);
411
412
    if ($currency_from != $currency_to) {
413
//      $config_currency_from_name = 'payment_currency_exchange_' . $currency_from;
414
//      $config_currency_to_name = 'payment_currency_exchange_' . $currency_to;
415
416
//      $exchange_from = floatval($currency_from == 'mm_' ? get_mm_cost() : $config->$config_currency_from_name);
417
//      $exchange_to = floatval($currency_to == 'mm_' ? get_mm_cost() : $config->$config_currency_to_name);
418
419
      $exchange_from = get_exchange_rate($currency_from);
420
      $exchange_to   = get_exchange_rate($currency_to);
421
422
      $value = $exchange_from ? $value / $exchange_from * $exchange_to * pow(10, $round) : 0;
423
      $value = ceil($value) / pow(10, $round);
424
    }
425
426
    return $value;
427
  }
428
429
  // Function calculates bonused DM amount for bulk purchase and ($direct = false) vice versa
430
431
  /**
432
   * Рассчёт бонуса ММ
433
   *
434
   * @param            $dark_matter
435
   * @param bool|true  $direct
436
   * @param bool|false $return_bonus
437
   *
438
   * @return float|int
439
   */
440
  public static function bonus_calculate($dark_matter, $direct = true, $return_bonus = false) {
441
    $bonus           = 0;
442
    $dark_matter_new = $dark_matter;
443
    if (!empty(self::$bonus_table) && $dark_matter >= self::$bonus_table[0]) {
444
      if ($direct) {
445
        foreach (self::$bonus_table as $dm_for_bonus => $multiplier) {
446
          if ($dm_for_bonus <= $dark_matter) {
447
            $dark_matter_new = $dark_matter * (1 + $multiplier);
448
            $bonus           = $multiplier;
449
          } else {
450
            break;
451
          }
452
        }
453
      } else {
454
        foreach (self::$bonus_table as $dm_for_bonus => $multiplier) {
455
          $temp = $dm_for_bonus * (1 + $multiplier);
456
          if ($dark_matter >= $temp) {
457
            $dark_matter_new = round($dark_matter / (1 + $multiplier));
458
            $bonus           = $multiplier;
459
          } else {
460
            break;
461
          }
462
        }
463
      }
464
    }
465
466
    return $return_bonus ? $bonus : $dark_matter_new;
467
  }
468
469
  // Дополнительная ре-трансляция адреса, если в каком-то случае платежная система ожидает нелогичный ответ
470
  // Пример: иксолла при неправильно заданном пользователе в ордере ожидает НЕПРАВИЛЬНЫЙ_ОРДЕР, а не НЕПРАВИЛЬНЫЙ_ПОЛЬЗОВАТЕЛЬ
471
  protected function retranslate_error($error_code, $options = array()) {
472
    return isset($options['retranslate_error'][$error_code]) ? $options['retranslate_error'][$error_code] : $error_code;
473
  }
474
475
476
  protected function db_insert() {
477
    $this->payment_test = !empty($this->config['test']) || $this->payment_test;
478
479
    $payment = array(
480
      'payment_module_name' => $this->manifest['name'],
481
482
      'payment_status' => $this->payment_status,
483
      // 'payment_date' => $this->payment_date, // Не нужно
484
485
      'payment_provider_id'  => $this->payment_provider_id,
486
      'payment_account_id'   => $this->payment_account_id,
487
      'payment_account_name' => $this->payment_account_name,
488
      'payment_user_id'      => $this->payment_user_id,
489
      'payment_user_name'    => $this->payment_user_name,
490
491
      'payment_dark_matter_paid'   => $this->payment_dark_matter_paid,
492
      'payment_dark_matter_gained' => $this->payment_dark_matter_gained,
493
494
      'payment_amount'   => $this->payment_amount,
495
      'payment_currency' => $this->payment_currency,
496
497
      'payment_external_id'       => $this->payment_external_id, // TODO
498
      'payment_external_amount'   => $this->payment_external_amount,
499
      'payment_external_currency' => $this->payment_external_currency,
500
      'payment_external_date'     => $this->payment_external_date, // TODO
501
502
      'payment_test' => $this->payment_test ? 1 : 0, // Boolean -> int
503
504
      'payment_comment' => $this->description_generated[PAYMENT_DESCRIPTION_MAX],
505
506
      'payment_external_lots' => $this->payment_dark_matter_paid / get_mm_cost(),
507
508
      'payment_method_id' => $this->payment_method,
509
    );
510
511
    $replace = false;
512
    if ($this->payment_id) {
513
      $payment['payment_id'] = $this->payment_id;
514
      $replace               = true;
515
    }
516
517
    $query = array();
518
    foreach ($payment as $key => $value) {
519
      if ($value === null) {
520
        $value = 'NULL';
521
      } else {
522
        $value = is_string($value) ? '"' . SN::$db->db_escape($value) . '"' : $value;
523
      }
524
      $query[] = "`{$key}` = {$value}";
525
    }
526
527
    $this->db->doquery(($replace ? 'REPLACE' : 'INSERT') . ' INTO `{{payment}}` SET ' . implode(',', $query) . ';');
528
529
    return $this->db_get_by_id($this->db->db_insert_id());
530
  }
531
532
  /**
533
   * Get currency that module support for method
534
   *
535
   * @param $paymentMethod
536
   *
537
   * @return string
538
   */
539
  public function getMethodCurrency($paymentMethod) {
540
    // Generally each module can support range of currencies and override this method
541
    // This is just a plug to route requests by default
542
    return PaymentMethods::getDefaultCurrency($paymentMethod);
543
  }
544
545
546
  /**
547
   * @throws Exception
548
   */
549
  protected function payment_adjust_mm_new() {
550
    if (!$this->payment_test) {
551
      // Not a test payment. Adding DM to account
552
      $this->account = new Account($this->db);
553
      $this->account->db_get_by_id($this->payment_account_id);
554
      $result = $this->account->metamatter_change(RPG_PURCHASE, $this->payment_dark_matter_gained, $this->payment_comment);
555
      if (!$result) {
556
        throw new Exception('Ошибка начисления ММ', SN_METAMATTER_ERROR_ADJUST);
557
      }
558
    }
559
  }
560
561
  /**
562
   * @param $payment
563
   *
564
   * @throws exception
565
   */
566
  function payment_cancel(/** @noinspection PhpUnusedParameterInspection */ &$payment) {
0 ignored issues
show
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...
567
    die('{НЕ РАБОТАЕТ! СООБЩИТЕ АДМИНИСТРАЦИИ!}');
0 ignored issues
show
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...
568
    global $lang;
0 ignored issues
show
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...
569
570
    if (!isset($payment['payment_status'])) {
571
      throw new exception($lang['pay_msg_request_payment_not_found'], SN_PAYMENT_REQUEST_ORDER_NOT_FOUND);
572
    }
573
574
    if ($payment['payment_status'] == PAYMENT_STATUS_COMPLETE) {
575
      $safe_comment = SN::$db->db_escape($payment['payment_comment'] = $lang['pay_msg_request_payment_cancelled'] . ' ' . $payment['payment_comment']);
576
577
      if (!$payment['payment_test']) {
578
        $result = $this->account->metamatter_change(RPG_PURCHASE_CANCEL, -$payment['payment_dark_matter_gained'], $payment['payment_comment']);
579
        if (!$result) {
580
          throw new exception('Ошибка начисления ММ', SN_METAMATTER_ERROR_ADJUST);
581
        }
582
      }
583
      $payment['payment_status'] = PAYMENT_STATUS_CANCELED;
584
      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

584
      /** @scrutinizer ignore-deprecated */ doquery("UPDATE {{payment}} SET payment_status = {$payment['payment_status']}, payment_comment = '{$safe_comment}' WHERE payment_id = {$payment['payment_id']};");
Loading history...
585
      throw new exception($lang['pay_msg_request_payment_cancel_complete'], SN_PAYMENT_REQUEST_OK);
586
    } elseif ($payment['payment_status'] == PAYMENT_STATUS_CANCELED) {
587
      throw new exception($lang['pay_msg_request_payment_cancelled_already'], SN_PAYMENT_REQUEST_OK);
588
    } elseif ($payment['payment_status'] == PAYMENT_STATUS_NONE) {
589
      throw new exception($lang['pay_msg_request_payment_cancel_not_complete'], SN_PAYMENT_REQUEST_PAYMENT_NOT_COMPLETE);
590
    }
591
  }
592
593
594
  protected function db_get_by_id($payment_id_unsafe) {
595
    $payment_id_internal_safe = $this->db->db_escape($payment_id_unsafe);
596
    $payment                  = $this->db->doQueryAndFetch(
597
      "SELECT * 
598
      FROM {{payment}} 
599
      WHERE 
600
        `payment_module_name` = '{$this->manifest['name']}' 
601
        AND `payment_id` = '{$payment_id_internal_safe}' 
602
        LIMIT 1 FOR UPDATE;"
603
    );
604
605
    return $this->db_assign_payment($payment);
606
  }
607
608
  /**
609
   * @throws Exception
610
   */
611
  protected function db_complete_payment() {
612
    // TODO - поле payment_processed
613
    if ($this->payment_status == PAYMENT_STATUS_NONE) {
614
      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
The condition PAYMENT_EXPIRE_TIME == 0 is always true.
Loading history...
615
        $this->payment_adjust_mm_new();
616
        $this->payment_status = PAYMENT_STATUS_COMPLETE;
617
      } else {
618
        $this->payment_status = PAYMENT_STATUS_EXPIRED;
619
      }
620
621
      $this->db_insert();
622
    }
623
  }
624
625
  protected function payment_reset() {
626
    $this->payment_id     = 0;
627
    $this->payment_status = PAYMENT_STATUS_NONE;
628
629
    $this->payment_provider_id  = ACCOUNT_PROVIDER_NONE;
630
    $this->payment_account_id   = 0;
631
    $this->payment_account_name = '';
632
    $this->payment_user_id      = 0;
633
    $this->payment_user_name    = '';
634
635
    $this->payment_amount   = 0;
636
    $this->payment_currency = '';
637
638
    $this->payment_dark_matter_paid   = 0;
639
    $this->payment_dark_matter_gained = 0;
640
    $this->payment_date               = SN_TIME_SQL;
641
    $this->payment_comment            = '';
642
    $this->payment_module_name        = '';
643
644
    $this->payment_external_id       = '';
645
    $this->payment_external_date     = '';
646
    $this->payment_external_lots     = 0;
647
    $this->payment_external_amount   = 0;
648
    $this->payment_external_currency = '';
649
650
    $this->payment_test = 0;
651
652
    $this->is_exists = false;
653
    $this->is_loaded = false;
654
655
    $this->description_generated = array();
656
  }
657
658
  protected function db_assign_payment($payment = null) {
659
    $this->payment_reset();
660
661
    if (is_array($payment) && isset($payment['payment_id'])) {
662
      $this->payment_id     = $payment['payment_id'];
663
      $this->payment_status = $payment['payment_status'];
664
      $this->payment_date   = $payment['payment_date'];
665
666
      $this->payment_provider_id  = $payment['payment_provider_id'];
667
      $this->payment_account_id   = $payment['payment_account_id'];
668
      $this->payment_account_name = $payment['payment_account_name'];
669
      $this->payment_user_id      = $payment['payment_user_id'];
670
      $this->payment_user_name    = $payment['payment_user_name'];
671
672
      $this->payment_amount   = $payment['payment_amount'];
673
      $this->payment_currency = $payment['payment_currency'];
674
675
      $this->payment_dark_matter_paid   = $payment['payment_dark_matter_paid'];
676
      $this->payment_dark_matter_gained = $payment['payment_dark_matter_gained'];
677
678
      $this->payment_comment     = $payment['payment_comment'];
679
      $this->payment_module_name = $payment['payment_module_name'];
680
681
      $this->payment_external_id       = $payment['payment_external_id'];
682
      $this->payment_external_date     = $payment['payment_external_date'];
683
      $this->payment_external_lots     = $payment['payment_external_lots'];
684
      $this->payment_external_amount   = $payment['payment_external_amount'];
685
      $this->payment_external_currency = $payment['payment_external_currency'];
686
687
      $this->payment_test = $payment['payment_test'];
688
689
      $this->is_exists = true;
690
      $this->is_loaded = true;
691
692
      $this->generate_description();
693
694
      return true;
695
    } else {
696
      return false;
697
    }
698
  }
699
700
  protected function generate_description() {
701
    $mmShort = SN::$lang['sys_metamatter_sh'];
702
    // TODO - системная локализация
703
    $this->description_generated = array(
704
      PAYMENT_DESCRIPTION_50 => substr(
705
        ($this->payment_test ? "T!" : '') .
706
        "{$this->payment_dark_matter_gained} {$mmShort} {$this->account->account_name}",
707
        0,
708
        PAYMENT_DESCRIPTION_50
709
      ),
710
      PAYMENT_DESCRIPTION_100 => substr("{$this->payment_dark_matter_gained} {$mmShort} аккаунт [{$this->account->account_name}] ID {$this->account->account_id} на " . SN_ROOT_VIRTUAL, 0, PAYMENT_DESCRIPTION_100),
711
      PAYMENT_DESCRIPTION_250 => substr("Оплата {$this->payment_dark_matter_gained} {$mmShort} для аккаунта [{$this->payment_user_name}] ID {$this->payment_user_id} на сервере " . SN_ROOT_VIRTUAL, 0, PAYMENT_DESCRIPTION_250),
712
      PAYMENT_DESCRIPTION_MAX => ($this->payment_test ? "ТЕСТОВЫЙ ПЛАТЕЖ! " : '') .
713
        "Платеж от аккаунта '{$this->payment_account_name}' ID {$this->payment_account_id} игрока '{$this->payment_user_name}' ID {$this->payment_user_id} на сервере " . SN_ROOT_VIRTUAL .
714
        " сумма {$this->payment_amount} {$this->payment_currency} за {$this->payment_dark_matter_paid} {$mmShort} (начислено {$this->payment_dark_matter_gained} {$mmShort})" .
715
        " через '{$this->manifest['name']}' сумма {$this->payment_external_amount} {$this->payment_external_currency}",
716
    );
717
  }
718
719
720
  /**
721
   * Does this module support payment method?
722
   *
723
   * @param $payment_method
724
   *
725
   * @return bool
726
   */
727
  public function isMethodSupported($payment_method) {
728
    return array_key_exists($payment_method, $this->manifest['payment_method']);
729
  }
730
731
  /**
732
   * Get details about payment method
733
   *
734
   * @param int $payment_method
735
   *
736
   * @return mixed|null
737
   */
738
  public function getMethodDetails($payment_method) {
739
    return $this->isMethodSupported($payment_method) ? $this->manifest['payment_method'][$payment_method] : null;
740
  }
741
742
  public function getMethodList() {
743
    return $this->manifest['payment_method'];
744
  }
745
746
  /**
747
   * Get payment method external ID used by payment provider
748
   *
749
   * @param $payment_method
750
   *
751
   * @return mixed|null
752
   */
753
  public function getMethodExternalId($payment_method) {
754
    return $this->getMethodDetails($payment_method);
755
  }
756
757
}
758