Budget.php 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532
  1. <?php
  2. Lib::loadClass('RouteBase');
  3. class Route_Budget extends RouteBase {
  4. public function handleAuth() {
  5. if (!User::logged()) {
  6. throw new HttpException('Unauthorized', 401);
  7. }
  8. }
  9. public function defaultAction() {
  10. $args = array();
  11. $args['year'] = V::get('year', '', $_REQUEST, 'int');
  12. $args['_print'] = V::get('_print', '', $_REQUEST, 'int');
  13. SE_Layout::gora();
  14. //SE_Layout::menu();
  15. if (!$args['_print']) {
  16. $this->menu($args['year']);
  17. }
  18. SE_Layout::dol();
  19. }
  20. public function yearBudgetAction() {
  21. $args = array();
  22. $args['year'] = V::get('year', '', $_REQUEST, 'int');
  23. $args['_print'] = V::get('_print', '', $_REQUEST, 'int');
  24. SE_Layout::gora();
  25. //SE_Layout::menu();
  26. if (!$args['_print']) {
  27. $this->menu($args['year']);
  28. }
  29. if (empty($args['year'])) {
  30. ?>
  31. <div class="alert alert-warning">
  32. Nie wybrano roku.
  33. </div>
  34. <?php
  35. SE_Layout::dol();
  36. exit;
  37. }
  38. $costs = $this->getCostsByYear($args['year']);
  39. if (empty($costs)) {
  40. ?>
  41. <div class="alert alert-warning">
  42. Brak danych na wybrany rok.
  43. </div>
  44. <?php
  45. return;
  46. }
  47. //echo'<pre style="border:1px solid red;overflow:auto;max-height:400px">$costs: ';print_r($costs);echo'</pre>';
  48. $this->printCostsForYear($args['year']);
  49. SE_Layout::dol();
  50. }
  51. private function menu($selectedYear) {
  52. //SE_Layout::menu();
  53. $year = ($selectedYear)? $selectedYear : date("Y");
  54. ?>
  55. <div class="jumbotron">
  56. <div class="container">
  57. <form class="form-inline" method="POST">
  58. <input type="hidden" name="_task" value="yearBudget" />
  59. <label for="year">Zestawienie kosztów projektów na podstawie korespondencji:</label>
  60. <div class="input-group date" id="fldZestYear">
  61. <input type="text" name="year" class="form-control" value="" />
  62. <span class="input-group-addon"><span class="glyphicon glyphicon-time"></span></span>
  63. </div>
  64. <button type="submit" id="fldZestYearBtn" class="btn btn-primary" autocomplete="off">
  65. Pokaż
  66. </button>
  67. </form>
  68. </div>
  69. </div>
  70. <script type="text/javascript">
  71. jQuery(document).ready(function () {
  72. jQuery('#fldZestYearBtn').on('click', function () {
  73. jQuery(this).text(jQuery(this).text() + '...').attr('disabled', 'disabled');
  74. jQuery(this).parent().submit();
  75. })
  76. jQuery("#fldZestYear").datetimepicker({
  77. format: "YYYY",
  78. defaultDate: new Date(<?php echo $year; ?>, <?php echo intval(date("m")); ?>, 1),
  79. // minDate: new Date(2014, 11, 1),
  80. // maxDate: "<?php echo date("Y"); ?>"
  81. });
  82. });
  83. </script>
  84. <?php
  85. }
  86. function css() {
  87. ?>
  88. <style type="text/css">
  89. .c { text-align:center; }
  90. .r { text-align:right; }
  91. .zestawienie-kosztow-tbl { border-collapse:collapse; border:1px solid #7EC5FF; }
  92. .zestawienie-kosztow-tbl td { border:1px solid #7EC5FF; }
  93. .zestawienie-kosztow-tbl .p2 { padding:0 2px; }
  94. .zestawienie-kosztow-tbl .nr { color:#7A7A7A; }
  95. .zestawienie-kosztow-tbl thead th { border:1px solid #7EC5FF; }
  96. .zestawienie-kosztow-tbl tbody tr:hover td { background:#cafbfd; }
  97. .row-selected td {background-color:#d8fded;}
  98. .showOnlySelected tr { display:none; }
  99. .showOnlySelected tr.row-selected { display:table-row; }
  100. .cell-cost { padding:0 2px; min-width:30px; text-align:right; }
  101. .cell-cost-only_child { color:#777; }
  102. .cell-cost-only_self { color:red; }
  103. .cell-cost-self_and_child { color:orange; }
  104. /* print table background colors */
  105. table td, table th { -webkit-print-color-adjust:exact; }
  106. table { page-break-after:auto }
  107. tr { page-break-inside:avoid; page-break-after:auto; position:relative; }
  108. td { page-break-inside:avoid; page-break-after:auto; position:relative; }
  109. thead { display:table-header-group }
  110. tfoot { display:table-footer-group }
  111. </style>
  112. <?php
  113. }
  114. function printCostsForYear($year) {
  115. $this->_costs = $this->_costs;
  116. $months = array();
  117. for ($i = 0; $i < 12; $i++) {
  118. $months[] = $i + 1;
  119. }
  120. $this->css();
  121. if(V::get('DBG','',$_GET)){echo'<pre style="width:600px;border:1px solid red;max-height:300px;overflow:auto;display:none">';print_r($this->_costs);echo'</pre>';}
  122. ?>
  123. <div class="container">
  124. <div style="float:right;color:#aaa;"><?php echo date("Y-m-d"); ?></div>
  125. <h1>Zestawienie kosztów projektów na rok <?php echo $year; ?></h1>
  126. <table cellspacing="0" cellpadding="0" border="0" id="zestawienie-kosztow-projektow" class="zestawienie-kosztow-tbl">
  127. <thead>
  128. <tr>
  129. <td colspan="3" class="p2">
  130. <span class="pull-left">
  131. <input type="checkbox" onclick="return showHideAll(this);"/> pokaż tylko zaznaczone
  132. </span>
  133. <span class="pull-right"><b>miesiąc</b></span>
  134. </td>
  135. <?php foreach ($months as $month) { ?>
  136. <th class="c"><?php echo sprintf("%02d", $month); ?></th>
  137. <?php } ?>
  138. </tr>
  139. </thead>
  140. <tbody>
  141. <?php $t = 1; ?>
  142. <?php foreach ($this->_projectPathsOrder as $projPath => $projId) : ?>
  143. <?php $projectInfo = $this->_costs[$projId]; ?>
  144. <?php if (empty($projectInfo)) {
  145. //echo'<tr><td colspan="10"><pre>ERROR:EMPTY: Path('.$projPath.') id('.$projId.')</pre></td></tr>';
  146. continue;
  147. } ?>
  148. <tr class="row-<?php echo ($t = 1 - $t); ?>"
  149. data-proj_id="<?php echo $projectInfo->ID_PROJECT; ?>"
  150. data-path="<?php echo $projectInfo->path; ?>">
  151. <td class="p2 r nr">
  152. <input type="checkbox" name="selectedProject" onclick="return selectProject(this);" value="<?php echo $projectInfo->ID_PROJECT; ?>" />
  153. </td>
  154. <td class="p2 l nr"><?php echo $projectInfo->path; ?></td>
  155. <td class="p2" style="max-width:300px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;" title="<?php echo $projectInfo->M_DIST_DESC; ?>"><?php echo $projectInfo->M_DIST_DESC; ?></td>
  156. <?php foreach ($months as $month) : ?>
  157. <?php if (array_key_exists($month, $projectInfo->costsByMonth)) : ?>
  158. <?php $vCost = V::get($month, '', $projectInfo->costsByMonth); ?>
  159. <?php $vCostChildOut = number_format($vCost->COST_CHILD, 2); ?>
  160. <?php $vCostSelfOut = number_format($vCost->COST_SELF, 2); ?>
  161. <?php $vCostTotalOut = number_format($vCost->COST_TOTAL, 2); ?>
  162. <?php if ($vCost->COST_CHILD > 0) : ?>
  163. <?php $title = "Koszt projektu {$vCostSelfOut} / koszt podprojektów $vCostChildOut"; ?>
  164. <?php if ($vCost->COST_SELF > 0) : ?>
  165. <td class="cell-cost cell-cost-self_and_child"
  166. data-month_num="<?php echo $month; ?>"
  167. data-proj_path="<?php echo $projectInfo->path; ?>"
  168. data-proj_id="<?php echo $projectInfo->ID_PROJECT; ?>">
  169. <span class="ttip" title="<?php echo $title; ?>"><?php echo $vCostTotalOut; ?></span>
  170. </td>
  171. <?php else : ?>
  172. <td class="cell-cost cell-cost-only_child"
  173. data-month_num="<?php echo $month; ?>"
  174. data-proj_path="<?php echo $projectInfo->path; ?>"
  175. data-proj_id="<?php echo $projectInfo->ID_PROJECT; ?>">
  176. <span class="ttip" title="<?php echo $title; ?>"><?php echo $vCostTotalOut; ?></span>
  177. </td>
  178. <?php endif; ?>
  179. <?php else : ?>
  180. <td class="cell-cost cell-cost-only_self"
  181. data-month_num="<?php echo $month; ?>"
  182. data-proj_path="<?php echo $projectInfo->path; ?>"
  183. data-proj_id="<?php echo $projectInfo->ID_PROJECT; ?>">
  184. <?php echo $vCostTotalOut; ?>
  185. </td>
  186. <?php endif; ?>
  187. <?php else : ?>
  188. <td style="min-width:30px">&nbsp;</td>
  189. <?php endif; ?>
  190. <?php endforeach; ?>
  191. </tr>
  192. <?php endforeach; ?>
  193. </tbody>
  194. </table>
  195. <script>
  196. jQuery(document).ready(function() {
  197. jQuery('#zestawienie-kosztow-projektow')
  198. .find('.cell-cost')
  199. .on('click', function(e) {
  200. var $n = jQuery(this);
  201. console.log('node', $n, 'data', $n.data());
  202. })
  203. })
  204. </script>
  205. <table id="proj-koresp-info" style="display:none">
  206. <?php foreach ($this->_costs as $projId => $projectInfo) : ?>
  207. <?php if (!empty($projectInfo->korespByMonth)) : ?>
  208. <?php foreach ($projectInfo->korespByMonth as $kMonth => $vKorespMonthList) : ?>
  209. <tbody id="row-proj-<?php echo $projectInfo->ID_PROJECT; ?>-koresp-by-month-<?php echo $kMonth; ?>">
  210. <tr>
  211. <td colspan="10">
  212. Projekt nr <?php echo $projectInfo->ID_PROJECT; ?>
  213. - miesiąc <?php echo $year; ?>-<?php echo sprintf("%02d", $kMonth); ?>
  214. </td>
  215. </tr>
  216. <?php foreach ($vKorespMonthList as $kKorespIdx => $vKorespInfo) : ?>
  217. <?php /*
  218. [ID] => 41235
  219. [MONTH] => 2015-02
  220. [K_ZAWARTOS] => Faktura za pomiar powykonawczy sieci telekomunikacyjnej
  221. [COST] => 1000.00
  222. [INCOME] => 0.00
  223. */ ?>
  224. <tr>
  225. <td class="p2 l nr"><?php echo $vKorespInfo->ID; ?></td>
  226. <td class="p2" style="max-width:400px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;" title="<?php echo $projectInfo->M_DIST_DESC; ?>"><?php echo $vKorespInfo->K_ZAWARTOS; ?></td>
  227. <?php $vKorespCostOut = number_format($vKorespInfo->COST, 2); ?>
  228. <td class="cell-cost cell-cost-only_self"><?php echo $vKorespCostOut; ?></td>
  229. </tr>
  230. <?php endforeach; ?>
  231. </tbody>
  232. <?php endforeach; ?>
  233. <?php endif; ?>
  234. <?php endforeach; ?>
  235. </table>
  236. </div>
  237. <script>
  238. jQuery(document).ready(function(){
  239. jQuery('.ttip').tooltip();
  240. });
  241. function selectProject(n) {
  242. var $n = jQuery(n);
  243. var $p = $n.parent().parent();
  244. if (n.checked) {
  245. $p.addClass('row-selected');
  246. } else {
  247. $p.removeClass('row-selected');
  248. }
  249. markSubProjects($p, $p.data('path'), n.checked);
  250. function markSubProjects($p, path, checked) {
  251. var $nextRow = $p.next('tr'),
  252. nextPath = $nextRow.data('path'),
  253. nextCheckbox = $nextRow.find('input[type="checkbox"]').get(0);
  254. if (0 !== nextPath.indexOf(path)) {
  255. return;
  256. }
  257. if (checked) {
  258. $nextRow.addClass('row-selected');
  259. } else {
  260. $nextRow.removeClass('row-selected');
  261. }
  262. nextCheckbox.checked = checked;
  263. markSubProjects($nextRow, path, checked);
  264. }
  265. }
  266. function showHideAll(n) {
  267. if (n.checked) {
  268. jQuery('#zestawienie-kosztow-projektow').find('tbody').addClass('showOnlySelected');
  269. } else {
  270. jQuery('#zestawienie-kosztow-projektow').find('tbody').removeClass('showOnlySelected');
  271. }
  272. }
  273. </script>
  274. <?php
  275. }
  276. public function getCostsByYear__OLD($year) {
  277. $db = DB::getDB();
  278. $costs = array();
  279. $sql = "
  280. select
  281. t.`ID_PROJECT`
  282. , t.`M_DIST_DESC`
  283. , t.`P_ID`
  284. , t.`path`
  285. , t.`MONTH`
  286. , t.`COST_SELF`
  287. , t.`COST_CHILD`
  288. , t.`COST_TOTAL`
  289. , t.`INCOME_SELF`
  290. , t.`INCOME_CHILD`
  291. , t.`INCOME_TOTAL`
  292. from `test_budget_project_synthetics_view` as t
  293. where 1=1
  294. and t.`MONTH` like '{$year}-%'
  295. ";
  296. $res = $db->query($sql);
  297. while ($r = $db->fetch($res)) {
  298. if (!array_key_exists($r->ID_PROJECT, $costs)) {
  299. $projectInfo = new stdClass();
  300. $projectInfo->ID_PROJECT = $r->ID_PROJECT;
  301. $projectInfo->M_DIST_DESC = $r->M_DIST_DESC;
  302. $projectInfo->path = $r->path;
  303. $projectInfo->costsByMonth = array();
  304. $costs[$r->ID_PROJECT] = $projectInfo;
  305. }
  306. $cost = new stdClass();
  307. $cost->MONTH = $r->MONTH;
  308. $cost->COST_SELF = $r->COST_SELF;
  309. $cost->COST_CHILD = $r->COST_CHILD;
  310. $cost->COST_TOTAL = $r->COST_TOTAL;
  311. $cost->INCOME_SELF = $r->INCOME_SELF;
  312. $cost->INCOME_CHILD = $r->INCOME_CHILD;
  313. $cost->INCOME_TOTAL = $r->INCOME_TOTAL;
  314. $monthNum = intval(substr($r->MONTH, 5, 2));
  315. $costs[$r->ID_PROJECT]->costsByMonth[$monthNum] = $cost;
  316. }
  317. return $costs;
  318. }
  319. public function getCostsByYear($year) {
  320. $db = DB::getDB();
  321. $this->_costs = array();
  322. $sql = "
  323. select k.`ID`
  324. , k.`ID_PROJECT` AS `ID_PROJECT`
  325. , date_format(k.`K_DATA_OTRZYMANEJ_KORESP`,'%Y-%m') AS `MONTH`
  326. , k.`COST_VALUE` AS `COST`
  327. , k.`INCOME_VALUE` AS `INCOME`
  328. , k.`TRANSFER_OPPOSITE_ID_PROJECT`
  329. , k.`path`
  330. , IF(k.`TRANSFER_OPPOSITE_ID_PROJECT`>0
  331. , (select p.`path`
  332. from `IN7_MK_BAZA_DYSTRYBUCJI` p
  333. where p.`ID`=k.`TRANSFER_OPPOSITE_ID_PROJECT`
  334. limit 1
  335. )
  336. , '') as TRANSFER_OPPOSITE_PROJECT_PATH
  337. , k.`K_ZAWARTOS`
  338. from `IN7_DZIENNIK_KORESP` k
  339. where ((k.`COST_VALUE` > 0) or (k.`INCOME_VALUE` > 0))
  340. and k.`K_DATA_OTRZYMANEJ_KORESP` like '{$year}-%'
  341. ";
  342. //echo'<pre style="border:1px solid red;overflow:auto;max-height:400px">';print_r($sql);echo'</pre>';
  343. $res = $db->query($sql);
  344. while ($r = $db->fetch($res)) {
  345. $vProjId = ($r->ID_PROJECT > 0)? $r->ID_PROJECT : 0;
  346. $vProjPaths = array();
  347. $vProjIds = array(0 => true);
  348. if ($r->ID_PROJECT > 0) {
  349. $vProjPaths[] = $r->ID_PROJECT;
  350. if (!empty($r->path)) {
  351. $vProjPaths[] = $r->path;
  352. }
  353. }
  354. if ($r->TRANSFER_OPPOSITE_ID_PROJECT > 0) {
  355. $vProjPaths[] = $r->TRANSFER_OPPOSITE_ID_PROJECT;
  356. if (!empty($r->TRANSFER_OPPOSITE_PROJECT_PATH)) {
  357. $vProjPaths[] = $r->TRANSFER_OPPOSITE_PROJECT_PATH;
  358. }
  359. }
  360. if (!empty($vProjPaths)) {
  361. //echo'<p>DBG:$r->ID_PROJECT['.$r->ID_PROJECT.']: $vProjPaths = ' . json_encode($vProjPaths) . '</p>';
  362. $vProjPaths = implode('-', $vProjPaths);
  363. $projIds = explode('-', $vProjPaths);
  364. //echo'<p>DBG:$r->ID_PROJECT['.$r->ID_PROJECT.']: $projIds = ' . json_encode($projIds) . '</p>';
  365. foreach ($projIds as $vProjId) {
  366. if ($vProjId > 0) $vProjIds[$vProjId] = true;
  367. }
  368. }
  369. {
  370. $projectZeroInfo = new stdClass();
  371. $projectZeroInfo->ID_PROJECT = 0;
  372. $projectZeroInfo->M_DIST_DESC = 'Wszystkie projekty';
  373. $projectZeroInfo->path = '0';
  374. $projectZeroInfo->costsByMonth = array();
  375. $projectZeroInfo->korespByMonth = array();
  376. $this->_costs[0] = $projectZeroInfo;
  377. }
  378. foreach ($vProjIds as $vProjId => $vBool) {
  379. if (!array_key_exists($vProjId, $this->_costs)) {
  380. $projectInfo = new stdClass();
  381. $projectInfo->ID_PROJECT = $vProjId;
  382. $projectInfo->M_DIST_DESC = '';
  383. $projectInfo->path = '';
  384. $projectInfo->costsByMonth = array();
  385. $projectInfo->korespByMonth = array();
  386. $this->_costs[$vProjId] = $projectInfo;
  387. }
  388. }
  389. $korespInfo = new stdClass();
  390. $korespInfo->ID = $r->ID;
  391. $korespInfo->MONTH = $r->MONTH;
  392. $korespInfo->K_ZAWARTOS = $r->K_ZAWARTOS;
  393. $monthNum = intval(substr($r->MONTH, 5, 2));
  394. if ($r->TRANSFER_OPPOSITE_ID_PROJECT > 0) {
  395. $korespInfo->COST = $r->INCOME;
  396. $korespInfo->INCOME = $r->COST;
  397. $korespInfo->TRANSFER_OPPOSITE_ID_PROJECT = $r->TRANSFER_OPPOSITE_ID_PROJECT;
  398. $this->_costs[$r->TRANSFER_OPPOSITE_ID_PROJECT]->korespByMonth[$monthNum][] = $korespInfo;
  399. } else if ($r->ID_PROJECT) {
  400. $korespInfo->COST = $r->COST;
  401. $korespInfo->INCOME = $r->INCOME;
  402. $this->_costs[$r->ID_PROJECT]->korespByMonth[$monthNum][] = $korespInfo;
  403. } else {
  404. $korespInfo->COST = $r->COST;
  405. $korespInfo->INCOME = $r->INCOME;
  406. $this->_costs[0]->korespByMonth[$monthNum][] = $korespInfo;
  407. }
  408. }
  409. $this->_fetchProjectInfo();
  410. $this->_buildProjectTree();
  411. $this->_reacountCostsFromKoresp();
  412. return $this->_costs;
  413. }
  414. private function _fetchProjectInfo() {
  415. $db = DB::getDB();
  416. $projectIds = array_keys($this->_costs);
  417. $sqlProjIds = "'" . implode("','", $projectIds) . "'";
  418. $sql = "select p.`ID`, p.`P_ID`, p.`path`, p.`M_DIST_DESC`
  419. from `IN7_MK_BAZA_DYSTRYBUCJI` p
  420. where p.`ID` in({$sqlProjIds})
  421. ";
  422. $res = $db->query($sql);
  423. while ($r = $db->fetch($res)) {
  424. $this->_costs[$r->ID]->path = $r->path;
  425. $this->_costs[$r->ID]->M_DIST_DESC = $r->M_DIST_DESC;
  426. }
  427. }
  428. private function _reacountCostsFromKoresp() {
  429. $projMonthHasCostSelfIds = array();
  430. foreach ($this->_costs as $kProjId => $vProjInfo) {
  431. foreach ($vProjInfo->korespByMonth as $kMonthNum => $vKorespList) {
  432. $this->_createCostIfNotDefined($kProjId, $kMonthNum);
  433. foreach ($vKorespList as $vKoresp) {
  434. $this->_costs[$kProjId]->costsByMonth[$kMonthNum]->COST_SELF += $vKoresp->COST;
  435. $this->_costs[$kProjId]->costsByMonth[$kMonthNum]->INCOME_SELF += $vKoresp->INCOME;
  436. }
  437. $projHasCostSelfIds[$kProjId][$kMonthNum] = $vProjInfo->path;
  438. }
  439. }
  440. //echo'<pre style="width:600px;border:1px solid red;max-height:300px;overflow:auto;">$projHasCostSelfIds: ';print_r($projHasCostSelfIds);echo'</pre>';
  441. foreach ($projHasCostSelfIds as $kProjId => $vProjMonthsList) {
  442. if ($kProjId <= 0) continue;
  443. foreach ($vProjMonthsList as $kMonthNum => $vProjPath) {
  444. $vProjPathIds = explode('-', $vProjPath);
  445. $vProjPathIds = array_reverse($vProjPathIds);
  446. $vProjMonthCostSelf = $this->_costs[$kProjId]->costsByMonth[$kMonthNum]->COST_SELF;
  447. $vProjMonthIncomeSelf = $this->_costs[$kProjId]->costsByMonth[$kMonthNum]->INCOME_SELF;
  448. foreach ($vProjPathIds as $vProjId) {
  449. if ($vProjId == $kProjId) continue;
  450. $this->_createCostIfNotDefined($vProjId, $kMonthNum);
  451. $this->_costs[$vProjId]->costsByMonth[$kMonthNum]->COST_CHILD += $vProjMonthCostSelf;
  452. $this->_costs[$vProjId]->costsByMonth[$kMonthNum]->INCOME_CHILD += $vProjMonthIncomeSelf;
  453. }
  454. }
  455. }
  456. // recount total
  457. foreach ($this->_costs as $vProjId => $vProjInfo) {
  458. foreach ($vProjInfo->costsByMonth as $kMonthNum => $vCost) {
  459. $this->_createCostIfNotDefined($vProjId, $kMonthNum);
  460. $this->_costs[$vProjId]->costsByMonth[$kMonthNum]->COST_TOTAL = $vCost->COST_SELF + $vCost->COST_CHILD;
  461. $this->_costs[$vProjId]->costsByMonth[$kMonthNum]->INCOME_TOTAL = $vCost->INCOME_SELF + $vCost->INCOME_CHILD;
  462. }
  463. }
  464. }
  465. private function _createCostIfNotDefined($projId, $monthNum) {
  466. if (empty($this->_costs[$projId]->costsByMonth[$monthNum])) {
  467. $vEmptyCost = new stdClass();
  468. $vEmptyCost->COST_SELF = 0;
  469. $vEmptyCost->INCOME_SELF = 0;
  470. $vEmptyCost->COST_CHILD = 0;
  471. $vEmptyCost->INCOME_CHILD = 0;
  472. $vEmptyCost->COST_TOTAL = 0;
  473. $vEmptyCost->INCOME_TOTAL = 0;
  474. $this->_costs[$projId]->costsByMonth[$monthNum] = $vEmptyCost;
  475. }
  476. }
  477. public function _buildProjectTree() {
  478. $this->_projectPathsOrder = array();
  479. foreach ($this->_costs as $idProject => $projectInfo) {
  480. $this->_projectPathsOrder[$projectInfo->path] = $projectInfo->ID_PROJECT;
  481. }
  482. //echo'<pre style="width:600px;border:1px solid red;max-height:300px;overflow:auto;">projPaths: ';print_r($this->_projectPathsOrder);echo'</pre>';
  483. uksort($this->_projectPathsOrder, array($this, 'sortPathsCallback'));
  484. //echo'<pre style="width:600px;border:1px solid red;max-height:300px;overflow:auto;">projPaths sorted: ';print_r($this->_projectPathsOrder);echo'</pre>';
  485. return $this->_projectPathsOrder;
  486. }
  487. public function sortPathsCallback($a, $b) {
  488. $ea = explode('-', $a);
  489. $eb = explode('-', $b);
  490. $la = count($ea);
  491. $lb = count($eb);
  492. $lmin = min($la, $lb);
  493. for ($i = 0; $i < $lmin; $i++) {
  494. if ($ea[$i] < $eb[$i]) {
  495. return -1;
  496. } else if ($ea[$i] > $eb[$i]) {
  497. return 1;
  498. }
  499. }
  500. return $la - $lb;
  501. }
  502. }