api.fundsflow.php 61 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606
  1. <?php
  2. /**
  3. * Financial data preprocessing and rendering class
  4. */
  5. class FundsFlow {
  6. /**
  7. * Contains system alter config as key=>value
  8. *
  9. * @var array
  10. */
  11. protected $alterConf = array();
  12. /**
  13. * Contains main billing config as key=>value
  14. *
  15. * @var array
  16. */
  17. protected $billingConf = array();
  18. /**
  19. * Contains all of available user data as login=>userdata
  20. *
  21. * @var array
  22. */
  23. protected $allUserData = array();
  24. /**
  25. * Contains available tariffs data as tariffname=>data
  26. *
  27. * @var array
  28. */
  29. protected $allTariffsData = array();
  30. /**
  31. * Storage os some temporary data
  32. *
  33. * @var array
  34. */
  35. protected $fundsTmp = array();
  36. /**
  37. * Contains assigned user tags
  38. *
  39. * @var array
  40. */
  41. protected $userTags = array();
  42. /**
  43. * Placeholder for FF_REP_AVOID_DUPLICATE_DT_KEYS alter.ini option
  44. *
  45. * @var bool
  46. */
  47. public $avoidDTKeysDuplicates = false;
  48. /**
  49. * Is fees harvester enabled flag.
  50. *
  51. * @var bool
  52. */
  53. protected $feesHarvesterFlag = false;
  54. /**
  55. * Harvested fees database abstraction layer
  56. *
  57. * @var object
  58. */
  59. protected $feesDb = '';
  60. /**
  61. * Payments database abstraction layer
  62. *
  63. * @var object
  64. */
  65. protected $paymentsDb = '';
  66. /**
  67. * Balance corrections database abstraction layer
  68. *
  69. * @var object
  70. */
  71. protected $corrDb = '';
  72. /**
  73. * Contains date filter for massive queries
  74. *
  75. * @var string
  76. */
  77. protected $dateFilter = '';
  78. /**
  79. * Contains cemetery instance for further usage
  80. *
  81. * @var object
  82. */
  83. protected $cemetery = '';
  84. /**
  85. * Contains buried users
  86. *
  87. * @var array
  88. */
  89. protected $allBuriedUsers = array();
  90. /**
  91. * Placeholder for ONLINE_SHOW_LAST_FEECHARGE alter.ini option
  92. *
  93. * @var string
  94. */
  95. protected $onlineShowLastFeeChargeON = 0;
  96. /**
  97. * Rendering coloring settings
  98. */
  99. protected $colorPayment = '005304';
  100. protected $colorFee = 'a90000';
  101. protected $colorBonus = '007706';
  102. protected $colorAdditionalFee = 'd50000';
  103. protected $colorCorrecting = 'ff6600';
  104. protected $colorMock = '006699';
  105. protected $colorSet = '000000';
  106. protected $colorCreditViolet = '552c82';
  107. /**
  108. * some stargazer log data offsets here
  109. */
  110. const OFFSET_DATE = 0;
  111. const OFFSET_TIME = 1;
  112. const OFFSET_LOGIN = 7;
  113. const OFFSET_FROM = 12;
  114. const OFFSET_TO = 14;
  115. /**
  116. * other predefined stuff
  117. */
  118. const MASK_FEE = 'fee charge';
  119. const TABLE_FEES = 'fees';
  120. const TABLE_PAYS = 'payments';
  121. const TABLE_CORR = 'paymentscorr';
  122. /**
  123. * Creates new FundsFlow instance
  124. *
  125. * @return void
  126. */
  127. public function __construct() {
  128. $this->loadConfigs();
  129. $this->initTmp();
  130. $this->initFinanceDb();
  131. if ($this->feesHarvesterFlag) {
  132. $this->initFeesDb();
  133. }
  134. if ($this->alterConf['CEMETERY_ENABLED']) {
  135. $this->loadCemetery();
  136. }
  137. }
  138. /**
  139. * Preloads system configs
  140. *
  141. * @return void
  142. */
  143. protected function loadConfigs() {
  144. global $ubillingConfig;
  145. $this->alterConf = $ubillingConfig->getAlter();
  146. $this->billingConf = $ubillingConfig->getBilling();
  147. $this->avoidDTKeysDuplicates = $ubillingConfig->getAlterParam('FF_REP_AVOID_DUPLICATE_DT_KEYS');
  148. $this->feesHarvesterFlag = $ubillingConfig->getAlterParam('FEES_HARVESTER');
  149. $this->onlineShowLastFeeChargeON = $ubillingConfig->getAlterParam('ONLINE_SHOW_LAST_FEECHARGE', 0);
  150. }
  151. /**
  152. * Inits tmp data with empty values
  153. *
  154. * @return void
  155. */
  156. protected function initTmp() {
  157. $this->fundsTmp['col1'] = 0;
  158. $this->fundsTmp['col2'] = 0;
  159. $this->fundsTmp['col3'] = 0;
  160. $this->fundsTmp['col4'] = 0;
  161. }
  162. /**
  163. * Inits fees database abstraction layer
  164. *
  165. * @return void
  166. */
  167. protected function initFinanceDb() {
  168. $this->paymentsDb = new NyanORM(self::TABLE_PAYS);
  169. $this->corrDb = new NyanORM(self::TABLE_CORR);
  170. }
  171. /**
  172. * Inits fees database abstraction layer
  173. *
  174. * @return void
  175. */
  176. protected function initFeesDb() {
  177. $this->feesDb = new NyanORM(self::TABLE_FEES);
  178. }
  179. /**
  180. * Loads all of available users data as login=>array
  181. *
  182. * @return void
  183. */
  184. protected function loadAllUserData() {
  185. $this->allUserData = zb_UserGetAllStargazerDataAssoc();
  186. }
  187. /**
  188. * Inits cemetery and preloads all buried users
  189. *
  190. * @return void
  191. */
  192. protected function loadCemetery() {
  193. $this->cemetery = new Cemetery();
  194. $this->allBuriedUsers = $this->cemetery->getAllTagged();
  195. }
  196. /**
  197. * Loads tariffs data from database into protected property
  198. *
  199. * @return void
  200. */
  201. protected function loadAllTariffsData() {
  202. $this->allTariffsData = zb_TariffGetAllData();
  203. }
  204. /**
  205. * Loads existing tagtypes and usertags into protected props for further usage
  206. *
  207. * @return void
  208. */
  209. protected function loadUserTags() {
  210. $this->userTags = zb_UserGetAllTags();
  211. }
  212. /**
  213. * Datetime mask for filtering payments/fees on massive queries
  214. *
  215. * @param string $dateMask
  216. *
  217. * @return void
  218. */
  219. public function setDateFilter($dateMask) {
  220. $this->dateFilter = ubRouting::filters($dateMask, 'mres');
  221. }
  222. /**
  223. * Returns array of fees by some login with parsing it from stargazer log
  224. *
  225. * @param string $login existing user login
  226. *
  227. * @return array
  228. */
  229. public function getLogFees($login) {
  230. $login = ubRouting::filters($login, 'mres');
  231. $sudo = $this->billingConf['SUDO'];
  232. $cat = $this->billingConf['CAT'];
  233. $grep = $this->billingConf['GREP'];
  234. $stglog = $this->alterConf['STG_LOG_PATH'];
  235. $result = array();
  236. $feeadmin = 'stargazer';
  237. $feenote = '';
  238. $feecashtype = 0;
  239. // monthly fees output
  240. $command = $sudo . ' ' . $cat . ' ' . $stglog . ' | ' . $grep . ' "' . self::MASK_FEE . '"' . ' | ' . $grep . ' "User \'' . $login . '\'" ';
  241. $rawdata = shell_exec($command);
  242. if (!empty($rawdata)) {
  243. $cleardata = exploderows($rawdata);
  244. foreach ($cleardata as $eachline) {
  245. $eachfee = explode(' ', $eachline);
  246. if (!empty($eachline)) {
  247. if (isset($eachfee[self::OFFSET_TIME])) {
  248. $counter = strtotime($eachfee[self::OFFSET_DATE] . ' ' . $eachfee[self::OFFSET_TIME]);
  249. // trying to avoid duplicate keys
  250. while ($this->avoidDTKeysDuplicates and array_key_exists($counter, $result)) {
  251. $counter++;
  252. }
  253. $feefrom = str_replace("'.", '', $eachfee[self::OFFSET_FROM]);
  254. $feeto = str_replace("'.", '', $eachfee[self::OFFSET_TO]);
  255. $feefrom = str_replace("'", '', $feefrom);
  256. $feeto = str_replace("'", '', $feeto);
  257. $result[$counter]['login'] = $login;
  258. $result[$counter]['date'] = $eachfee[self::OFFSET_DATE] . ' ' . $eachfee[self::OFFSET_TIME];
  259. $result[$counter]['admin'] = $feeadmin;
  260. $result[$counter]['summ'] = $feeto - $feefrom;
  261. $result[$counter]['from'] = $feefrom;
  262. $result[$counter]['to'] = $feeto;
  263. $result[$counter]['operation'] = 'Fee';
  264. $result[$counter]['note'] = $feenote;
  265. $result[$counter]['cashtype'] = $feecashtype;
  266. }
  267. }
  268. }
  269. }
  270. return ($result);
  271. }
  272. /**
  273. * Returns array of fees by some login from harvested fees database
  274. *
  275. * @param string $login existing user login
  276. *
  277. * @return array
  278. */
  279. public function getDbFees($login) {
  280. $result = array();
  281. $login = ubRouting::filters($login, 'mres');
  282. $this->feesDb->where('login', '=', $login);
  283. $allFees = $this->feesDb->getAll();
  284. if (!empty($allFees)) {
  285. foreach ($allFees as $io => $each) {
  286. $counter = strtotime($each['date']);
  287. // trying to avoid duplicate keys
  288. while ($this->avoidDTKeysDuplicates and array_key_exists($counter, $result)) {
  289. $counter++;
  290. }
  291. $result[$counter]['login'] = $each['login'];
  292. $result[$counter]['date'] = $each['date'];
  293. $result[$counter]['admin'] = $each['admin'];
  294. $result[$counter]['summ'] = $each['summ'];
  295. $result[$counter]['from'] = $each['from'];
  296. $result[$counter]['to'] = $each['to'];
  297. $result[$counter]['operation'] = 'Fee';
  298. $result[$counter]['note'] = $each['note'];
  299. $result[$counter]['cashtype'] = $each['cashtype'];
  300. }
  301. }
  302. return ($result);
  303. }
  304. /**
  305. * Returns array of fees by some login with parsing it from stargazer log
  306. *
  307. * @param string $login existing user login
  308. *
  309. * @return array
  310. */
  311. public function getFees($login) {
  312. $result = array();
  313. if ($this->feesHarvesterFlag) {
  314. $result = $this->getDbFees($login);
  315. } else {
  316. $result = $this->getLogFees($login);
  317. }
  318. return ($result);
  319. }
  320. /**
  321. * Returns all payments/fees/corrections with optional date filter as login=>counter=>flows
  322. *
  323. * @return array
  324. */
  325. public function getAllCashFlows() {
  326. $result = array();
  327. $payments = array();
  328. $paymentscorr = array();
  329. /**
  330. * Fees
  331. */
  332. if ($this->feesHarvesterFlag) {
  333. if ($this->dateFilter) {
  334. $this->feesDb->where('date', 'LIKE', $this->dateFilter . '%');
  335. }
  336. $allFees = $this->feesDb->getAll();
  337. if (!empty($allFees)) {
  338. foreach ($allFees as $io => $each) {
  339. $counter = strtotime($each['date']);
  340. // trying to avoid duplicate keys
  341. while ($this->avoidDTKeysDuplicates and isset($result[$each['login']][$counter])) {
  342. $counter++;
  343. }
  344. $result[$each['login']][$counter]['login'] = $each['login'];
  345. $result[$each['login']][$counter]['date'] = $each['date'];
  346. $result[$each['login']][$counter]['admin'] = $each['admin'];
  347. $result[$each['login']][$counter]['summ'] = $each['summ'];
  348. $result[$each['login']][$counter]['from'] = $each['from'];
  349. $result[$each['login']][$counter]['to'] = $each['to'];
  350. $result[$each['login']][$counter]['operation'] = 'Fee';
  351. $result[$each['login']][$counter]['note'] = $each['note'];
  352. $result[$each['login']][$counter]['cashtype'] = $each['cashtype'];
  353. }
  354. }
  355. } else {
  356. //log fees
  357. $sudo = $this->billingConf['SUDO'];
  358. $cat = $this->billingConf['CAT'];
  359. $grep = $this->billingConf['GREP'];
  360. $stglog = $this->alterConf['STG_LOG_PATH'];
  361. $command = $sudo . ' ' . $cat . ' ' . $stglog . ' | ' . $grep . ' "' . self::MASK_FEE . '"';
  362. if ($this->dateFilter) {
  363. $command .= ' | ' . $grep . ' ' . $this->dateFilter;
  364. }
  365. $feeadmin = 'stargazer';
  366. $feenote = '';
  367. $feecashtype = 0;
  368. $rawdata = shell_exec($command);
  369. if (!empty($rawdata)) {
  370. $cleardata = exploderows($rawdata);
  371. foreach ($cleardata as $eachline) {
  372. $eachfee = explode(' ', $eachline);
  373. if (!empty($eachline)) {
  374. if (isset($eachfee[self::OFFSET_TIME])) {
  375. $counter = strtotime($eachfee[self::OFFSET_DATE] . ' ' . $eachfee[self::OFFSET_TIME]);
  376. $loginExtracted = zb_ParseTagData("User '", "': 'cash'", $eachline, false);
  377. // trying to avoid duplicate keys
  378. while ($this->avoidDTKeysDuplicates and isset($result[$loginExtracted][$counter])) {
  379. $counter++;
  380. }
  381. $feefrom = str_replace("'.", '', $eachfee[self::OFFSET_FROM]);
  382. $feeto = str_replace("'.", '', $eachfee[self::OFFSET_TO]);
  383. $feefrom = str_replace("'", '', $feefrom);
  384. $feeto = str_replace("'", '', $feeto);
  385. $result[$loginExtracted][$counter]['login'] = $loginExtracted;
  386. $result[$loginExtracted][$counter]['date'] = $eachfee[self::OFFSET_DATE] . ' ' . $eachfee[self::OFFSET_TIME];
  387. $result[$loginExtracted][$counter]['admin'] = $feeadmin;
  388. $result[$loginExtracted][$counter]['summ'] = $feeto - $feefrom;
  389. $result[$loginExtracted][$counter]['from'] = $feefrom;
  390. $result[$loginExtracted][$counter]['to'] = $feeto;
  391. $result[$loginExtracted][$counter]['operation'] = 'Fee';
  392. $result[$loginExtracted][$counter]['note'] = $feenote;
  393. $result[$loginExtracted][$counter]['cashtype'] = $feecashtype;
  394. }
  395. }
  396. }
  397. }
  398. }
  399. /**
  400. * Payments
  401. */
  402. if ($this->dateFilter) {
  403. $this->paymentsDb->where('date', 'LIKE', $this->dateFilter . '%');
  404. }
  405. $allPayments = $this->paymentsDb->getAll();
  406. if (!empty($allPayments)) {
  407. foreach ($allPayments as $io => $each) {
  408. $counter = strtotime($each['date']);
  409. // trying to avoid duplicate keys
  410. while ($this->avoidDTKeysDuplicates and isset($result[$each['login']][$counter])) {
  411. $counter++;
  412. }
  413. if (ispos($each['note'], 'MOCK:')) {
  414. $cashto = $each['balance'];
  415. }
  416. if (ispos($each['note'], 'BALANCESET:')) {
  417. $cashto = $each['summ'];
  418. }
  419. if ((!ispos($each['note'], 'MOCK:')) and (!ispos($each['note'], 'BALANCESET:'))) {
  420. if (is_numeric($each['summ']) and is_numeric($each['balance'])) {
  421. $cashto = $each['summ'] + $each['balance'];
  422. } else {
  423. $cashto = __('Corrupted');
  424. }
  425. }
  426. $result[$each['login']][$counter]['login'] = $each['login'];
  427. $result[$each['login']][$counter]['date'] = $each['date'];
  428. $result[$each['login']][$counter]['admin'] = $each['admin'];
  429. $result[$each['login']][$counter]['summ'] = $each['summ'];
  430. $result[$each['login']][$counter]['from'] = $each['balance'];
  431. $result[$each['login']][$counter]['to'] = $cashto;
  432. $result[$each['login']][$counter]['operation'] = 'Payment';
  433. $result[$each['login']][$counter]['note'] = $each['note'];
  434. $result[$each['login']][$counter]['cashtype'] = $each['cashtypeid'];
  435. }
  436. }
  437. /**
  438. * Balance corrections
  439. */
  440. if ($this->dateFilter) {
  441. $this->corrDb->where('date', 'LIKE', $this->dateFilter . '%');
  442. }
  443. $allCorrs = $this->corrDb->getAll();
  444. if (!empty($allCorrs)) {
  445. foreach ($allCorrs as $io => $each) {
  446. $counter = strtotime($each['date']);
  447. // trying to avoid duplicate keys
  448. while ($this->avoidDTKeysDuplicates and isset($result[$each['login']][$counter])) {
  449. $counter++;
  450. }
  451. $cashto = $each['summ'] + $each['balance'];
  452. $result[$each['login']][$counter]['login'] = $each['login'];
  453. $result[$each['login']][$counter]['date'] = $each['date'];
  454. $result[$each['login']][$counter]['admin'] = $each['admin'];
  455. $result[$each['login']][$counter]['summ'] = $each['summ'];
  456. $result[$each['login']][$counter]['from'] = $each['balance'];
  457. $result[$each['login']][$counter]['to'] = $cashto;
  458. $result[$each['login']][$counter]['operation'] = 'Correcting';
  459. $result[$each['login']][$counter]['note'] = $each['note'];
  460. $result[$each['login']][$counter]['cashtype'] = $each['cashtypeid'];
  461. }
  462. }
  463. return ($result);
  464. }
  465. /**
  466. * Harvests some fees from stargazer log to database
  467. *
  468. * @param string $customDateMask parse only explicit date range log records instead of full log scan
  469. *
  470. * @return int
  471. */
  472. public function harvestFees($customDateMask = '') {
  473. $stgLog = $this->alterConf['STG_LOG_PATH'];
  474. $feeadmin = 'stargazer';
  475. $feenote = '';
  476. $feecashtype = 0;
  477. $feeoperation = 'Fee';
  478. $result = 0;
  479. $lineCount = 0;
  480. $dateMaskFilter = '';
  481. if ($customDateMask) {
  482. $dateMaskFilter = $customDateMask;
  483. }
  484. if (file_exists($stgLog)) {
  485. $this->feesDb->selectable('id,hash');
  486. if ($customDateMask) {
  487. $this->feesDb->where('date', 'LIKE', $dateMaskFilter . '%');
  488. }
  489. $alreadyHarvested = $this->feesDb->getAll('hash');
  490. //here per-line file read to avoid memory overheads
  491. $handle = fopen($stgLog, "r");
  492. // checking for "handle" to be non-empty, e.g. the "fopen()" didn't return "false"
  493. // or we might find ourselves in an infinite loop
  494. if (empty($handle)) {
  495. log_register('FEES HARVESTER: FAILED TO OPEN "' . $stgLog . '"');
  496. } else {
  497. while (!feof($handle)) {
  498. $eachline = fgets($handle);
  499. if (!empty($eachline)) {
  500. $requiredDateOffset = false;
  501. if ($customDateMask) {
  502. if (ispos($eachline, $dateMaskFilter)) {
  503. $requiredDateOffset = true;
  504. }
  505. } else {
  506. $requiredDateOffset = true;
  507. }
  508. if ($requiredDateOffset) {
  509. if (ispos($eachline, self::MASK_FEE)) {
  510. $eachfee = explode(' ', $eachline);
  511. if (isset($eachfee[self::OFFSET_TIME])) {
  512. $feefrom = str_replace("'.", '', $eachfee[self::OFFSET_FROM]);
  513. $feeto = str_replace("'.", '', $eachfee[self::OFFSET_TO]);
  514. $feefrom = str_replace("'", '', $feefrom);
  515. $feeto = str_replace("'", '', $feeto);
  516. $login = $eachfee[self::OFFSET_LOGIN];
  517. $login = str_replace("'", '', $login);
  518. $login = str_replace(':', '', $login);
  519. $login = ubRouting::filters($login, 'mres');
  520. $date = $eachfee[self::OFFSET_DATE] . ' ' . $eachfee[self::OFFSET_TIME];
  521. $summ = $feeto - $feefrom;
  522. $hash = md5($date . $login . $summ . $feefrom . $feeto);
  523. if (!isset($alreadyHarvested[$hash])) {
  524. $this->feesDb->data('hash', $hash);
  525. $this->feesDb->data('login', $login);
  526. $this->feesDb->data('date', $date);
  527. $this->feesDb->data('admin', $feeadmin);
  528. $this->feesDb->data('from', $feefrom);
  529. $this->feesDb->data('to', $feeto);
  530. $this->feesDb->data('summ', $summ);
  531. $this->feesDb->data('note', $feenote);
  532. $this->feesDb->data('cashtype', $feecashtype);
  533. $this->feesDb->create();
  534. $alreadyHarvested[$hash] = array('harvested');
  535. $result++;
  536. }
  537. }
  538. $lineCount++;
  539. }
  540. }
  541. }
  542. }
  543. fclose($handle);
  544. }
  545. }
  546. $timeRange = (!empty($customDateMask)) ? $customDateMask : 'ALL_TIME';
  547. log_register('FEES HARVESTED `' . $result . '` OF `' . $lineCount . '` RECORDS PARSED BY `' . $timeRange . '`');
  548. if ($this->onlineShowLastFeeChargeON) {
  549. $this->getLastFeeChargesAll();
  550. }
  551. return ($result);
  552. }
  553. /**
  554. * Stores last fee charge data to system cache
  555. *
  556. * @return void
  557. */
  558. public static function getLastFeeChargesAll() {
  559. $feesDb = new NyanORM(self::TABLE_FEES);
  560. $feesDb->selectable('login, summ, MAX(`date`) as `max_date`');
  561. $feesDb->groupBy('login');
  562. $lastFeeChargeData = $feesDb->getAll('login');
  563. if (!empty($lastFeeChargeData)) {
  564. $ubCache = new UbillingCache();
  565. $ubCache->set('STG_LAST_FEE_CHARGE', $lastFeeChargeData);
  566. log_register('FEES HARVESTER: ONLINE_SHOW_LAST_FEECHARGE data cache have been updated');
  567. }
  568. }
  569. /**
  570. * Returns array of all payments by some user
  571. *
  572. * @param string $login existing user login
  573. *
  574. * @return array
  575. */
  576. public function getPayments($login) {
  577. $login = ubRouting::filters($login, 'mres');
  578. $this->paymentsDb->where('login', '=', $login);
  579. $allpayments = $this->paymentsDb->getAll();
  580. $result = array();
  581. if (!empty($allpayments)) {
  582. foreach ($allpayments as $io => $eachpayment) {
  583. $counter = strtotime($eachpayment['date']);
  584. // trying to avoid duplicate keys
  585. while ($this->avoidDTKeysDuplicates and array_key_exists($counter, $result)) {
  586. $counter++;
  587. }
  588. if (ispos($eachpayment['note'], 'MOCK:')) {
  589. $cashto = $eachpayment['balance'];
  590. }
  591. if (ispos($eachpayment['note'], 'BALANCESET:')) {
  592. $cashto = $eachpayment['summ'];
  593. }
  594. if ((!ispos($eachpayment['note'], 'MOCK:')) and (!ispos($eachpayment['note'], 'BALANCESET:'))) {
  595. if (is_numeric($eachpayment['summ']) and is_numeric($eachpayment['balance'])) {
  596. $cashto = $eachpayment['summ'] + $eachpayment['balance'];
  597. } else {
  598. $cashto = __('Corrupted');
  599. }
  600. }
  601. $result[$counter]['login'] = $login;
  602. $result[$counter]['date'] = $eachpayment['date'];
  603. $result[$counter]['admin'] = $eachpayment['admin'];
  604. $result[$counter]['summ'] = $eachpayment['summ'];
  605. $result[$counter]['from'] = $eachpayment['balance'];
  606. $result[$counter]['to'] = $cashto;
  607. $result[$counter]['operation'] = 'Payment';
  608. $result[$counter]['note'] = $eachpayment['note'];
  609. $result[$counter]['cashtype'] = $eachpayment['cashtypeid'];
  610. }
  611. }
  612. return ($result);
  613. }
  614. /**
  615. * Returns array of all payments of user by some login
  616. *
  617. * @param string $login existing user login
  618. * @return array
  619. */
  620. public function getPaymentsCorr($login) {
  621. $login = ubRouting::filters($login, 'mres');
  622. $this->corrDb->where('login', '=', $login);
  623. $allpayments = $this->corrDb->getAll();
  624. $result = array();
  625. if (!empty($allpayments)) {
  626. foreach ($allpayments as $io => $eachpayment) {
  627. $counter = strtotime($eachpayment['date']);
  628. // trying to avoid duplicate keys
  629. while ($this->avoidDTKeysDuplicates and array_key_exists($counter, $result)) {
  630. $counter++;
  631. }
  632. $cashto = $eachpayment['summ'] + $eachpayment['balance'];
  633. $result[$counter]['login'] = $login;
  634. $result[$counter]['date'] = $eachpayment['date'];
  635. $result[$counter]['admin'] = $eachpayment['admin'];
  636. $result[$counter]['summ'] = $eachpayment['summ'];
  637. $result[$counter]['from'] = $eachpayment['balance'];
  638. $result[$counter]['to'] = $cashto;
  639. $result[$counter]['operation'] = 'Correcting';
  640. $result[$counter]['note'] = $eachpayment['note'];
  641. $result[$counter]['cashtype'] = $eachpayment['cashtypeid'];
  642. }
  643. }
  644. return ($result);
  645. }
  646. /**
  647. * Returns array of cashtype names
  648. *
  649. * @return array
  650. */
  651. function getCashTypeNames() {
  652. $result = zb_CashGetTypesNamed();
  653. return ($result);
  654. }
  655. /**
  656. * Renders result of default fundsflow module
  657. *
  658. * @param array $fundsflow
  659. */
  660. public function renderArray($fundsflow) {
  661. global $ubillingConfig;
  662. $timeIntervalPalette = $ubillingConfig->getAlterParam('FUNDSFLOW_EXTCOLORING');
  663. $timeIntervalColoringFlag = ($timeIntervalPalette) ? true : false;
  664. $allcashtypes = $this->getCashTypeNames();
  665. $allservicenames = zb_VservicesGetAllNamesLabeled();
  666. @$employeeNames = unserialize(ts_GetAllEmployeeLoginsCached());
  667. $result = '';
  668. $tablecells = '';
  669. if ($timeIntervalColoringFlag) {
  670. $tablecells .= wf_TableCell('');
  671. }
  672. $tablecells .= wf_TableCell(__('Date'));
  673. $tablecells .= wf_TableCell(__('Cash'));
  674. $tablecells .= wf_TableCell(__('From'));
  675. $tablecells .= wf_TableCell(__('To'));
  676. $tablecells .= wf_TableCell(__('Operation'));
  677. $tablecells .= wf_TableCell(__('Cash type'));
  678. $tablecells .= wf_TableCell(__('Notes'));
  679. $tablecells .= wf_TableCell(__('Admin'));
  680. $tablerows = wf_TableRow($tablecells, 'row1');
  681. if (!empty($fundsflow)) {
  682. foreach ($fundsflow as $io => $each) {
  683. //default operation type
  684. $operation = $each['operation'];
  685. //cashtype setting
  686. if ($each['cashtype'] != 0) {
  687. @$cashtype = $allcashtypes[$each['cashtype']];
  688. } else {
  689. $cashtype = __('Fee');
  690. }
  691. //coloring
  692. $efc = wf_tag('font', true);
  693. if ($each['operation'] == 'Fee') {
  694. $fc = wf_tag('font', false, '', 'color="#' . $this->colorFee . '"');
  695. }
  696. if ($each['operation'] == 'Payment') {
  697. $fc = wf_tag('font', false, '', 'color="#' . $this->colorPayment . '"');
  698. }
  699. if ($each['operation'] == 'Correcting') {
  700. $fc = wf_tag('font', false, '', 'color="#' . $this->colorCorrecting . '"');
  701. }
  702. if (ispos($each['note'], 'MOCK:')) {
  703. $fc = wf_tag('font', false, '', 'color="#' . $this->colorMock . '"');
  704. }
  705. if (ispos($each['note'], 'BALANCESET:')) {
  706. $fc = wf_tag('font', false, '', 'color="#' . $this->colorSet . '"');
  707. }
  708. //virtual services fees
  709. if ((ispos($each['note'], 'Service:')) and ($each['summ'] < 0)) {
  710. $fc = wf_tag('font', false, '', 'color="#' . $this->colorAdditionalFee . '"');
  711. $operation = __('Virtual service');
  712. }
  713. //virtual services bonuses
  714. if ((ispos($each['note'], 'Service:')) and ($each['summ'] >= 0)) {
  715. $fc = wf_tag('font', false, '', 'color="#' . $this->colorBonus . '"');
  716. $operation = __('Bonus');
  717. }
  718. //Megogo fees
  719. if (ispos($each['note'], 'MEGOGO:')) {
  720. $fc = wf_tag('font', false, '', 'color="#' . $this->colorAdditionalFee . '"');
  721. $operation = __('Service') . ' ' . __('Megogo');
  722. }
  723. //OmegaTV fees
  724. if (ispos($each['note'], 'OMEGATV:')) {
  725. $fc = wf_tag('font', false, '', 'color="#' . $this->colorAdditionalFee . '"');
  726. $operation = __('Service') . ' ' . __('OmegaTV');
  727. }
  728. //ProstoTV fees
  729. if (ispos($each['note'], 'PROSTOTV:')) {
  730. $fc = wf_tag('font', false, '', 'color="#' . $this->colorAdditionalFee . '"');
  731. $operation = __('Service') . ' ' . __('ProstoTV');
  732. }
  733. //YouTV fees
  734. if (ispos($each['note'], 'YOUTV:')) {
  735. $fc = wf_tag('font', false, '', 'color="#' . $this->colorAdditionalFee . '"');
  736. $operation = __('Service') . ' ' . __('YouTV');
  737. }
  738. //TrinityTV/SweetTV fees
  739. if (ispos($each['note'], 'TRINITYTV:')) {
  740. $fc = wf_tag('font', false, '', 'color="#' . $this->colorAdditionalFee . '"');
  741. $operation = __('Service') . ' ' . __('TrinityTV');
  742. }
  743. //OllTV fees
  744. if (ispos($each['note'], 'OLLTV:')) {
  745. $fc = wf_tag('font', false, '', 'color="#' . $this->colorAdditionalFee . '"');
  746. $operation = __('Service') . ' ' . __('OllTV');
  747. }
  748. //Self crediting fees
  749. if (ispos($each['note'], 'SCFEE')) {
  750. $creditColor = (@$this->alterConf['CREDIT_EVERGARDEN']) ? $this->colorCreditViolet : $this->colorAdditionalFee;
  751. $fc = wf_tag('font', false, '', 'color="#' . $creditColor . '"');
  752. $operation = __('Service') . ' ' . __('credit');
  753. }
  754. //Self freezing fees
  755. if (ispos($each['note'], 'AFFEE')) {
  756. $fc = wf_tag('font', false, '', 'color="#' . $this->colorAdditionalFee . '"');
  757. $operation = __('Service') . ' ' . __('freezing');
  758. }
  759. //Tariff changing fee
  760. if (ispos($each['note'], 'TCHANGE:')) {
  761. $fc = wf_tag('font', false, '', 'color="#' . $this->colorAdditionalFee . '"');
  762. $operation = __('Service') . ' ' . __('change tariff');
  763. }
  764. //Penalty fees
  765. if (ispos($each['note'], 'PENALTY')) {
  766. $fc = wf_tag('font', false, '', 'color="#' . $this->colorAdditionalFee . '"');
  767. $operation = __('Penalty');
  768. }
  769. //SMS reminder service activation
  770. if (ispos($each['note'], 'REMINDER')) {
  771. $fc = wf_tag('font', false, '', 'color="#' . $this->colorAdditionalFee . '"');
  772. $operation = __('Service') . ' ' . __('SMS reminder');
  773. }
  774. //discount bonuses
  775. if (ispos($each['note'], 'DISCOUNT:')) {
  776. $fc = wf_tag('font', false, '', 'color="#' . $this->colorBonus . '"');
  777. $operation = __('Discount');
  778. }
  779. //friendship bonuses
  780. if (ispos($each['note'], 'FRIENDSHIP')) {
  781. $fc = wf_tag('font', false, '', 'color="#' . $this->colorBonus . '"');
  782. $operation = __('Friendship');
  783. }
  784. //manual charged
  785. if (ispos($each['note'], 'ECHARGE')) {
  786. $fc = wf_tag('font', false, '', 'color="#' . $this->colorAdditionalFee . '"');
  787. $operation = __('Charged');
  788. }
  789. //DDT charged
  790. if (ispos($each['note'], 'DDT')) {
  791. $fc = wf_tag('font', false, '', 'color="#' . $this->colorAdditionalFee . '"');
  792. $operation = __('Charged');
  793. $cashtype = __('Fee');
  794. }
  795. //Visor camera charged
  796. if (ispos($each['note'], 'VISORCHARGE')) {
  797. $fc = wf_tag('font', false, '', 'color="#' . $this->colorAdditionalFee . '"');
  798. $operation = __('Service') . ' ' . __('Camera');
  799. $cashtype = __('Fee');
  800. }
  801. //Visor cash moved from primary account
  802. if (ispos($each['note'], 'VISORPUSH')) {
  803. $fc = wf_tag('font', false, '', 'color="#' . $this->colorBonus . '"');
  804. $operation = __('Charged');
  805. $cashtype = __('Payment');
  806. }
  807. //PowerTariffs Internet service fee
  808. if (ispos($each['note'], 'PTFEE')) {
  809. $fc = wf_tag('font', false, '', 'color="#' . $this->colorFee . '"');
  810. $operation = __('Fee');
  811. $cashtype = __('Fee');
  812. }
  813. //manual charged
  814. if (ispos($each['note'], 'EXTFEE')) {
  815. $fc = wf_tag('font', false, '', 'color="#' . $this->colorAdditionalFee . '"');
  816. $operation = __('Fee');
  817. $cashtype = __('Fee');
  818. }
  819. //taxsup fees
  820. if (ispos($each['note'], 'TAXSUP:')) {
  821. $fc = wf_tag('font', false, '', 'color="#' . $this->colorAdditionalFee . '"');
  822. $operation = __('Fee');
  823. $cashtype = __('Fee');
  824. }
  825. //deferred sale
  826. if (ispos($each['note'], 'DEFSALE')) {
  827. $fc = wf_tag('font', false, '', 'color="#' . $this->colorAdditionalFee . '"');
  828. $operation = __('Charged');
  829. $cashtype = __('Fee');
  830. }
  831. //notes translation
  832. if ($this->alterConf['TRANSLATE_PAYMENTS_NOTES']) {
  833. $displaynote = zb_TranslatePaymentNote($each['note'], $allservicenames);
  834. } else {
  835. $displaynote = $each['note'];
  836. }
  837. //admin login detection
  838. $adminName = (isset($employeeNames[$each['admin']])) ? $employeeNames[$each['admin']] : $each['admin'];
  839. //time interval coloring
  840. if ($timeIntervalColoringFlag) {
  841. $operationMonth = (!empty($each['date'])) ? date("m", strtotime($each['date'])) : '';
  842. $intervalColor = wf_genColorCodeFromText($operationMonth, $timeIntervalPalette);
  843. }
  844. $tablecells = '';
  845. if ($timeIntervalColoringFlag) {
  846. $tablecells .= wf_TableCell('&nbsp;', '', '', 'bgcolor="#' . $intervalColor . '"');
  847. }
  848. $tablecells .= wf_TableCell($fc . $each['date'] . $efc, '150');
  849. $tablecells .= wf_TableCell($fc . $each['summ'] . $efc);
  850. $tablecells .= wf_TableCell($fc . $each['from'] . $efc);
  851. $tablecells .= wf_TableCell($fc . $each['to'] . $efc);
  852. $tablecells .= wf_TableCell($fc . __($operation) . $efc);
  853. $tablecells .= wf_TableCell($cashtype);
  854. $tablecells .= wf_TableCell($displaynote);
  855. $tablecells .= wf_TableCell($adminName);
  856. $tablerows .= wf_TableRow($tablecells, 'row3');
  857. }
  858. $legendcells = wf_TableCell(__('Legend') . ':');
  859. $legendcells .= wf_TableCell(wf_tag('font', false, '', 'color="#' . $this->colorPayment . '"') . __('Payment') . $efc);
  860. $legendcells .= wf_TableCell(wf_tag('font', false, '', 'color="#' . $this->colorFee . '"') . __('Fee') . $efc);
  861. $legendcells .= wf_TableCell(wf_tag('font', false, '', 'color="#' . $this->colorBonus . '"') . __('Bonuses') . $efc);
  862. $legendcells .= wf_TableCell(wf_tag('font', false, '', 'color="#' . $this->colorAdditionalFee . '"') . __('Additional fees') . $efc);
  863. $legendcells .= wf_TableCell(wf_tag('font', false, '', 'color="#' . $this->colorCorrecting . '"') . __('Correct saldo') . $efc);
  864. $legendcells .= wf_TableCell(wf_tag('font', false, '', 'color="#' . $this->colorMock . '"') . __('Mock payment') . $efc);
  865. $legendcells .= wf_TableCell(wf_tag('font', false, '', 'color="#' . $this->colorSet . '"') . __('Set cash') . $efc);
  866. if (@$this->alterConf['CREDIT_EVERGARDEN']) {
  867. $legendcells .= wf_TableCell(wf_tag('font', false, '', 'color="#' . $this->colorCreditViolet . '"') . __('Credit') . $efc);
  868. }
  869. $legendrows = wf_TableRow($legendcells, 'row3');
  870. $legend = wf_TableBody($legendrows, '60%', 0, 'glamour');
  871. $legend .= wf_tag('div', false, '', 'style="clear:both;"') . wf_tag('div', true);
  872. $legend .= wf_delimiter();
  873. $result = wf_TableBody($tablerows, '100%', 0, 'sortable');
  874. $result .= $legend;
  875. } else {
  876. $messages = new UbillingMessageHelper();
  877. $result .= $messages->getStyledMessage(__('Nothing to show'), 'warning');
  878. }
  879. return ($result);
  880. }
  881. /**
  882. * Transforms array for normal output
  883. *
  884. * @param array $fundsflow
  885. *
  886. * @return array
  887. */
  888. public function transformArray($fundsflow) {
  889. if (!empty($fundsflow)) {
  890. ksort($fundsflow);
  891. $fundsflow = array_reverse($fundsflow);
  892. }
  893. return ($fundsflow);
  894. }
  895. /**
  896. * Extracts funds only with some date pattern
  897. *
  898. * @param array $fundsflow standard fundsflow array
  899. * @param string $date
  900. *
  901. * @return array
  902. */
  903. public function filterByDate($fundsflow, $date) {
  904. $result = array();
  905. if (!empty($fundsflow)) {
  906. foreach ($fundsflow as $timestamp => $flowdata) {
  907. if (ispos($flowdata['date'], $date)) {
  908. $result[$timestamp] = $flowdata;
  909. }
  910. }
  911. }
  912. return ($result);
  913. }
  914. /**
  915. * Renders user tags if available
  916. *
  917. * @param string $userLogin
  918. *
  919. * @return string
  920. */
  921. protected function renderUserTags($userLogin) {
  922. $result = '';
  923. if (!empty($userLogin)) {
  924. if (isset($this->userTags[$userLogin])) {
  925. if (!empty($this->userTags[$userLogin])) {
  926. $result .= implode(', ', $this->userTags[$userLogin]);
  927. }
  928. }
  929. }
  930. return ($result);
  931. }
  932. /**
  933. * Renders table for corps users payments/fees stats
  934. *
  935. * @param array $fundsFlows
  936. * @param array $corpsData
  937. * @param array $corpUsers
  938. * @param array $allUserTariffs
  939. * @param array $allUserContracts
  940. *
  941. * @return string
  942. */
  943. public function renderCorpsFlows($num, $fundsFlows, $corpsData, $corpUsers, $allUserContracts, $allUsersCash, $allUserTariffs, $allTariffPrices) {
  944. $result = '';
  945. $rawData = array();
  946. $rawData['balance'] = 0;
  947. $rawData['payments'] = 0;
  948. $rawData['paymentscorr'] = 0;
  949. $rawData['fees'] = 0;
  950. $rawData['login'] = '';
  951. $rawData['contract'] = '';
  952. $rawData['corpid'] = '';
  953. $rawData['corpname'] = '';
  954. $rawData['balance'] = 0;
  955. $rawData['used'] = 0;
  956. //loading some user tags
  957. if (empty($this->userTags)) {
  958. $this->loadUserTags();
  959. }
  960. if (!empty($fundsFlows)) {
  961. foreach ($fundsFlows as $io => $eachop) {
  962. if ($eachop['operation'] == 'Fee') {
  963. $rawData['fees'] = $rawData['fees'] + abs($eachop['summ']);
  964. }
  965. if ($eachop['operation'] == 'Payment') {
  966. $rawData['payments'] = $rawData['payments'] + abs($eachop['summ']);
  967. }
  968. if ($eachop['operation'] == 'Correcting') {
  969. $rawData['paymentscorr'] = $rawData['paymentscorr'] + abs($eachop['summ']);
  970. }
  971. }
  972. $rawData['login'] = $eachop['login'];
  973. if (!isset($this->allBuriedUsers[$rawData['login']])) {
  974. @$rawData['contract'] = array_search($eachop['login'], $allUserContracts);
  975. @$rawData['corpid'] = $corpUsers[$eachop['login']];
  976. @$rawData['corpname'] = $corpsData[$rawData['corpid']]['corpname'];
  977. $rawData['balance'] = $allUsersCash[$eachop['login']];
  978. $rawData['used'] = $rawData['fees'];
  979. //forming result
  980. $cells = wf_TableCell($num);
  981. $corpLink = wf_Link('?module=corps&show=corps&editid=' . $rawData['corpid'], $rawData['corpname'], false, '');
  982. $cells .= wf_TableCell($corpLink);
  983. if ($rawData['contract']) {
  984. $loginLink = wf_Link('?module=userprofile&username=' . $rawData['login'], $rawData['contract'], false, '');
  985. } else {
  986. $loginLink = wf_Link('?module=userprofile&username=' . $rawData['login'], $rawData['login'], false, '');
  987. }
  988. if (!empty($rawData['login'])) {
  989. $currentTags = $this->renderUserTags($rawData['login']);
  990. } else {
  991. $currentTags = '';
  992. }
  993. $cells .= wf_TableCell($loginLink);
  994. $cells .= wf_TableCell($currentTags);
  995. $cells .= wf_TableCell(@$allTariffPrices[$allUserTariffs[$rawData['login']]]);
  996. $cells .= wf_TableCell(round($rawData['payments'], 2));
  997. $cells .= wf_TableCell(round($rawData['paymentscorr'], 2));
  998. $cells .= wf_TableCell(round($rawData['balance'], 2));
  999. $cells .= wf_TableCell(round($rawData['used'], 2));
  1000. $result .= wf_TableRow($cells, 'row3');
  1001. //fill summary data
  1002. $this->fundsTmp['col1'] += $rawData['payments'];
  1003. $this->fundsTmp['col2'] += $rawData['paymentscorr'];
  1004. $this->fundsTmp['col3'] += $rawData['balance'];
  1005. $this->fundsTmp['col4'] += $rawData['used'];
  1006. }
  1007. }
  1008. return ($result);
  1009. }
  1010. /**
  1011. * Returns totals data from previous renderCorpsFlows runs
  1012. *
  1013. * @return string
  1014. */
  1015. public function renderCorpsFlowsTotal() {
  1016. $result = '';
  1017. if (!empty($this->fundsTmp)) {
  1018. $cells = wf_TableCell('');
  1019. $cells .= wf_TableCell(__('Total'));
  1020. $cells .= wf_TableCell('');
  1021. $cells .= wf_TableCell('');
  1022. $cells .= wf_TableCell('');
  1023. $cells .= wf_TableCell(round($this->fundsTmp['col1'], 2));
  1024. $cells .= wf_TableCell(round($this->fundsTmp['col2'], 2));
  1025. $cells .= wf_TableCell(round($this->fundsTmp['col3'], 2));
  1026. $cells .= wf_TableCell(round($this->fundsTmp['col4'], 2));
  1027. $result .= wf_TableRow($cells, 'row2');
  1028. }
  1029. return ($result);
  1030. }
  1031. /**
  1032. * Returns corpsacts table headers
  1033. *
  1034. * @param string $year
  1035. * @param string $month
  1036. *
  1037. * @return string
  1038. */
  1039. public function renderCorpsFlowsHeaders($year, $month) {
  1040. $monthArr = months_array();
  1041. $month = $monthArr[$month];
  1042. $month = rcms_date_localise($month);
  1043. $cd = wf_tag('p', false, '', 'align="center"') . wf_tag('b');
  1044. $cde = wf_tag('b', true) . wf_tag('p', true);
  1045. $result = wf_tag('tr', false, 'row2');
  1046. $result .= wf_TableCell($cd . __('Num #') . $cde, '15', '', 'rowspan="3"');
  1047. $result .= wf_TableCell($cd . __('Organisation') . $cde, '141', '', 'rowspan="3"');
  1048. $result .= wf_TableCell('', '62', '', '');
  1049. $result .= wf_TableCell('', '62', '', '');
  1050. $result .= wf_TableCell($cd . $month . ' ' . $year . $cde, '240', '', 'colspan="5"');
  1051. $result .= wf_tag('tr', true);
  1052. $result .= wf_tag('tr', false, 'row2');
  1053. $result .= wf_TableCell($cd . __('Contract') . $cde, '62', '', 'rowspan="2"');
  1054. $result .= wf_TableCell($cd . __('Tags') . $cde, '62', '', 'rowspan="2"');
  1055. $result .= wf_TableCell($cd . __('Fee') . $cde, '62', '', 'rowspan="2"');
  1056. $result .= wf_TableCell($cd . __('Income') . $cde, '84', '', 'colspan="2"');
  1057. $result .= wf_TableCell($cd . __('Current deposit') . $cde, '68', '', 'rowspan="2"');
  1058. $result .= wf_TableCell($cd . __('Expenditure') . $cde, '84', '', 'rowspan="2"');
  1059. $result .= wf_tag('tr', true);
  1060. $result .= wf_tag('tr', false, 'row2');
  1061. $result .= wf_TableCell($cd . __('on deposit') . $cde, '41');
  1062. $result .= wf_TableCell($cd . __('corr.') . $cde, '41');
  1063. $result .= wf_tag('tr', true);
  1064. return ($result);
  1065. }
  1066. /**
  1067. * Returns year/month selectors form
  1068. *
  1069. * @return string
  1070. */
  1071. public function renderCorpsFlowsDateForm() {
  1072. $allagents = zb_ContrAhentGetAllData();
  1073. $tmpArr = array();
  1074. $tmpArr[''] = __('Any');
  1075. if (!empty($allagents)) {
  1076. foreach ($allagents as $io => $eachagent) {
  1077. $tmpArr[$eachagent['id']] = $eachagent['contrname'];
  1078. }
  1079. }
  1080. /**
  1081. * Again and again and again and again
  1082. * We Smash the Game BUHA!!
  1083. * And again and again and again and again
  1084. * Remember our name / Furyo 'til I Die
  1085. */
  1086. $inputs = wf_YearSelectorPreset('yearsel', __('Year'), false, ubRouting::post('yearsel')) . ' ';
  1087. $inputs .= wf_MonthSelector('monthsel', __('Month'), ubRouting::post('monthsel'), false) . ' ';
  1088. $inputs .= wf_Selector('agentsel', $tmpArr, __('Contrahent name'), ubRouting::post('agentsel'), false);
  1089. $inputs .= wf_Submit(__('Show'));
  1090. $result = wf_Form('', 'POST', $inputs, 'glamour');
  1091. return ($result);
  1092. }
  1093. /**
  1094. * Returns user online left days
  1095. *
  1096. * @param string $login existing users login
  1097. * @param bool $rawdays show only days count
  1098. *
  1099. * @return string
  1100. */
  1101. public function getOnlineLeftCount($login, $rawDays = false, $includeVServices = false) {
  1102. $userData = zb_UserGetStargazerData($login);
  1103. $balanceExpire = '';
  1104. if (!empty($userData)) {
  1105. $userTariff = $userData['Tariff'];
  1106. $userBalanceRaw = $userData['Cash'];
  1107. $userBalance = $userData['Cash'];
  1108. $tariffData = zb_TariffGetData($userTariff);
  1109. $userFeeOffset = 0;
  1110. $daysOnLine = 0;
  1111. $totalVsrvPrice = 0;
  1112. if (empty($tariffData)) {
  1113. //user have no tariff
  1114. $tariffData['name'] = '*_NO_TARIFF_*';
  1115. $tariffData['Fee'] = 0;
  1116. $tariffData['period'] = 'month';
  1117. }
  1118. $tariffFee = $tariffData['Fee'];
  1119. $tariffPeriod = isset($tariffData['period']) ? $tariffData['period'] : 'month';
  1120. if ($this->alterConf['PT_ENABLED']) {
  1121. $powerTariffs = new PowerTariffs();
  1122. //suspicious tariff?
  1123. if ($tariffFee == 0) {
  1124. //wow too much power!
  1125. if ($powerTariffs->isPowerTariff($userTariff)) {
  1126. $tariffFee = $powerTariffs->getPowerTariffPrice($userTariff);
  1127. $userFeeOffset = $powerTariffs->getUserOffsetDay($login);
  1128. $maxDay = ($powerTariffs->getMaxDay() - 1);
  1129. if ($userFeeOffset == 0) {
  1130. $userFeeOffset = (date('j') < $maxDay) ? date('j') + 1 : 1;
  1131. $daysOnLine = (date('j') < $maxDay) ? 0 : date('j');
  1132. } else {
  1133. if ($userFeeOffset < 0) {
  1134. $userFeeOffset = (date('j') < $maxDay) ? date('j') + 1 : 1;
  1135. }
  1136. $daysOnLine = ($userFeeOffset == date('j')) ? 0 : (($userFeeOffset < date('j')) ? -1 : date('j') * -1);
  1137. }
  1138. $userFeeOffset = $userFeeOffset - 1;
  1139. }
  1140. }
  1141. }
  1142. if ($includeVServices) {
  1143. $totalVsrvPrice = zb_VservicesGetUserPricePeriod($login, $tariffPeriod);
  1144. $tariffFee += $totalVsrvPrice;
  1145. }
  1146. if (isset($this->alterConf['SPREAD_FEE'])) {
  1147. if ($this->alterConf['SPREAD_FEE']) {
  1148. $spreadFee = true;
  1149. } else {
  1150. $spreadFee = false;
  1151. }
  1152. } else {
  1153. $spreadFee = false;
  1154. }
  1155. if ($userBalance >= 0) {
  1156. if ($tariffFee > 0) {
  1157. //spread fee
  1158. if ($spreadFee) {
  1159. if ($tariffPeriod == 'month') {
  1160. //monthly period
  1161. while ($userBalance >= 0) {
  1162. $daysOnLine++;
  1163. $dayFee = $tariffFee / date('t', time() + ($daysOnLine * 24 * 60 * 60));
  1164. $userBalance = $userBalance - $dayFee;
  1165. }
  1166. } else {
  1167. //daily period
  1168. while ($userBalance >= 0) {
  1169. $daysOnLine++;
  1170. $userBalance = $userBalance - $tariffFee;
  1171. }
  1172. }
  1173. } else {
  1174. //non spread normal fee
  1175. if ($tariffPeriod == 'month') {
  1176. //monthly non spread fee
  1177. while ($userBalance >= 0) {
  1178. $daysOnLine = $daysOnLine + $userFeeOffset + date('t', time() + ($daysOnLine * 24 * 60 * 60)) - date('d', time() + ($daysOnLine * 24 * 60 * 60)) + 1;
  1179. $userBalance = $userBalance - $tariffFee;
  1180. }
  1181. } else {
  1182. //daily non spread fee
  1183. while ($userBalance >= 0) {
  1184. $daysOnLine++;
  1185. $userBalance = $userBalance - $tariffFee;
  1186. }
  1187. }
  1188. }
  1189. $daysLabel = $daysOnLine;
  1190. $dateLabel = date("d.m.Y", time() + ($daysOnLine * 24 * 60 * 60));
  1191. } else {
  1192. $daysLabel = '&infin;';
  1193. $dateLabel = '&infin;';
  1194. }
  1195. $balanceExpire = wf_tag('span', false, 'alert_info');
  1196. $balanceExpire .= __('Current Cash state') . ': ' . wf_tag('b') . $userBalanceRaw . wf_tag('b', true) . ', ' . __('which should be enough for another');
  1197. $balanceExpire .= ' ' . $daysLabel . ' ' . __('days') . ' ' . __('of service usage') . ' ';
  1198. $balanceExpire .= __('or enought till the') . ' ' . $dateLabel . ' ';
  1199. $balanceExpire .= __('according to the tariff') . ' ' . $userTariff . (($includeVServices) ? ' + ' . __('virtual services') : '') . ' (' . $tariffFee . ' / ' . __($tariffPeriod) . ')';
  1200. $balanceExpire .= wf_tag('span', true);
  1201. } else {
  1202. $balanceExpire = wf_tag('span', false, 'alert_warning') . __('Current Cash state') . ': ' . wf_tag('b') . $userBalanceRaw . wf_tag('b', true);
  1203. $balanceExpire .= ', ' . __('indebtedness') . '!' . ' ' . wf_tag('span', true);
  1204. }
  1205. if ($rawDays) {
  1206. $balanceExpire = $daysOnLine;
  1207. }
  1208. }
  1209. return ($balanceExpire);
  1210. }
  1211. /**
  1212. * Loads all user and tariffs data
  1213. *
  1214. * @return void
  1215. */
  1216. public function runDataLoders() {
  1217. $this->loadAllUserData();
  1218. $this->loadAllTariffsData();
  1219. }
  1220. /**
  1221. * Returns user online left days without additional DB queries
  1222. * runDataLoaders() must be run once, before usage
  1223. *
  1224. * @param string $login existing users login
  1225. *
  1226. * @return int >=0: days left, -1: debt, -2: zero tariff price
  1227. */
  1228. public function getOnlineLeftCountFast($login, $includeVServices = false) {
  1229. if (isset($this->allUserData[$login])) {
  1230. $userData = $this->allUserData[$login];
  1231. }
  1232. $daysOnLine = 0;
  1233. $totalVsrvPrice = 0;
  1234. if (!empty($userData)) {
  1235. $userTariff = $userData['Tariff'];
  1236. $userBalanceRaw = $userData['Cash'];
  1237. $userBalance = $userData['Cash'];
  1238. if (isset($this->allTariffsData[$userTariff])) {
  1239. $tariffData = $this->allTariffsData[$userTariff];
  1240. $tariffFee = $tariffData['Fee'];
  1241. $tariffPeriod = isset($tariffData['period']) ? $tariffData['period'] : 'month';
  1242. if ($includeVServices) {
  1243. $totalVsrvPrice = zb_VservicesGetUserPricePeriod($login, $tariffPeriod);
  1244. $tariffFee += $totalVsrvPrice;
  1245. }
  1246. if (isset($this->alterConf['SPREAD_FEE'])) {
  1247. if ($this->alterConf['SPREAD_FEE']) {
  1248. $spreadFee = true;
  1249. } else {
  1250. $spreadFee = false;
  1251. }
  1252. } else {
  1253. $spreadFee = false;
  1254. }
  1255. if ($userBalance >= 0) {
  1256. if ($tariffFee > 0) {
  1257. //spread fee
  1258. if ($spreadFee) {
  1259. if ($tariffPeriod == 'month') {
  1260. //monthly period
  1261. while ($userBalance >= 0) {
  1262. $daysOnLine++;
  1263. $dayFee = $tariffFee / date('t', time() + ($daysOnLine * 24 * 60 * 60));
  1264. $userBalance = $userBalance - $dayFee;
  1265. }
  1266. } else {
  1267. //daily period
  1268. while ($userBalance >= 0) {
  1269. $daysOnLine++;
  1270. $userBalance = $userBalance - $tariffFee;
  1271. }
  1272. }
  1273. } else {
  1274. //non spread fee
  1275. if ($tariffPeriod == 'month') {
  1276. //monthly non spread fee
  1277. while ($userBalance >= 0) {
  1278. $daysOnLine = $daysOnLine + date('t', time() + ($daysOnLine * 24 * 60 * 60)) - date('d', time() + ($daysOnLine * 24 * 60 * 60)) + 1;
  1279. $userBalance = $userBalance - $tariffFee;
  1280. }
  1281. } else {
  1282. //daily non spread fee
  1283. while ($userBalance >= 0) {
  1284. $daysOnLine++;
  1285. $userBalance = $userBalance - $tariffFee;
  1286. }
  1287. }
  1288. }
  1289. } else {
  1290. $daysOnLine = '-2';
  1291. }
  1292. } else {
  1293. $daysOnLine = '-1';
  1294. }
  1295. }
  1296. }
  1297. return ($daysOnLine);
  1298. }
  1299. /**
  1300. * Charges month freezing fee (i dont know why this is here)
  1301. *
  1302. * @return void
  1303. */
  1304. public function makeFreezeMonthFee($debug2log = false) {
  1305. $cost = $this->alterConf['FREEZEMONTH_COST'];
  1306. $cashType = $this->alterConf['FREEZEMONTH_CASHTYPE'];
  1307. $processedUsers = 0;
  1308. if ($debug2log) {
  1309. log_register('FROZEN FEE CHARGE PROCESSING STARTED. COST: ' . $cost . '. CASHTYPE: ' . $cashType);
  1310. }
  1311. if (!empty($this->alterConf['FREEZEMONTH_ONLY_TAG'])) {
  1312. log_register('FROZEN FEE CHARGE PROCESSING ONLY TAGS: ' . $this->alterConf['FREEZEMONTH_ONLY_TAG']);
  1313. $allUsersWithFMOTag = zb_UserGetAllTagsUnique('', $this->alterConf['FREEZEMONTH_ONLY_TAG']);
  1314. $allUserData = array_intersect_key($this->allUserData, $allUsersWithFMOTag);
  1315. } else {
  1316. $allUserData = $this->allUserData;
  1317. }
  1318. if (!empty($this->alterConf['FREEZEMONTH_EXCLUDE_TAG'])) {
  1319. log_register('FROZEN FEE CHARGE EXCLUDING TAGS: ' . $this->alterConf['FREEZEMONTH_EXCLUDE_TAG']);
  1320. $allUsersWithFMETag = zb_UserGetAllTagsUnique('', $this->alterConf['FREEZEMONTH_EXCLUDE_TAG']);
  1321. $allUserData = array_diff_key($allUserData, $allUsersWithFMETag);
  1322. }
  1323. if (!empty($allUserData)) {
  1324. foreach ($allUserData as $eachUser) {
  1325. if ($eachUser['Passive'] == 1) {
  1326. zb_CashAdd($eachUser['login'], -1 * $cost, 'add', $cashType, 'FROZEN FEE CHARGE:' . $cost);
  1327. $processedUsers++;
  1328. if ($debug2log) {
  1329. log_register('FROZEN FEE CHARGE AMOUNT ' . -1 * $cost . ' FOR USER (' . $eachUser['login'] . ')');
  1330. }
  1331. }
  1332. }
  1333. } elseif ($debug2log) {
  1334. log_register('FROZEN FEE CHARGE PROCESSING: NO USERS TO PROCESS FOUND');
  1335. }
  1336. if ($debug2log) {
  1337. log_register('FROZEN FEE CHARGE PROCESSING FINISHED FOR ' . $processedUsers . ' USERS');
  1338. }
  1339. }
  1340. /**
  1341. * Process possible duplicates and concatenates $fees, $payments and $corrections arrays
  1342. *
  1343. * @param array $fees
  1344. * @param array $payments
  1345. * @param array $corrections
  1346. *
  1347. * @return mixed
  1348. */
  1349. public function concatAvoidDuplicateKeys($fees, $payments, $corrections) {
  1350. // searching and fixing duplicates in fees - payments array
  1351. $duplicates = array_intersect_key($fees, $payments);
  1352. if (!empty($duplicates)) {
  1353. foreach ($duplicates as $key => $val) {
  1354. // walking through duplicates array and trying to get
  1355. // a unique key instead of existing duplicate key
  1356. if (array_key_exists($key, $payments)) {
  1357. $tmpVal = $payments[$key];
  1358. $tmpKey = $key + 1;
  1359. while (
  1360. array_key_exists($tmpKey, $fees) or
  1361. array_key_exists($tmpKey, $payments) or
  1362. array_key_exists($tmpKey, $corrections)
  1363. ) {
  1364. $tmpKey++;
  1365. }
  1366. // remove array item with duplicate key and set it's preserved value to new key
  1367. // we're not worried about the keys order as concatenated array
  1368. // will be later sorted by keys anyway
  1369. unset($payments[$key]);
  1370. $payments[$tmpKey] = $tmpVal;
  1371. }
  1372. }
  1373. }
  1374. // searching and fixing duplicates in fees - corrections array
  1375. $duplicates = array_intersect_key($fees, $corrections);
  1376. if (!empty($duplicates)) {
  1377. foreach ($duplicates as $key => $val) {
  1378. if (array_key_exists($key, $corrections)) {
  1379. $tmpVal = $corrections[$key];
  1380. $tmpKey = $key + 1;
  1381. while (
  1382. array_key_exists($tmpKey, $fees) or
  1383. array_key_exists($tmpKey, $payments) or
  1384. array_key_exists($tmpKey, $corrections)
  1385. ) {
  1386. $tmpKey++;
  1387. }
  1388. unset($corrections[$key]);
  1389. $corrections[$tmpKey] = $tmpVal;
  1390. }
  1391. }
  1392. }
  1393. // searching and fixing duplicates in payments - corrections array
  1394. $duplicates = array_intersect_key($payments, $corrections);
  1395. if (!empty($duplicates)) {
  1396. foreach ($duplicates as $key => $val) {
  1397. if (array_key_exists($key, $corrections)) {
  1398. $tmpVal = $corrections[$key];
  1399. $tmpKey = $key + 1;
  1400. while (
  1401. array_key_exists($tmpKey, $fees) or
  1402. array_key_exists($tmpKey, $payments) or
  1403. array_key_exists($tmpKey, $corrections)
  1404. ) {
  1405. $tmpKey++;
  1406. }
  1407. unset($corrections[$key]);
  1408. $corrections[$tmpKey] = $tmpVal;
  1409. }
  1410. }
  1411. }
  1412. // concatenate fixed arrays
  1413. $allFundsFlow = $fees + $payments + $corrections;
  1414. return ($allFundsFlow);
  1415. }
  1416. }