scope('listing', _t('@bills', 'Bills List View')) ->method('listing') ->scope('manage', _t('@bills', 'Bills Management')) ->method('ajax')->actions(['check', 'extra']) # + 'listing' => formStatus:onSubmit, formBalance=>onSubmit ->scope('payways', _t('@bills', 'Payment Methods')) ->method('payways') ; } /** * @return string * @throws \Exception */ public function listing() { if (! $this->haveAccessTo('listing')) { return $this->showAccessDenied(); } $summary = function ($d) { // }; $list = AdminHelpers::list($this, 'admin/listing', ['id' => 'bills.listing', 'templateDir' => $this->module_dir_tpl_core, 'data' => ['summary' => & $summary]]); $formStatus = AdminHelpers::form($this, 'admin/form.status', ['id' => 'bills.listing.status', 'templateDir' => $this->module_dir_tpl_core]) ->onSubmit(function ($id, $params) { $data = $params['data']; do { if (! $this->haveAccessTo('manage')) { $this->errors->set(Errors::ACCESSDENIED); break; } if (! $id || empty($data['status'])) { $this->errors->set(Errors::IMPOSSIBLE); break; } $statusID = $data['status']; if (in_array($statusID, array(static::STATUS_WAITING, static::STATUS_PROCESSING))) { $this->errors->set(Errors::IMPOSSIBLE); break; } $billData = $this->model->billData($id, ['user_id', 'type', 'status', 'amount', 'service_settings']); if (! $billData) { $this->errors->set(Errors::IMPOSSIBLE); break; } if ($statusID === $billData['status']) { # требуемый статус = текущему $this->errors->set(Errors::IMPOSSIBLE); break; } # закрываем счет if ($statusID == static::STATUS_COMPLETED) { if ($billData['type'] == static::TYPE_IN_PAY && $billData['user_id'] > 0 && empty($billData['service_settings'])) { $success = $this->completeBill($id, true, [ 'user_id' => $billData['user_id'], 'amount' => $billData['amount'], 'add' => true, ]); if ($success) { # обновляем баланс пользователя (зачисляем средства) # в случае закрытия счета типа "пополнение счета" $this->updateUserBalance($billData['user_id'], $billData['amount'], true); $params['response']['msg'] = $this->errors->getSystemMessage(Errors::SUCCESS); } } else { $cronManager = $this->app->cronManager(); if ($cronManager->isEnabled()) { $cronManager->executeOnce('bills', 'cronAdminProcessBill', ['id' => $id, 'user_id' => User::id()], 'bill' . $id); $params['response']['msg'] = _t('@bills', 'The task is planned. The operation will be completed within a minute'); } else { $this->errors->set(_t('@bills', 'The cron-manager is not running.')); } } } else { # отменяем счет (переключаем кастомный статус) $this->model->billSave($id, ['status' => $statusID]); } } while (false); return false; }) ->onLoad(function ($id, $data) { $bill = $this->model->billData($id); if (empty($bill['status']) || ! in_array($bill['status'], $this->getStatusChangeAllowed())) { $this->errors->set(Errors::IMPOSSIBLE); } return $bill; }) ->onSave(function ($id, $data) { // }); $list->formCustom($formStatus, 'status', ['idKey' => 'item_id', 'popup' => true]); $formBalance = AdminHelpers::form($this, 'admin/form.balance', ['id' => 'bills.listing.balance', 'templateDir' => $this->module_dir_tpl_core]) ->onSubmit(function ($userID, $data) { $data = $data['data']; do { if (! $this->haveAccessTo('manage')) { $this->errors->set(Errors::ACCESSDENIED); break; } $operation = $data['operation']; if (! $userID || ! in_array($operation, ['inc', 'dec'])) { $this->errors->set(Errors::IMPOSSIBLE); break; } $amount = $data[$operation . '_amount']; if ($amount <= 0) { $this->errors->set(_t('@bills', 'Amount must be greater than 0.')); break; } $description = $data[$operation . '_description']; $this->input->cleanVariable($description, [], TYPE_NOTAGS); $userBalance = Users::model()->userBalance($userID); if ($userBalance === false) { $this->errors->set(Errors::IMPOSSIBLE); break; } $createBill = !empty($description); if ($operation == 'dec') { # Проверяем не уйдем ли в минус if ($userBalance < $amount && $createBill) { $this->errors->set(Errors::IMPOSSIBLE); break; } # Списываем со счета $res = $this->updateUserBalance($userID, $amount, false); if (empty($res)) { $this->errors->set(Errors::IMPOSSIBLE); break; } if ($createBill) { $billID = $this->createBill_OutAdmin($userID, $userBalance - $amount, $amount, $description); } } else { # Пополняем счет $res = $this->updateUserBalance($userID, $amount, true); if (empty($res)) { $this->errors->set(Errors::IMPOSSIBLE); break; } if ($createBill) { $billID = $this->createBill_InGift($userID, $userBalance + $amount, $amount, $description); } } if ($createBill) { $success = !empty($billID); if ($success) { bff()->callModules('onUserBalanceAdmin', [$userID, $billID, ! empty($data[$operation . '_enotify'])]); } } } while (false); return false; }) ->onLoad(function ($id, $data) { return Users::model()->userData($id, ['user_id', 'email', 'phone_number', 'balance']); }) ->onSave(function ($id, $data) { // }); $list->formCustom($formBalance, 'balance', ['idKey' => 'user_id']); $list->onFordev(_t('@bills', 'Delete All Transactions'), function () { if (!$this->isAdminFordev()) { return $this->showAccessDenied(); } if ($this->model->billsDeleteAll()) { return $this->adminRedirect(Errors::SUCCESS, 'listing'); } return $this->showError(Errors::IMPOSSIBLE); }, true, 'icon-trash'); $tabs = $list->tabs(); $statuses = $this->getStatusData(); $tabs->add(0, _t('@', 'All'), true); foreach ($statuses as $k => $v) { $tabs->add($k, tpl::ucfirst($v)); } $filter = [ 'status' => $list->tab(), 'uid' => $list->filter('uid'), 'id' => $list->filter('id'), 'item' => $list->filter('item'), 'p_from' => $list->filter('p_from'), 'p_to' => $list->filter('p_to'), 'type' => $list->filter('type'), 'svc' => $list->filter('svc'), ]; $filter['status'] = $list->tab(); $list->perPageRange([ 20 => '20', 40 => '40', 100 => '100', -1 => _t('@', 'All')]); $list->total($this->model->billsListing($filter, true)); $rows = $this->model->billsListing($filter, false, $list->getLimitOffset(), $list->order('id-desc', true)); $list->rows($rows); $summary($this->model->billsListing($filter, false, '', '', true)); return $list->view(); } public function ajax() { if (! $this->isAJAX()) { return $this->ajaxResponse(Errors::ACCESSDENIED); } $billID = $this->input->post('bid', TYPE_UINT); $action = $this->input->getpost('act', TYPE_STR); switch ($action) { /** * Проверка состояния счета: * 1) webmoney - X18 интерфейс * 2) robox * * @param int $billID ID счета */ case 'check': { if (! $this->haveAccessTo('manage')) { return $this->ajaxResponse(Errors::ACCESSDENIED); } if (! $billID) { return $this->ajaxResponse(Errors::IMPOSSIBLE); } $billData = $this->model->billData($billID, ['psystem', 'psystem_way']); if (! $billData) { return $this->ajaxResponse(Errors::IMPOSSIBLE); } $paySystem = $this->paymentProvider($billData['psystem']); if (! $paySystem) { return $this->ajaxResponse(Errors::IMPOSSIBLE); } if (method_exists($paySystem, 'check')) { return $paySystem->check($billID); } return $this->ajaxResponse(Errors::IMPOSSIBLE); } case 'extra': { if (!$billID) { return $this->ajaxResponse(Errors::IMPOSSIBLE); } if (!$this->haveAccessTo('manage')) { return $this->ajaxResponse(Errors::ACCESSDENIED); } $aData = $this->model->billData($billID, ['details']); return $this->ajaxResponse(['extra' => $aData['details']]); } default: { $this->app->hook('bills.admin.ajax.default.action', $action, $this); } break; } return $this->ajaxResponse(Errors::IMPOSSIBLE); } /** * Настройка доступных способов оплаты * @return string */ public function payways() { if (! $this->haveAccessTo('payways')) { return $this->showAccessDenied(); } $path = $this->app->path('svc', 'images'); $url = $this->app->url('svc', 'images'); $extAllowed = ['jpg','png','gif','svg']; $prefix = 'pays'; $opts = $this->app->filter('bills.payways.opts', [ 'logo' => ['width' => 300, 'height' => 300], ]); $act = $this->input->postget('act', TYPE_STR); # валюты $currencyListISO = Currency::knownList(); $currencyListDb = Currency::list(false); $currencyList = []; foreach ($currencyListDb as $k => & $v) { $key = $v['keyword'] = mb_strtolower($v['keyword']); $v['iso'] = (isset($currencyListISO[$key]) ? $currencyListISO[$key] : []); $currencyList[$key] = $v; } unset($v); $currencyDefault = Currency::data(); if (empty($currencyDefault)) { $currencyDefault = ['id' => 0, 'title' => '']; } # системы оплаты $listSystems = []; foreach ($this->paymentProvidersList() as $k => $v) { $listSystems[$k] = [ 'key' => $v->providerKey(), 'title' => $v->providerTitle(), 'ways' => $v->payWays(), 'currency' => mb_strtolower($v->payDefaultCurrency()), 'logo' => $v->payLogoUrl(), ]; } uasort($listSystems, function ($a, $b) { return $a['title'] > $b['title']; }); $modified = config::get(static::PAYWAYS_CONFIG_MODIFIED, 0, TYPE_UINT); if (! $modified) { $modified = time(); config::save(static::PAYWAYS_CONFIG_MODIFIED, $modified); } # способы оплаты $listUser = $this->getPayWaysList(false, ['enabledOnly' => false]); foreach ($listUser as $k => & $v) { $v['is_new'] = 0; if (! isset($v['logo_file'])) { $v['logo_file'] = ''; } $v['currency_title'] = isset($currencyList[ $v['currency'] ]) ? $currencyList[ $v['currency'] ]['title'] : ''; $v['hash'] = $k; } unset($v); if ($this->isPOST()) { $response = []; switch ($act) { case 'save': if ($this->input->post('modified', TYPE_UINT) != $modified) { $this->errors->reloadPage(); break; } $data = $this->input->post($prefix, TYPE_ARRAY); $save = []; $priority = 10; foreach ($data as $k => $v) { if (empty($v['key']) || ! isset($listSystems[$v['key']])) { continue; } if (! isset($v['title']) || ! isset($v['currency']) || ! isset($currencyList[ $v['currency'] ])) { continue; } $s = [ 'key' => $v['key'], 'title' => $this->input->clean($v['title'], TYPE_NOTAGS), 'way' => $this->input->clean($v['way'], TYPE_NOTAGS), 'currency' => $v['currency'], 'currency_id' => $currencyList[ $v['currency'] ]['id'], 'enabled' => ! empty($v['enabled']), ]; if (empty($s)) { continue; } if (! empty($v['new'])) { if (isset($_FILES[$prefix . '_' . $k]) && $_FILES[$prefix . '_' . $k]['error'] == UPLOAD_ERR_OK) { $attach = new Attachment($path); $attach->setFiledataAsString(false); $attach->setAllowedExtensions($extAllowed); $file = $attach->uploadFILES($prefix . '_' . $k); $file_original = $path . $file['filename']; if (! empty($file['error'])) { $this->errors->setUploadError($file['error']); break 2; } if (! is_file($file_original)) { $this->errors->setUploadError(Errors::FILE_UPLOAD_ERROR); break 2; } $file_size = getimagesize($file_original); if (! empty($file_size) && ($file_size[0] > $opts['logo']['width'] || $file_size[1] > $opts['logo']['height'])) { $thumb_file = $path . func::generator(14) . '.' . $file['extension']; $thumb = new Thumbnail($file_original, false); $thumb->save([[ 'filename' => $thumb_file, 'width' => $opts['logo']['width'], 'height' => false, 'vertical' => [ 'width' => false, 'height' => $opts['logo']['height'], ], ],]); if (! is_file($thumb_file)) { $this->errors->setUploadError(Errors::FILE_UPLOAD_ERROR); break 2; } $s['logo_file'] = $thumb_file; } else { $s['logo_file'] = $file_original; } $s['logo_file'] = str_replace($this->app->basePath(), '{path_base}', $s['logo_file']); $response['reload'] = 1; } } if (empty($s['logo_file']) && ! empty($v['logo_file'])) { if (file_exists($v['logo_file'])) { $s['logo_file'] = str_replace($this->app->basePath(), '{path_base}', $v['logo_file']); } } if (empty($v['hash'])) { do { $v['hash'] = func::generatorLetters(10); } while (isset($save[$v['hash']])); } $s['priority'] = $priority; $priority += 10; $save[$v['hash']] = $s; } $modified = time(); config::save(static::PAYWAYS_CONFIG, $save); config::save(static::PAYWAYS_CONFIG_MODIFIED, $modified); $response['modified'] = $modified; # удалим файлы для удаленных способов оплаты foreach ($listUser as $k => $v) { if (isset($save[$k])) { continue; } if (empty($v['logo_file'])) { continue; } if (file_exists($v['logo_file'])) { @unlink($v['logo_file']); } } $response['msg'] = $this->errors->getSystemMessage(Errors::SUCCESS); break; } return $this->iframeResponseForm($response); } $data = [ 'inputNamePrefix' => $prefix, 'listUser' => $listUser, 'listSystems' => $listSystems, 'currencyList' => $currencyList, 'currencyDefault' => $currencyDefault, 'modified' => $modified, ]; return $this->template('admin/payways', $data, [ 'path' => $this->module_dir_tpl_core, ]); } /** * Список услуг * @return array */ public function serviceOptions() { $serviceModel = Svc::model()->service(); $list = $serviceModel::where('enabled', 1) ->orderBy('group_key') ->orderBy('service_type') ->orderBy('num') ->get() ->toArray(); $data = []; foreach ($list as $v) { $title = ''; if ($this->app->moduleExists($v['group_key'])) { $module = $this->app->module($v['group_key']); if ($module) { $title = $module->module_title . ' / '; } } $data[] = [ 'id' => $v['group_key'] . ':' . $v['service_key'], 'title' => $title . $v['title'], ]; } return $data; } }