api.fundsflow.php 60 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593
  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. }
  506. else {
  507. $requiredDateOffset = true;
  508. }
  509. if ($requiredDateOffset) {
  510. if (ispos($eachline, self::MASK_FEE)) {
  511. $eachfee = explode(' ', $eachline);
  512. if (isset($eachfee[self::OFFSET_TIME])) {
  513. $feefrom = str_replace("'.", '', $eachfee[self::OFFSET_FROM]);
  514. $feeto = str_replace("'.", '', $eachfee[self::OFFSET_TO]);
  515. $feefrom = str_replace("'", '', $feefrom);
  516. $feeto = str_replace("'", '', $feeto);
  517. $login = $eachfee[self::OFFSET_LOGIN];
  518. $login = str_replace("'", '', $login);
  519. $login = str_replace(':', '', $login);
  520. $login = ubRouting::filters($login, 'mres');
  521. $date = $eachfee[self::OFFSET_DATE] . ' ' . $eachfee[self::OFFSET_TIME];
  522. $summ = $feeto - $feefrom;
  523. $hash = md5($date . $login . $summ . $feefrom . $feeto);
  524. if (!isset($alreadyHarvested[$hash])) {
  525. $this->feesDb->data('hash', $hash);
  526. $this->feesDb->data('login', $login);
  527. $this->feesDb->data('date', $date);
  528. $this->feesDb->data('admin', $feeadmin);
  529. $this->feesDb->data('from', $feefrom);
  530. $this->feesDb->data('to', $feeto);
  531. $this->feesDb->data('summ', $summ);
  532. $this->feesDb->data('note', $feenote);
  533. $this->feesDb->data('cashtype', $feecashtype);
  534. $this->feesDb->create();
  535. $alreadyHarvested[$hash] = array('harvested');
  536. $result++;
  537. }
  538. }
  539. $lineCount++;
  540. }
  541. }
  542. }
  543. }
  544. fclose($handle);
  545. }
  546. }
  547. $timeRange = (!empty($customDateMask)) ? $customDateMask : 'ALL_TIME';
  548. log_register('FEES HARVESTED `' . $result . '` OF `' . $lineCount . '` RECORDS PARSED BY `' . $timeRange . '`');
  549. if ($this->onlineShowLastFeeChargeON) {
  550. $this->getLastFeeChargesAll();
  551. }
  552. return($result);
  553. }
  554. /**
  555. * Stores last fee charge data to system cache
  556. *
  557. * @return void
  558. */
  559. public static function getLastFeeChargesAll() {
  560. $feesDb = new NyanORM(self::TABLE_FEES);
  561. $feesDb->selectable('login, summ, MAX(`date`) as `max_date`');
  562. $feesDb->groupBy('login');
  563. $lastFeeChargeData = $feesDb->getAll('login');
  564. if (!empty($lastFeeChargeData)) {
  565. $ubCache = new UbillingCache();
  566. $ubCache->set('STG_LAST_FEE_CHARGE', $lastFeeChargeData);
  567. log_register('FEES HARVESTER: ONLINE_SHOW_LAST_FEECHARGE data cache have been updated');
  568. }
  569. }
  570. /**
  571. * Returns array of all payments by some user
  572. *
  573. * @param string $login existing user login
  574. *
  575. * @return array
  576. */
  577. public function getPayments($login) {
  578. $login = ubRouting::filters($login, 'mres');
  579. $this->paymentsDb->where('login', '=', $login);
  580. $allpayments = $this->paymentsDb->getAll();
  581. $result = array();
  582. if (!empty($allpayments)) {
  583. foreach ($allpayments as $io => $eachpayment) {
  584. $counter = strtotime($eachpayment['date']);
  585. // trying to avoid duplicate keys
  586. while ($this->avoidDTKeysDuplicates and array_key_exists($counter, $result)) {
  587. $counter++;
  588. }
  589. if (ispos($eachpayment['note'], 'MOCK:')) {
  590. $cashto = $eachpayment['balance'];
  591. }
  592. if (ispos($eachpayment['note'], 'BALANCESET:')) {
  593. $cashto = $eachpayment['summ'];
  594. }
  595. if ((!ispos($eachpayment['note'], 'MOCK:')) AND (!ispos($eachpayment['note'], 'BALANCESET:'))) {
  596. if (is_numeric($eachpayment['summ']) AND is_numeric($eachpayment['balance'])) {
  597. $cashto = $eachpayment['summ'] + $eachpayment['balance'];
  598. } else {
  599. $cashto = __('Corrupted');
  600. }
  601. }
  602. $result[$counter]['login'] = $login;
  603. $result[$counter]['date'] = $eachpayment['date'];
  604. $result[$counter]['admin'] = $eachpayment['admin'];
  605. $result[$counter]['summ'] = $eachpayment['summ'];
  606. $result[$counter]['from'] = $eachpayment['balance'];
  607. $result[$counter]['to'] = $cashto;
  608. $result[$counter]['operation'] = 'Payment';
  609. $result[$counter]['note'] = $eachpayment['note'];
  610. $result[$counter]['cashtype'] = $eachpayment['cashtypeid'];
  611. }
  612. }
  613. return ($result);
  614. }
  615. /**
  616. * Returns array of all payments of user by some login
  617. *
  618. * @param string $login existing user login
  619. * @return array
  620. */
  621. public function getPaymentsCorr($login) {
  622. $login = ubRouting::filters($login, 'mres');
  623. $this->corrDb->where('login', '=', $login);
  624. $allpayments = $this->corrDb->getAll();
  625. $result = array();
  626. if (!empty($allpayments)) {
  627. foreach ($allpayments as $io => $eachpayment) {
  628. $counter = strtotime($eachpayment['date']);
  629. // trying to avoid duplicate keys
  630. while ($this->avoidDTKeysDuplicates and array_key_exists($counter, $result)) {
  631. $counter++;
  632. }
  633. $cashto = $eachpayment['summ'] + $eachpayment['balance'];
  634. $result[$counter]['login'] = $login;
  635. $result[$counter]['date'] = $eachpayment['date'];
  636. $result[$counter]['admin'] = $eachpayment['admin'];
  637. $result[$counter]['summ'] = $eachpayment['summ'];
  638. $result[$counter]['from'] = $eachpayment['balance'];
  639. $result[$counter]['to'] = $cashto;
  640. $result[$counter]['operation'] = 'Correcting';
  641. $result[$counter]['note'] = $eachpayment['note'];
  642. $result[$counter]['cashtype'] = $eachpayment['cashtypeid'];
  643. }
  644. }
  645. return ($result);
  646. }
  647. /**
  648. * Returns array of cashtype names
  649. *
  650. * @return array
  651. */
  652. function getCashTypeNames() {
  653. $result = zb_CashGetTypesNamed();
  654. return ($result);
  655. }
  656. /**
  657. * Renders result of default fundsflow module
  658. *
  659. * @param array $fundsflow
  660. */
  661. public function renderArray($fundsflow) {
  662. global $ubillingConfig;
  663. $timeIntervalPalette = $ubillingConfig->getAlterParam('FUNDSFLOW_EXTCOLORING');
  664. $timeIntervalColoringFlag = ($timeIntervalPalette) ? true : false;
  665. $allcashtypes = $this->getCashTypeNames();
  666. $allservicenames = zb_VservicesGetAllNamesLabeled();
  667. @$employeeNames = unserialize(ts_GetAllEmployeeLoginsCached());
  668. $result = '';
  669. $tablecells = '';
  670. if ($timeIntervalColoringFlag) {
  671. $tablecells .= wf_TableCell('');
  672. }
  673. $tablecells .= wf_TableCell(__('Date'));
  674. $tablecells .= wf_TableCell(__('Cash'));
  675. $tablecells .= wf_TableCell(__('From'));
  676. $tablecells .= wf_TableCell(__('To'));
  677. $tablecells .= wf_TableCell(__('Operation'));
  678. $tablecells .= wf_TableCell(__('Cash type'));
  679. $tablecells .= wf_TableCell(__('Notes'));
  680. $tablecells .= wf_TableCell(__('Admin'));
  681. $tablerows = wf_TableRow($tablecells, 'row1');
  682. if (!empty($fundsflow)) {
  683. foreach ($fundsflow as $io => $each) {
  684. //default operation type
  685. $operation = $each['operation'];
  686. //cashtype setting
  687. if ($each['cashtype'] != 0) {
  688. @$cashtype = $allcashtypes[$each['cashtype']];
  689. } else {
  690. $cashtype = __('Fee');
  691. }
  692. //coloring
  693. $efc = wf_tag('font', true);
  694. if ($each['operation'] == 'Fee') {
  695. $fc = wf_tag('font', false, '', 'color="#' . $this->colorFee . '"');
  696. }
  697. if ($each['operation'] == 'Payment') {
  698. $fc = wf_tag('font', false, '', 'color="#' . $this->colorPayment . '"');
  699. }
  700. if ($each['operation'] == 'Correcting') {
  701. $fc = wf_tag('font', false, '', 'color="#' . $this->colorCorrecting . '"');
  702. }
  703. if (ispos($each['note'], 'MOCK:')) {
  704. $fc = wf_tag('font', false, '', 'color="#' . $this->colorMock . '"');
  705. }
  706. if (ispos($each['note'], 'BALANCESET:')) {
  707. $fc = wf_tag('font', false, '', 'color="#' . $this->colorSet . '"');
  708. }
  709. //virtual services fees
  710. if ((ispos($each['note'], 'Service:')) AND ( $each['summ'] < 0)) {
  711. $fc = wf_tag('font', false, '', 'color="#' . $this->colorAdditionalFee . '"');
  712. $operation = __('Virtual service');
  713. }
  714. //virtual services bonuses
  715. if ((ispos($each['note'], 'Service:')) AND ( $each['summ'] >= 0)) {
  716. $fc = wf_tag('font', false, '', 'color="#' . $this->colorBonus . '"');
  717. $operation = __('Bonus');
  718. }
  719. //Megogo fees
  720. if (ispos($each['note'], 'MEGOGO:')) {
  721. $fc = wf_tag('font', false, '', 'color="#' . $this->colorAdditionalFee . '"');
  722. $operation = __('Service') . ' ' . __('Megogo');
  723. }
  724. //OmegaTV fees
  725. if (ispos($each['note'], 'OMEGATV:')) {
  726. $fc = wf_tag('font', false, '', 'color="#' . $this->colorAdditionalFee . '"');
  727. $operation = __('Service') . ' ' . __('OmegaTV');
  728. }
  729. //ProstoTV fees
  730. if (ispos($each['note'], 'PROSTOTV:')) {
  731. $fc = wf_tag('font', false, '', 'color="#' . $this->colorAdditionalFee . '"');
  732. $operation = __('Service') . ' ' . __('ProstoTV');
  733. }
  734. //YouTV fees
  735. if (ispos($each['note'], 'YOUTV:')) {
  736. $fc = wf_tag('font', false, '', 'color="#' . $this->colorAdditionalFee . '"');
  737. $operation = __('Service') . ' ' . __('YouTV');
  738. }
  739. //TrinityTV/SweetTV fees
  740. if (ispos($each['note'], 'TRINITYTV:')) {
  741. $fc = wf_tag('font', false, '', 'color="#' . $this->colorAdditionalFee . '"');
  742. $operation = __('Service') . ' ' . __('TrinityTV');
  743. }
  744. //OllTV fees
  745. if (ispos($each['note'], 'OLLTV:')) {
  746. $fc = wf_tag('font', false, '', 'color="#' . $this->colorAdditionalFee . '"');
  747. $operation = __('Service') . ' ' . __('OllTV');
  748. }
  749. //Self crediting fees
  750. if (ispos($each['note'], 'SCFEE')) {
  751. $creditColor = (@$this->alterConf['CREDIT_EVERGARDEN']) ? $this->colorCreditViolet : $this->colorAdditionalFee;
  752. $fc = wf_tag('font', false, '', 'color="#' . $creditColor . '"');
  753. $operation = __('Service') . ' ' . __('credit');
  754. }
  755. //Self freezing fees
  756. if (ispos($each['note'], 'AFFEE')) {
  757. $fc = wf_tag('font', false, '', 'color="#' . $this->colorAdditionalFee . '"');
  758. $operation = __('Service') . ' ' . __('freezing');
  759. }
  760. //Tariff changing fee
  761. if (ispos($each['note'], 'TCHANGE:')) {
  762. $fc = wf_tag('font', false, '', 'color="#' . $this->colorAdditionalFee . '"');
  763. $operation = __('Service') . ' ' . __('change tariff');
  764. }
  765. //Penalty fees
  766. if (ispos($each['note'], 'PENALTY')) {
  767. $fc = wf_tag('font', false, '', 'color="#' . $this->colorAdditionalFee . '"');
  768. $operation = __('Penalty');
  769. }
  770. //SMS reminder service activation
  771. if (ispos($each['note'], 'REMINDER')) {
  772. $fc = wf_tag('font', false, '', 'color="#' . $this->colorAdditionalFee . '"');
  773. $operation = __('Service') . ' ' . __('SMS reminder');
  774. }
  775. //discount bonuses
  776. if (ispos($each['note'], 'DISCOUNT:')) {
  777. $fc = wf_tag('font', false, '', 'color="#' . $this->colorBonus . '"');
  778. $operation = __('Discount');
  779. }
  780. //friendship bonuses
  781. if (ispos($each['note'], 'FRIENDSHIP')) {
  782. $fc = wf_tag('font', false, '', 'color="#' . $this->colorBonus . '"');
  783. $operation = __('Friendship');
  784. }
  785. //manual charged
  786. if (ispos($each['note'], 'ECHARGE')) {
  787. $fc = wf_tag('font', false, '', 'color="#' . $this->colorAdditionalFee . '"');
  788. $operation = __('Charged');
  789. }
  790. //DDT charged
  791. if (ispos($each['note'], 'DDT')) {
  792. $fc = wf_tag('font', false, '', 'color="#' . $this->colorAdditionalFee . '"');
  793. $operation = __('Charged');
  794. $cashtype = __('Fee');
  795. }
  796. //Visor camera charged
  797. if (ispos($each['note'], 'VISORCHARGE')) {
  798. $fc = wf_tag('font', false, '', 'color="#' . $this->colorAdditionalFee . '"');
  799. $operation = __('Service') . ' ' . __('Camera');
  800. $cashtype = __('Fee');
  801. }
  802. //Visor cash moved from primary account
  803. if (ispos($each['note'], 'VISORPUSH')) {
  804. $fc = wf_tag('font', false, '', 'color="#' . $this->colorBonus . '"');
  805. $operation = __('Charged');
  806. $cashtype = __('Payment');
  807. }
  808. //PowerTariffs Internet service fee
  809. if (ispos($each['note'], 'PTFEE')) {
  810. $fc = wf_tag('font', false, '', 'color="#' . $this->colorFee . '"');
  811. $operation = __('Fee');
  812. $cashtype = __('Fee');
  813. }
  814. //manual charged
  815. if (ispos($each['note'], 'EXTFEE')) {
  816. $fc = wf_tag('font', false, '', 'color="#' . $this->colorAdditionalFee . '"');
  817. $operation = __('Fee');
  818. $cashtype = __('Fee');
  819. }
  820. //deferred sale
  821. if (ispos($each['note'], 'DEFSALE')) {
  822. $fc = wf_tag('font', false, '', 'color="#' . $this->colorAdditionalFee . '"');
  823. $operation = __('Charged');
  824. $cashtype = __('Fee');
  825. }
  826. //notes translation
  827. if ($this->alterConf['TRANSLATE_PAYMENTS_NOTES']) {
  828. $displaynote = zb_TranslatePaymentNote($each['note'], $allservicenames);
  829. } else {
  830. $displaynote = $each['note'];
  831. }
  832. //admin login detection
  833. $adminName = (isset($employeeNames[$each['admin']])) ? $employeeNames[$each['admin']] : $each['admin'];
  834. //time interval coloring
  835. if ($timeIntervalColoringFlag) {
  836. $operationMonth = (!empty($each['date'])) ? date("m", strtotime($each['date'])) : '';
  837. $intervalColor = wf_genColorCodeFromText($operationMonth, $timeIntervalPalette);
  838. }
  839. $tablecells = '';
  840. if ($timeIntervalColoringFlag) {
  841. $tablecells .= wf_TableCell('&nbsp;', '', '', 'bgcolor="#' . $intervalColor . '"');
  842. }
  843. $tablecells .= wf_TableCell($fc . $each['date'] . $efc, '150');
  844. $tablecells .= wf_TableCell($fc . $each['summ'] . $efc);
  845. $tablecells .= wf_TableCell($fc . $each['from'] . $efc);
  846. $tablecells .= wf_TableCell($fc . $each['to'] . $efc);
  847. $tablecells .= wf_TableCell($fc . __($operation) . $efc);
  848. $tablecells .= wf_TableCell($cashtype);
  849. $tablecells .= wf_TableCell($displaynote);
  850. $tablecells .= wf_TableCell($adminName);
  851. $tablerows .= wf_TableRow($tablecells, 'row3');
  852. }
  853. $legendcells = wf_TableCell(__('Legend') . ':');
  854. $legendcells .= wf_TableCell(wf_tag('font', false, '', 'color="#' . $this->colorPayment . '"') . __('Payment') . $efc);
  855. $legendcells .= wf_TableCell(wf_tag('font', false, '', 'color="#' . $this->colorFee . '"') . __('Fee') . $efc);
  856. $legendcells .= wf_TableCell(wf_tag('font', false, '', 'color="#' . $this->colorBonus . '"') . __('Bonuses') . $efc);
  857. $legendcells .= wf_TableCell(wf_tag('font', false, '', 'color="#' . $this->colorAdditionalFee . '"') . __('Additional fees') . $efc);
  858. $legendcells .= wf_TableCell(wf_tag('font', false, '', 'color="#' . $this->colorCorrecting . '"') . __('Correct saldo') . $efc);
  859. $legendcells .= wf_TableCell(wf_tag('font', false, '', 'color="#' . $this->colorMock . '"') . __('Mock payment') . $efc);
  860. $legendcells .= wf_TableCell(wf_tag('font', false, '', 'color="#' . $this->colorSet . '"') . __('Set cash') . $efc);
  861. if (@$this->alterConf['CREDIT_EVERGARDEN']) {
  862. $legendcells .= wf_TableCell(wf_tag('font', false, '', 'color="#' . $this->colorCreditViolet . '"') . __('Credit') . $efc);
  863. }
  864. $legendrows = wf_TableRow($legendcells, 'row3');
  865. $legend = wf_TableBody($legendrows, '60%', 0, 'glamour');
  866. $legend .= wf_tag('div', false, '', 'style="clear:both;"') . wf_tag('div', true);
  867. $legend .= wf_delimiter();
  868. $result = wf_TableBody($tablerows, '100%', 0, 'sortable');
  869. $result .= $legend;
  870. }
  871. return ($result);
  872. }
  873. /**
  874. * Transforms array for normal output
  875. *
  876. * @param array $fundsflow
  877. *
  878. * @return array
  879. */
  880. public function transformArray($fundsflow) {
  881. if (!empty($fundsflow)) {
  882. ksort($fundsflow);
  883. $fundsflow = array_reverse($fundsflow);
  884. }
  885. return ($fundsflow);
  886. }
  887. /**
  888. * Extracts funds only with some date pattern
  889. *
  890. * @param array $fundsflow standard fundsflow array
  891. * @param string $date
  892. *
  893. * @return array
  894. */
  895. public function filterByDate($fundsflow, $date) {
  896. $result = array();
  897. if (!empty($fundsflow)) {
  898. foreach ($fundsflow as $timestamp => $flowdata) {
  899. if (ispos($flowdata['date'], $date)) {
  900. $result[$timestamp] = $flowdata;
  901. }
  902. }
  903. }
  904. return ($result);
  905. }
  906. /**
  907. * Renders user tags if available
  908. *
  909. * @param string $userLogin
  910. *
  911. * @return string
  912. */
  913. protected function renderUserTags($userLogin) {
  914. $result = '';
  915. if (!empty($userLogin)) {
  916. if (isset($this->userTags[$userLogin])) {
  917. if (!empty($this->userTags[$userLogin])) {
  918. $result .= implode(', ', $this->userTags[$userLogin]);
  919. }
  920. }
  921. }
  922. return ($result);
  923. }
  924. /**
  925. * Renders table for corps users payments/fees stats
  926. *
  927. * @param array $fundsFlows
  928. * @param array $corpsData
  929. * @param array $corpUsers
  930. * @param array $allUserTariffs
  931. * @param array $allUserContracts
  932. *
  933. * @return string
  934. */
  935. public function renderCorpsFlows($num, $fundsFlows, $corpsData, $corpUsers, $allUserContracts, $allUsersCash, $allUserTariffs, $allTariffPrices) {
  936. $result = '';
  937. $rawData = array();
  938. $rawData['balance'] = 0;
  939. $rawData['payments'] = 0;
  940. $rawData['paymentscorr'] = 0;
  941. $rawData['fees'] = 0;
  942. $rawData['login'] = '';
  943. $rawData['contract'] = '';
  944. $rawData['corpid'] = '';
  945. $rawData['corpname'] = '';
  946. $rawData['balance'] = 0;
  947. $rawData['used'] = 0;
  948. //loading some user tags
  949. if (empty($this->userTags)) {
  950. $this->loadUserTags();
  951. }
  952. if (!empty($fundsFlows)) {
  953. foreach ($fundsFlows as $io => $eachop) {
  954. if ($eachop['operation'] == 'Fee') {
  955. $rawData['fees'] = $rawData['fees'] + abs($eachop['summ']);
  956. }
  957. if ($eachop['operation'] == 'Payment') {
  958. $rawData['payments'] = $rawData['payments'] + abs($eachop['summ']);
  959. }
  960. if ($eachop['operation'] == 'Correcting') {
  961. $rawData['paymentscorr'] = $rawData['paymentscorr'] + abs($eachop['summ']);
  962. }
  963. }
  964. $rawData['login'] = $eachop['login'];
  965. if (!isset($this->allBuriedUsers[$rawData['login']])) {
  966. @$rawData['contract'] = array_search($eachop['login'], $allUserContracts);
  967. @$rawData['corpid'] = $corpUsers[$eachop['login']];
  968. @$rawData['corpname'] = $corpsData[$rawData['corpid']]['corpname'];
  969. $rawData['balance'] = $allUsersCash[$eachop['login']];
  970. $rawData['used'] = $rawData['fees'];
  971. //forming result
  972. $cells = wf_TableCell($num);
  973. $corpLink = wf_Link('?module=corps&show=corps&editid=' . $rawData['corpid'], $rawData['corpname'], false, '');
  974. $cells .= wf_TableCell($corpLink);
  975. if ($rawData['contract']) {
  976. $loginLink = wf_Link('?module=userprofile&username=' . $rawData['login'], $rawData['contract'], false, '');
  977. } else {
  978. $loginLink = wf_Link('?module=userprofile&username=' . $rawData['login'], $rawData['login'], false, '');
  979. }
  980. if (!empty($rawData['login'])) {
  981. $currentTags = $this->renderUserTags($rawData['login']);
  982. } else {
  983. $currentTags = '';
  984. }
  985. $cells .= wf_TableCell($loginLink);
  986. $cells .= wf_TableCell($currentTags);
  987. $cells .= wf_TableCell(@$allTariffPrices[$allUserTariffs[$rawData['login']]]);
  988. $cells .= wf_TableCell(round($rawData['payments'], 2));
  989. $cells .= wf_TableCell(round($rawData['paymentscorr'], 2));
  990. $cells .= wf_TableCell(round($rawData['balance'], 2));
  991. $cells .= wf_TableCell(round($rawData['used'], 2));
  992. $result .= wf_TableRow($cells, 'row3');
  993. //fill summary data
  994. $this->fundsTmp['col1'] += $rawData['payments'];
  995. $this->fundsTmp['col2'] += $rawData['paymentscorr'];
  996. $this->fundsTmp['col3'] += $rawData['balance'];
  997. $this->fundsTmp['col4'] += $rawData['used'];
  998. }
  999. }
  1000. return ($result);
  1001. }
  1002. /**
  1003. * Returns totals data from previous renderCorpsFlows runs
  1004. *
  1005. * @return string
  1006. */
  1007. public function renderCorpsFlowsTotal() {
  1008. $result = '';
  1009. if (!empty($this->fundsTmp)) {
  1010. $cells = wf_TableCell('');
  1011. $cells .= wf_TableCell(__('Total'));
  1012. $cells .= wf_TableCell('');
  1013. $cells .= wf_TableCell('');
  1014. $cells .= wf_TableCell('');
  1015. $cells .= wf_TableCell(round($this->fundsTmp['col1'], 2));
  1016. $cells .= wf_TableCell(round($this->fundsTmp['col2'], 2));
  1017. $cells .= wf_TableCell(round($this->fundsTmp['col3'], 2));
  1018. $cells .= wf_TableCell(round($this->fundsTmp['col4'], 2));
  1019. $result .= wf_TableRow($cells, 'row2');
  1020. }
  1021. return ($result);
  1022. }
  1023. /**
  1024. * Returns corpsacts table headers
  1025. *
  1026. * @param string $year
  1027. * @param string $month
  1028. *
  1029. * @return string
  1030. */
  1031. public function renderCorpsFlowsHeaders($year, $month) {
  1032. $monthArr = months_array();
  1033. $month = $monthArr[$month];
  1034. $month = rcms_date_localise($month);
  1035. $cd = wf_tag('p', false, '', 'align="center"') . wf_tag('b');
  1036. $cde = wf_tag('b', true) . wf_tag('p', true);
  1037. $result = wf_tag('tr', false, 'row2');
  1038. $result .= wf_TableCell($cd . __('Num #') . $cde, '15', '', 'rowspan="3"');
  1039. $result .= wf_TableCell($cd . __('Organisation') . $cde, '141', '', 'rowspan="3"');
  1040. $result .= wf_TableCell('', '62', '', '');
  1041. $result .= wf_TableCell('', '62', '', '');
  1042. $result .= wf_TableCell($cd . $month . ' ' . $year . $cde, '240', '', 'colspan="5"');
  1043. $result .= wf_tag('tr', true);
  1044. $result .= wf_tag('tr', false, 'row2');
  1045. $result .= wf_TableCell($cd . __('Contract') . $cde, '62', '', 'rowspan="2"');
  1046. $result .= wf_TableCell($cd . __('Tags') . $cde, '62', '', 'rowspan="2"');
  1047. $result .= wf_TableCell($cd . __('Fee') . $cde, '62', '', 'rowspan="2"');
  1048. $result .= wf_TableCell($cd . __('Income') . $cde, '84', '', 'colspan="2"');
  1049. $result .= wf_TableCell($cd . __('Current deposit') . $cde, '68', '', 'rowspan="2"');
  1050. $result .= wf_TableCell($cd . __('Expenditure') . $cde, '84', '', 'rowspan="2"');
  1051. $result .= wf_tag('tr', true);
  1052. $result .= wf_tag('tr', false, 'row2');
  1053. $result .= wf_TableCell($cd . __('on deposit') . $cde, '41');
  1054. $result .= wf_TableCell($cd . __('corr.') . $cde, '41');
  1055. $result .= wf_tag('tr', true);
  1056. return ($result);
  1057. }
  1058. /**
  1059. * Returns year/month selectors form
  1060. *
  1061. * @return string
  1062. */
  1063. public function renderCorpsFlowsDateForm() {
  1064. $allagents = zb_ContrAhentGetAllData();
  1065. $tmpArr = array();
  1066. $tmpArr[''] = __('Any');
  1067. if (!empty($allagents)) {
  1068. foreach ($allagents as $io => $eachagent) {
  1069. $tmpArr[$eachagent['id']] = $eachagent['contrname'];
  1070. }
  1071. }
  1072. /**
  1073. * Again and again and again and again
  1074. * We Smash the Game BUHA!!
  1075. * And again and again and again and again
  1076. * Remember our name / Furyo 'til I Die
  1077. */
  1078. $inputs = wf_YearSelectorPreset('yearsel', __('Year'), false, ubRouting::post('yearsel')) . ' ';
  1079. $inputs .= wf_MonthSelector('monthsel', __('Month'), ubRouting::post('monthsel'), false) . ' ';
  1080. $inputs .= wf_Selector('agentsel', $tmpArr, __('Contrahent name'), ubRouting::post('agentsel'), false);
  1081. $inputs .= wf_Submit(__('Show'));
  1082. $result = wf_Form('', 'POST', $inputs, 'glamour');
  1083. return ($result);
  1084. }
  1085. /**
  1086. * Returns user online left days
  1087. *
  1088. * @param string $login existing users login
  1089. * @param bool $rawdays show only days count
  1090. *
  1091. * @return string
  1092. */
  1093. public function getOnlineLeftCount($login, $rawDays = false, $includeVServices = false) {
  1094. $userData = zb_UserGetStargazerData($login);
  1095. $balanceExpire = '';
  1096. if (!empty($userData)) {
  1097. $userTariff = $userData['Tariff'];
  1098. $userBalanceRaw = $userData['Cash'];
  1099. $userBalance = $userData['Cash'];
  1100. $tariffData = zb_TariffGetData($userTariff);
  1101. $userFeeOffset = 0;
  1102. $daysOnLine = 0;
  1103. $totalVsrvPrice = 0;
  1104. if (empty($tariffData)) {
  1105. //user have no tariff
  1106. $tariffData['name'] = '*_NO_TARIFF_*';
  1107. $tariffData['Fee'] = 0;
  1108. $tariffData['period'] = 'month';
  1109. }
  1110. $tariffFee = $tariffData['Fee'];
  1111. $tariffPeriod = isset($tariffData['period']) ? $tariffData['period'] : 'month';
  1112. if ($this->alterConf['PT_ENABLED']) {
  1113. $powerTariffs = new PowerTariffs();
  1114. //suspicious tariff?
  1115. if ($tariffFee == 0) {
  1116. //wow too much power!
  1117. if ($powerTariffs->isPowerTariff($userTariff)) {
  1118. $tariffFee = $powerTariffs->getPowerTariffPrice($userTariff);
  1119. $userFeeOffset = $powerTariffs->getUserOffsetDay($login);
  1120. $maxDay = ($powerTariffs->getMaxDay() - 1);
  1121. if ($userFeeOffset == 0) {
  1122. $userFeeOffset = (date('j') < $maxDay) ? date('j') + 1 : 1;
  1123. $daysOnLine = (date('j') < $maxDay) ? 0 : date('j');
  1124. } else {
  1125. if ($userFeeOffset < 0) {
  1126. $userFeeOffset = (date('j') < $maxDay) ? date('j') + 1 : 1;
  1127. }
  1128. $daysOnLine = ($userFeeOffset == date('j')) ? 0 : (($userFeeOffset < date('j')) ? -1 : date('j') * -1);
  1129. }
  1130. $userFeeOffset = $userFeeOffset - 1;
  1131. }
  1132. }
  1133. }
  1134. if ($includeVServices) {
  1135. $totalVsrvPrice = zb_VservicesGetUserPricePeriod($login, $tariffPeriod);
  1136. $tariffFee += $totalVsrvPrice;
  1137. }
  1138. if (isset($this->alterConf['SPREAD_FEE'])) {
  1139. if ($this->alterConf['SPREAD_FEE']) {
  1140. $spreadFee = true;
  1141. } else {
  1142. $spreadFee = false;
  1143. }
  1144. } else {
  1145. $spreadFee = false;
  1146. }
  1147. if ($userBalance >= 0) {
  1148. if ($tariffFee > 0) {
  1149. //spread fee
  1150. if ($spreadFee) {
  1151. if ($tariffPeriod == 'month') {
  1152. //monthly period
  1153. while ($userBalance >= 0) {
  1154. $daysOnLine++;
  1155. $dayFee = $tariffFee / date('t', time() + ($daysOnLine * 24 * 60 * 60));
  1156. $userBalance = $userBalance - $dayFee;
  1157. }
  1158. } else {
  1159. //daily period
  1160. while ($userBalance >= 0) {
  1161. $daysOnLine++;
  1162. $userBalance = $userBalance - $tariffFee;
  1163. }
  1164. }
  1165. } else {
  1166. //non spread normal fee
  1167. if ($tariffPeriod == 'month') {
  1168. //monthly non spread fee
  1169. while ($userBalance >= 0) {
  1170. $daysOnLine = $daysOnLine + $userFeeOffset + date('t', time() + ($daysOnLine * 24 * 60 * 60)) - date('d', time() + ($daysOnLine * 24 * 60 * 60)) + 1;
  1171. $userBalance = $userBalance - $tariffFee;
  1172. }
  1173. } else {
  1174. //daily non spread fee
  1175. while ($userBalance >= 0) {
  1176. $daysOnLine++;
  1177. $userBalance = $userBalance - $tariffFee;
  1178. }
  1179. }
  1180. }
  1181. $daysLabel = $daysOnLine;
  1182. $dateLabel = date("d.m.Y", time() + ($daysOnLine * 24 * 60 * 60));
  1183. } else {
  1184. $daysLabel = '&infin;';
  1185. $dateLabel = '&infin;';
  1186. }
  1187. $balanceExpire = wf_tag('span', false, 'alert_info');
  1188. $balanceExpire .= __('Current Cash state') . ': ' . wf_tag('b') . $userBalanceRaw . wf_tag('b', true) . ', ' . __('which should be enough for another');
  1189. $balanceExpire .= ' ' . $daysLabel . ' ' . __('days') . ' ' . __('of service usage') . ' ';
  1190. $balanceExpire .= __('or enought till the') . ' ' . $dateLabel . ' ';
  1191. $balanceExpire .= __('according to the tariff') . ' ' . $userTariff . (($includeVServices) ? ' + ' . __('virtual services') : '') . ' (' . $tariffFee . ' / ' . __($tariffPeriod) . ')';
  1192. $balanceExpire .= wf_tag('span', true);
  1193. } else {
  1194. $balanceExpire = wf_tag('span', false, 'alert_warning') . __('Current Cash state') . ': ' . wf_tag('b') . $userBalanceRaw . wf_tag('b', true);
  1195. $balanceExpire .= ', ' . __('indebtedness') . '!' . ' ' . wf_tag('span', true);
  1196. }
  1197. if ($rawDays) {
  1198. $balanceExpire = $daysOnLine;
  1199. }
  1200. }
  1201. return ($balanceExpire);
  1202. }
  1203. /**
  1204. * Loads all user and tariffs data
  1205. *
  1206. * @return void
  1207. */
  1208. public function runDataLoders() {
  1209. $this->loadAllUserData();
  1210. $this->loadAllTariffsData();
  1211. }
  1212. /**
  1213. * Returns user online left days without additional DB queries
  1214. * runDataLoaders() must be run once, before usage
  1215. *
  1216. * @param string $login existing users login
  1217. *
  1218. * @return int >=0: days left, -1: debt, -2: zero tariff price
  1219. */
  1220. public function getOnlineLeftCountFast($login, $includeVServices = false) {
  1221. if (isset($this->allUserData[$login])) {
  1222. $userData = $this->allUserData[$login];
  1223. }
  1224. $daysOnLine = 0;
  1225. $totalVsrvPrice = 0;
  1226. if (!empty($userData)) {
  1227. $userTariff = $userData['Tariff'];
  1228. $userBalanceRaw = $userData['Cash'];
  1229. $userBalance = $userData['Cash'];
  1230. if (isset($this->allTariffsData[$userTariff])) {
  1231. $tariffData = $this->allTariffsData[$userTariff];
  1232. $tariffFee = $tariffData['Fee'];
  1233. $tariffPeriod = isset($tariffData['period']) ? $tariffData['period'] : 'month';
  1234. if ($includeVServices) {
  1235. $totalVsrvPrice = zb_VservicesGetUserPricePeriod($login, $tariffPeriod);
  1236. $tariffFee += $totalVsrvPrice;
  1237. }
  1238. if (isset($this->alterConf['SPREAD_FEE'])) {
  1239. if ($this->alterConf['SPREAD_FEE']) {
  1240. $spreadFee = true;
  1241. } else {
  1242. $spreadFee = false;
  1243. }
  1244. } else {
  1245. $spreadFee = false;
  1246. }
  1247. if ($userBalance >= 0) {
  1248. if ($tariffFee > 0) {
  1249. //spread fee
  1250. if ($spreadFee) {
  1251. if ($tariffPeriod == 'month') {
  1252. //monthly period
  1253. while ($userBalance >= 0) {
  1254. $daysOnLine++;
  1255. $dayFee = $tariffFee / date('t', time() + ($daysOnLine * 24 * 60 * 60));
  1256. $userBalance = $userBalance - $dayFee;
  1257. }
  1258. } else {
  1259. //daily period
  1260. while ($userBalance >= 0) {
  1261. $daysOnLine++;
  1262. $userBalance = $userBalance - $tariffFee;
  1263. }
  1264. }
  1265. } else {
  1266. //non spread fee
  1267. if ($tariffPeriod == 'month') {
  1268. //monthly non spread fee
  1269. while ($userBalance >= 0) {
  1270. $daysOnLine = $daysOnLine + date('t', time() + ($daysOnLine * 24 * 60 * 60)) - date('d', time() + ($daysOnLine * 24 * 60 * 60)) + 1;
  1271. $userBalance = $userBalance - $tariffFee;
  1272. }
  1273. } else {
  1274. //daily non spread fee
  1275. while ($userBalance >= 0) {
  1276. $daysOnLine++;
  1277. $userBalance = $userBalance - $tariffFee;
  1278. }
  1279. }
  1280. }
  1281. } else {
  1282. $daysOnLine = '-2';
  1283. }
  1284. } else {
  1285. $daysOnLine = '-1';
  1286. }
  1287. }
  1288. }
  1289. return ($daysOnLine);
  1290. }
  1291. /**
  1292. * Charges month freezing fee (i dont know why this is here)
  1293. *
  1294. * @return void
  1295. */
  1296. public function makeFreezeMonthFee($debug2log = false) {
  1297. $cost = $this->alterConf['FREEZEMONTH_COST'];
  1298. $cashType = $this->alterConf['FREEZEMONTH_CASHTYPE'];
  1299. $processedUsers = 0;
  1300. if ($debug2log) {
  1301. log_register('FROZEN FEE CHARGE PROCESSING STARTED. COST: ' . $cost . '. CASHTYPE: ' . $cashType);
  1302. }
  1303. if (!empty($this->alterConf['FREEZEMONTH_ONLY_TAG'])) {
  1304. log_register('FROZEN FEE CHARGE PROCESSING ONLY TAGS: ' . $this->alterConf['FREEZEMONTH_ONLY_TAG']);
  1305. $allUsersWithFMOTag = zb_UserGetAllTagsUnique('', $this->alterConf['FREEZEMONTH_ONLY_TAG']);
  1306. $allUserData = array_intersect_key($this->allUserData, $allUsersWithFMOTag);
  1307. } else {
  1308. $allUserData = $this->allUserData;
  1309. }
  1310. if (!empty($this->alterConf['FREEZEMONTH_EXCLUDE_TAG'])) {
  1311. log_register('FROZEN FEE CHARGE EXCLUDING TAGS: ' . $this->alterConf['FREEZEMONTH_EXCLUDE_TAG']);
  1312. $allUsersWithFMETag = zb_UserGetAllTagsUnique('', $this->alterConf['FREEZEMONTH_EXCLUDE_TAG']);
  1313. $allUserData = array_diff_key($allUserData, $allUsersWithFMETag);
  1314. }
  1315. if (!empty($allUserData)) {
  1316. foreach ($allUserData as $eachUser) {
  1317. if ($eachUser['Passive'] == 1) {
  1318. zb_CashAdd($eachUser['login'], -1 * $cost, 'add', $cashType, 'FROZEN FEE CHARGE:' . $cost);
  1319. $processedUsers++;
  1320. if ($debug2log) {
  1321. log_register('FROZEN FEE CHARGE AMOUNT ' . -1 * $cost . ' FOR USER (' . $eachUser['login'] . ')');
  1322. }
  1323. }
  1324. }
  1325. } elseif ($debug2log) {
  1326. log_register('FROZEN FEE CHARGE PROCESSING: NO USERS TO PROCESS FOUND');
  1327. }
  1328. if ($debug2log) {
  1329. log_register('FROZEN FEE CHARGE PROCESSING FINISHED FOR ' . $processedUsers . ' USERS');
  1330. }
  1331. }
  1332. /**
  1333. * Process possible duplicates and concatenates $fees, $payments and $corrections arrays
  1334. *
  1335. * @param array $fees
  1336. * @param array $payments
  1337. * @param array $corrections
  1338. *
  1339. * @return mixed
  1340. */
  1341. public function concatAvoidDuplicateKeys($fees, $payments, $corrections) {
  1342. // searching and fixing duplicates in fees - payments array
  1343. $duplicates = array_intersect_key($fees, $payments);
  1344. if (!empty($duplicates)) {
  1345. foreach ($duplicates as $key => $val) {
  1346. // walking through duplicates array and trying to get
  1347. // a unique key instead of existing duplicate key
  1348. if (array_key_exists($key, $payments)) {
  1349. $tmpVal = $payments[$key];
  1350. $tmpKey = $key + 1;
  1351. while (array_key_exists($tmpKey, $fees) or
  1352. array_key_exists($tmpKey, $payments) or
  1353. array_key_exists($tmpKey, $corrections)
  1354. ) {
  1355. $tmpKey++;
  1356. }
  1357. // remove array item with duplicate key and set it's preserved value to new key
  1358. // we're not worried about the keys order as concatenated array
  1359. // will be later sorted by keys anyway
  1360. unset($payments[$key]);
  1361. $payments[$tmpKey] = $tmpVal;
  1362. }
  1363. }
  1364. }
  1365. // searching and fixing duplicates in fees - corrections array
  1366. $duplicates = array_intersect_key($fees, $corrections);
  1367. if (!empty($duplicates)) {
  1368. foreach ($duplicates as $key => $val) {
  1369. if (array_key_exists($key, $corrections)) {
  1370. $tmpVal = $corrections[$key];
  1371. $tmpKey = $key + 1;
  1372. while (array_key_exists($tmpKey, $fees) or
  1373. array_key_exists($tmpKey, $payments) or
  1374. array_key_exists($tmpKey, $corrections)
  1375. ) {
  1376. $tmpKey++;
  1377. }
  1378. unset($corrections[$key]);
  1379. $corrections[$tmpKey] = $tmpVal;
  1380. }
  1381. }
  1382. }
  1383. // searching and fixing duplicates in payments - corrections array
  1384. $duplicates = array_intersect_key($payments, $corrections);
  1385. if (!empty($duplicates)) {
  1386. foreach ($duplicates as $key => $val) {
  1387. if (array_key_exists($key, $corrections)) {
  1388. $tmpVal = $corrections[$key];
  1389. $tmpKey = $key + 1;
  1390. while (array_key_exists($tmpKey, $fees) or
  1391. array_key_exists($tmpKey, $payments) or
  1392. array_key_exists($tmpKey, $corrections)
  1393. ) {
  1394. $tmpKey++;
  1395. }
  1396. unset($corrections[$key]);
  1397. $corrections[$tmpKey] = $tmpVal;
  1398. }
  1399. }
  1400. }
  1401. // concatenate fixed arrays
  1402. $allFundsFlow = $fees + $payments + $corrections;
  1403. return ($allFundsFlow);
  1404. }
  1405. }