index.php 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388
  1. <?php
  2. if (cfr('ROOT')) {
  3. class PaymentFixer {
  4. /**
  5. * Contains system alter.ini config as key=>value
  6. *
  7. * @var array
  8. */
  9. protected $altCfg = array();
  10. /**
  11. * Contains system billing.ini config as key=>value
  12. *
  13. * @var array
  14. */
  15. protected $billCfg = array();
  16. /**
  17. * Contains all available users data as login=>userData
  18. *
  19. * @var array
  20. */
  21. protected $allUserData = array();
  22. /**
  23. * System messages helper object placeholder
  24. *
  25. * @var object
  26. */
  27. protected $messages = '';
  28. /**
  29. * Payments table data model placeholder
  30. *
  31. * @var object
  32. */
  33. protected $payments = '';
  34. /**
  35. * Date to detect unprocessed transactions
  36. *
  37. * @var string
  38. */
  39. protected $checkDate = '';
  40. /**
  41. * Routing etc...
  42. */
  43. const URL_PROFILE = '?module=userprofile&username=';
  44. const URL_ME = '?module=paymentsfixer';
  45. public function __construct() {
  46. $this->initMessages();
  47. $this->loadConfigs();
  48. $this->loadUserData();
  49. $this->initDataModels();
  50. }
  51. /**
  52. * Loads existing user data from database
  53. *
  54. * @return void
  55. */
  56. protected function loadUserData() {
  57. $this->allUserData = zb_UserGetAllData(); //here must be an actual data
  58. }
  59. /**
  60. * Inits message helper instance
  61. *
  62. * @return void
  63. */
  64. protected function initMessages() {
  65. $this->messages = new UbillingMessageHelper();
  66. }
  67. /**
  68. * Loads all required configs into protected props for further usage
  69. *
  70. * @global object $ubillingConfig
  71. *
  72. * @return void
  73. */
  74. protected function loadConfigs() {
  75. global $ubillingConfig;
  76. $this->altCfg = $ubillingConfig->getAlter();
  77. $this->billCfg = $ubillingConfig->getBilling();
  78. }
  79. /**
  80. * Inits required data models for further usage
  81. *
  82. * @return void
  83. */
  84. protected function initDataModels() {
  85. $this->payments = new NyanORM('payments');
  86. }
  87. /**
  88. * Sets required date into protected prop
  89. *
  90. * @param string $date
  91. *
  92. * @return void
  93. */
  94. public function setDate($date = '') {
  95. if (empty($date)) {
  96. $this->checkDate = curdate();
  97. } else {
  98. $this->checkDate = $date;
  99. }
  100. }
  101. /**
  102. * Returns array of positive payments by selected date
  103. *
  104. * @return array
  105. */
  106. protected function getPayments() {
  107. $result = array();
  108. if (!empty($this->checkDate)) {
  109. $this->payments->where('date', 'LIKE', $this->checkDate . '%');
  110. $this->payments->where('summ', '>', '0');
  111. $result = $this->payments->getAll();
  112. }
  113. return($result);
  114. }
  115. /**
  116. * Returns all available cash operations by selected date
  117. *
  118. * @return string
  119. */
  120. protected function getStargazerOps() {
  121. $result = '';
  122. if (!empty($this->checkDate)) {
  123. $sudo = $this->billCfg['SUDO'];
  124. $cat = $this->billCfg['CAT'];
  125. $stgLog = $this->altCfg['STG_LOG_PATH'];
  126. $grep = $this->billCfg['GREP'];
  127. $command = $sudo . ' ' . $cat . ' ' . $stgLog . ' | ' . $grep . ' ' . $this->checkDate . ' | ' . $grep . ' cash | ' . $grep . ' -v fee';
  128. $result .= shell_exec($command);
  129. }
  130. return($result);
  131. }
  132. /**
  133. * Returns array of payments that was not detected in stargazer log on selected date
  134. *
  135. * @return array
  136. */
  137. public function getFailedPayments() {
  138. $stgDataRaw = $this->getStargazerOps();
  139. $allPayments = $this->getPayments();
  140. $result = array();
  141. if (!empty($allPayments)) {
  142. foreach ($allPayments as $io => $eachPayment) {
  143. if (!ispos($eachPayment['note'], 'MOCK:')) {
  144. if (!ispos($stgDataRaw, $eachPayment['login'])) {
  145. $result[$eachPayment['id']] = $eachPayment;
  146. }
  147. }
  148. }
  149. }
  150. return($result);
  151. }
  152. /**
  153. * Renders failed payments list with some controls
  154. *
  155. * @return string
  156. */
  157. public function renderFailedPayments() {
  158. $result = '';
  159. $allCashtypes = zb_CashGetAllCashTypes();
  160. $allFailed = $this->getFailedPayments();
  161. if (!empty($allFailed)) {
  162. $cells = wf_TableCell(__('ID'));
  163. $cells .= wf_TableCell(__('Date'));
  164. $cells .= wf_TableCell(__('Sum'));
  165. $cells .= wf_TableCell(__('Previous') . ' ' . __('Balance'));
  166. $cells .= wf_TableCell(__('Cash type'));
  167. $cells .= wf_TableCell(__('User'));
  168. $cells .= wf_TableCell(__('Current Cash state'));
  169. $cells .= wf_TableCell(__('Notes'));
  170. $cells .= wf_TableCell(__('Actions'));
  171. $rows = wf_TableRow($cells, 'row1');
  172. foreach ($allFailed as $io => $each) {
  173. @$userData = $this->allUserData[$each['login']];
  174. $cells = wf_TableCell($each['id']);
  175. $cells .= wf_TableCell($each['date']);
  176. $cells .= wf_TableCell($each['summ']);
  177. $cells .= wf_TableCell($each['balance']);
  178. $cells .= wf_TableCell(__(@$allCashtypes[$each['cashtypeid']]));
  179. $userLink = wf_Link(self::URL_PROFILE . $each['login'], web_profile_icon() . ' ' . @$userData['fulladress']);
  180. $cells .= wf_TableCell($userLink);
  181. $cells .= wf_TableCell($userData['Cash']);
  182. $cells .= wf_TableCell($each['note']);
  183. $actionControls = '';
  184. $actionControls .= wf_JSAlert(self::URL_ME . '&paymentdelete=' . $each['id'], web_delete_icon(), $this->messages->getDeleteAlert()) . ' ';
  185. $actionControls .= wf_JSAlert(self::URL_ME . '&fixpaymentid=' . $each['id'], wf_img('skins/icon_repair.gif', __('Fix')), $this->messages->getEditAlert() . ' ' . __('Add cash') . '?') . ' ';
  186. $cells .= wf_TableCell($actionControls);
  187. $rows .= wf_TableRow($cells, 'row5');
  188. }
  189. $result .= wf_TableBody($rows, '100%', 0, 'sortable');
  190. } else {
  191. $result .= $this->messages->getStyledMessage(__('Nothing to show'), 'success');
  192. }
  193. return($result);
  194. }
  195. /**
  196. * Renders users that failed with their payments
  197. *
  198. * @return string
  199. */
  200. public function renderDebtorUsers() {
  201. $result = '';
  202. $allPayments = $this->getPayments();
  203. $debtorsTmp = array();
  204. if (!empty($allPayments)) {
  205. foreach ($allPayments as $io => $each) {
  206. if (isset($this->allUserData[$each['login']])) {
  207. $userData = $this->allUserData[$each['login']];
  208. if ($userData['Cash'] < '-' . $userData['Credit']) {
  209. if (!ispos($each['note'], 'MOCK:')) {
  210. $debtorsTmp[] = $each;
  211. }
  212. }
  213. }
  214. }
  215. if (!empty($debtorsTmp)) {
  216. $allCashtypes = zb_CashGetAllCashTypes();
  217. $allTariffPrices = zb_TariffGetPricesAll();
  218. $cells = wf_TableCell(__('Sum'));
  219. $cells .= wf_TableCell(__('Previous') . ' ' . __('Balance'));
  220. $cells .= wf_TableCell(__('Current Cash state'));
  221. $cells .= wf_TableCell(__('Cash type'));
  222. $cells .= wf_TableCell(__('User'));
  223. $cells .= wf_TableCell(__('Tariff') . ' / ' . __('Fee'));
  224. $cells .= wf_TableCell(__('Notes'));
  225. $cells .= wf_TableCell(__('Reason'));
  226. $rows = wf_TableRow($cells, 'row1');
  227. foreach ($debtorsTmp as $io => $each) {
  228. $userData = $this->allUserData[$each['login']];
  229. $userTariff = $userData['Tariff'];
  230. $userTariffPrice = (isset($allTariffPrices[$userTariff])) ? $allTariffPrices[$userTariff] : 0;
  231. $cells = wf_TableCell($each['summ']);
  232. $cells .= wf_TableCell($each['balance']);
  233. $cells .= wf_TableCell($userData['Cash']);
  234. $cells .= wf_TableCell(__(@$allCashtypes[$each['cashtypeid']]));
  235. $userLink = wf_Link(self::URL_PROFILE . $each['login'], web_profile_icon() . ' ' . @$userData['fulladress']);
  236. $cells .= wf_TableCell($userLink);
  237. $cells .= wf_TableCell($userTariff . ' / ' . $userTariffPrice);
  238. $cells .= wf_TableCell($each['note']);
  239. $reason = '';
  240. if ($each['summ'] < $userTariffPrice) {
  241. $reason .= __('Less than tariff price') . ' ';
  242. } else {
  243. if ($userData['Cash'] < '-' . $userTariffPrice) {
  244. $reason .= __('User was inactive for a long time') . ' ';
  245. }
  246. }
  247. $cells .= wf_TableCell($reason);
  248. $rows .= wf_TableRow($cells, 'row5');
  249. }
  250. $result .= wf_TableBody($rows, '100%', 0, 'sortable');
  251. } else {
  252. $result .= $this->messages->getStyledMessage(__('Nothing to show'), 'success');
  253. }
  254. } else {
  255. $result .= $this->messages->getStyledMessage(__('Nothing to show'), 'success');
  256. }
  257. return($result);
  258. }
  259. /**
  260. * Rdenders default date setup form
  261. *
  262. * @param string $date
  263. *
  264. * @return string
  265. */
  266. public function renderDateSelectorForm($date) {
  267. $result = '';
  268. $inputs = wf_DatePickerPreset('checkdate', $date, true) . ' ';
  269. $inputs .= wf_Submit(__('Find'));
  270. $result .= wf_Form('', 'POST', $inputs, 'glamour');
  271. return($result);
  272. }
  273. /**
  274. * Adds cash on stargazer user account, pushes payment to log.
  275. *
  276. * @param int $paymentId
  277. *
  278. * @return void/string on error
  279. */
  280. public function fixPayment($paymentId) {
  281. $result = '';
  282. $paymentId = ubRouting::filters($paymentId, 'int');
  283. if (!empty($paymentId)) {
  284. $this->payments->where('id', '=', $paymentId);
  285. $paymentData = $this->payments->getAll();
  286. if (!empty($paymentData)) {
  287. $paymentData = $paymentData[0];
  288. zb_CashAdd($paymentData['login'], $paymentData['summ'], 'correct', $paymentData['cashtypeid'], 'PAYFIXED:' . $paymentId);
  289. $sudo = $this->billCfg['SUDO'];
  290. $stgLog = $this->altCfg['STG_LOG_PATH'];
  291. $command = 'echo "' . $paymentData['date'] . ' ' . $paymentData['login'] . ' cash fixed manually summ:' . $paymentData['summ'] . '" | ' . $sudo . ' tee -a ' . $stgLog;
  292. shell_exec($command);
  293. } else {
  294. $result .= __('Something went wrong') . ': EX_EMPTYPAYMENTDATA';
  295. }
  296. } else {
  297. $result .= __('Something went wrong') . ': EX_EMPTYPAYMENTID';
  298. }
  299. return($result);
  300. }
  301. }
  302. $alter = $ubillingConfig->getAlter();
  303. $checkDate = (ubRouting::checkPost('checkdate')) ? ubRouting::post('checkdate', 'mres') : curdate();
  304. $fixer = new PaymentFixer();
  305. //payment correction
  306. if (ubRouting::checkGet('fixpaymentid')) {
  307. $repairResult = $fixer->fixPayment(ubRouting::get('fixpaymentid'));
  308. if (empty($repairResult)) {
  309. ubRouting::nav($fixer::URL_ME);
  310. } else {
  311. show_error($repairResult);
  312. }
  313. }
  314. //payment deletion
  315. if (ubRouting::checkGet('paymentdelete')) {
  316. $deletePaymentId = ubRouting::get('paymentdelete', 'int');
  317. $deletingAdmins = array();
  318. $iCanDeletePayments = false;
  319. $currentAdminLogin = whoami();
  320. $paymentsDb = new nya_payments();
  321. $paymentsDb->selectable(array('id', 'login'));
  322. $paymentsDb->where('id', '=', $deletePaymentId);
  323. $login = $paymentsDb->getAll();
  324. $login = @$login[0]['login'];
  325. if (!empty($login)) {
  326. //extract delete admin logins
  327. if (!empty($alter['CAN_DELETE_PAYMENTS'])) {
  328. $deletingAdmins = explode(',', $alter['CAN_DELETE_PAYMENTS']);
  329. $deletingAdmins = array_flip($deletingAdmins);
  330. }
  331. $iCanDeletePayments = (isset($deletingAdmins[$currentAdminLogin])) ? true : false;
  332. //right check
  333. if ($iCanDeletePayments) {
  334. $paymentsDb = new nya_payments();
  335. $paymentsDb->where('id', '=', $deletePaymentId);
  336. $paymentsDb->delete();
  337. log_register("PAYMENT DELETE [" . $deletePaymentId . "] (" . $login . ")");
  338. } else {
  339. log_register("PAYMENT UNAUTH DELETION ATTEMPT [" . $deletePaymentId . "] (" . $login . ")");
  340. }
  341. }
  342. ubRouting::nav($fixer::URL_ME);
  343. }
  344. show_window('', $fixer->renderDateSelectorForm($checkDate));
  345. $fixer->setDate($checkDate);
  346. show_window(__('Money transactions that may was not processed'), $fixer->renderFailedPayments());
  347. show_window(__('That users payed something but still is debtors'), $fixer->renderDebtorUsers());
  348. show_window('', wf_BackLink('?module=report_finance'));
  349. } else {
  350. show_error(__('Access denied'));
  351. }