|
|
@@ -0,0 +1,397 @@
|
|
|
+<?php
|
|
|
+
|
|
|
+Lib::loadClass('RouteBase');
|
|
|
+
|
|
|
+class Route_Budget extends RouteBase {
|
|
|
+
|
|
|
+ public function handleAuth() {
|
|
|
+ if (!User::logged()) {
|
|
|
+ throw new HttpException('Unauthorized', 401);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ public function defaultAction() {
|
|
|
+ $args = array();
|
|
|
+ $args['year'] = V::get('year', '', $_REQUEST, 'int');
|
|
|
+ $args['_print'] = V::get('_print', '', $_REQUEST, 'int');
|
|
|
+
|
|
|
+ SE_Layout::gora();
|
|
|
+ //SE_Layout::menu();
|
|
|
+ if (!$args['_print']) {
|
|
|
+ $this->menu($args['year']);
|
|
|
+ }
|
|
|
+ SE_Layout::dol();
|
|
|
+ }
|
|
|
+
|
|
|
+ public function yearBudgetAction() {
|
|
|
+ $args = array();
|
|
|
+ $args['year'] = V::get('year', '', $_REQUEST, 'int');
|
|
|
+ $args['_print'] = V::get('_print', '', $_REQUEST, 'int');
|
|
|
+
|
|
|
+ SE_Layout::gora();
|
|
|
+ //SE_Layout::menu();
|
|
|
+ if (!$args['_print']) {
|
|
|
+ $this->menu($args['year']);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (empty($args['year'])) {
|
|
|
+ ?>
|
|
|
+ <div class="alert alert-warning">
|
|
|
+ Nie wybrano roku.
|
|
|
+ </div>
|
|
|
+ <?php
|
|
|
+ SE_Layout::dol();
|
|
|
+ exit;
|
|
|
+ }
|
|
|
+
|
|
|
+ $costs = $this->getCostsByYear($args['year']);
|
|
|
+ if (empty($costs)) {
|
|
|
+ ?>
|
|
|
+ <div class="alert alert-warning">
|
|
|
+ Brak danych na wybrany rok.
|
|
|
+ </div>
|
|
|
+ <?php
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ echo'<pre style="border:1px solid red;overflow:auto;max-height:400px">';print_r($costs);echo'</pre>';
|
|
|
+
|
|
|
+ $projTree = $this->buildProjectTree($costs);
|
|
|
+ $this->printCostsForYear($projTree, $costs, $args['year']);
|
|
|
+
|
|
|
+ SE_Layout::dol();
|
|
|
+ }
|
|
|
+
|
|
|
+ private function menu($selectedYear) {
|
|
|
+ //SE_Layout::menu();
|
|
|
+ $year = ($selectedYear)? $selectedYear : date("Y");
|
|
|
+ ?>
|
|
|
+<div class="jumbotron">
|
|
|
+ <div class="container">
|
|
|
+ <form class="form-inline" method="POST">
|
|
|
+ <input type="hidden" name="_task" value="yearBudget" />
|
|
|
+ <label for="year">Zestawienie kosztów projektów na podstawie korespondencji:</label>
|
|
|
+ <div class="input-group date" id="fldZestYear">
|
|
|
+ <input type="text" name="year" class="form-control" value="" />
|
|
|
+ <span class="input-group-addon"><span class="glyphicon glyphicon-time"></span></span>
|
|
|
+ </div>
|
|
|
+ <button type="submit" id="fldZestYearBtn" class="btn btn-primary" autocomplete="off">
|
|
|
+ Pokaż
|
|
|
+ </button>
|
|
|
+ </form>
|
|
|
+ </div>
|
|
|
+</div>
|
|
|
+<script type="text/javascript">
|
|
|
+jQuery(document).ready(function () {
|
|
|
+ jQuery('#fldZestYearBtn').on('click', function () {
|
|
|
+ jQuery(this).text(jQuery(this).text() + '...').attr('disabled', 'disabled');
|
|
|
+ jQuery(this).parent().submit();
|
|
|
+ })
|
|
|
+
|
|
|
+ jQuery("#fldZestYear").datetimepicker({
|
|
|
+ format: "YYYY",
|
|
|
+ defaultDate: new Date(<?php echo $year; ?>, <?php echo intval(date("m")); ?>, 1),
|
|
|
+ // minDate: new Date(2014, 11, 1),
|
|
|
+ // maxDate: "<?php echo date("Y"); ?>"
|
|
|
+ });
|
|
|
+});
|
|
|
+</script>
|
|
|
+ <?php
|
|
|
+ }
|
|
|
+
|
|
|
+ function css() {
|
|
|
+ ?>
|
|
|
+ <style type="text/css">
|
|
|
+ .c { text-align:center; }
|
|
|
+ .r { text-align:right; }
|
|
|
+
|
|
|
+ .zestawienie-kosztow-tbl { border-collapse:collapse; border:1px solid #7EC5FF; }
|
|
|
+ .zestawienie-kosztow-tbl td { border:1px solid #7EC5FF; }
|
|
|
+ .zestawienie-kosztow-tbl .p2 { padding:0 2px; }
|
|
|
+ .zestawienie-kosztow-tbl .nr { color:#7A7A7A; }
|
|
|
+ .zestawienie-kosztow-tbl thead th { border:1px solid #7EC5FF; }
|
|
|
+ .zestawienie-kosztow-tbl tbody tr:hover td { background:#cafbfd; }
|
|
|
+ .row-selected td {background-color:#d8fded;}
|
|
|
+ .showOnlySelected tr { display:none; }
|
|
|
+ .showOnlySelected tr.row-selected { display:table-row; }
|
|
|
+
|
|
|
+ .cost { padding:0 2px; min-width:30px; text-align:right; }
|
|
|
+ .cost-only_child { color:#777; }
|
|
|
+ .cost-only_self { color:red; }
|
|
|
+ .cost-self_and_child { color:orange; }
|
|
|
+
|
|
|
+ /* print table background colors */
|
|
|
+ table td, table th { -webkit-print-color-adjust:exact; }
|
|
|
+ table { page-break-after:auto }
|
|
|
+ tr { page-break-inside:avoid; page-break-after:auto; position:relative; }
|
|
|
+ td { page-break-inside:avoid; page-break-after:auto; position:relative; }
|
|
|
+ thead { display:table-header-group }
|
|
|
+ tfoot { display:table-footer-group }
|
|
|
+ </style>
|
|
|
+ <?php
|
|
|
+ }
|
|
|
+
|
|
|
+ function printCostsForYear($projOrder, $costs, $year) {
|
|
|
+ $months = array();
|
|
|
+ for ($i = 0; $i < 12; $i++) {
|
|
|
+ $months[] = $i + 1;
|
|
|
+ }
|
|
|
+ $this->css();
|
|
|
+ if(V::get('DBG','',$_GET)){echo'<pre style="width:600px;border:1px solid red;max-height:300px;overflow:auto;display:none">';print_r($costs);echo'</pre>';}
|
|
|
+?>
|
|
|
+<div class="container">
|
|
|
+ <div style="float:right;color:#aaa;"><?php echo date("Y-m-d"); ?></div>
|
|
|
+ <h1>Zestawienie kosztów projektów na rok <?php echo $year; ?></h1>
|
|
|
+ <table cellspacing="0" cellpadding="0" border="0" id="zestawienie-kosztow-projektow" class="zestawienie-kosztow-tbl">
|
|
|
+ <thead>
|
|
|
+ <tr>
|
|
|
+ <td colspan="3" class="p2">
|
|
|
+ <span class="pull-left">
|
|
|
+ <input type="checkbox" onclick="return showHideAll(this);"/> pokaż tylko zaznaczone
|
|
|
+ </span>
|
|
|
+ <span class="pull-right">miesiąc</span>
|
|
|
+ </td>
|
|
|
+ <?php foreach ($months as $month) { ?>
|
|
|
+ <th class="c"><?php echo $month; ?></th>
|
|
|
+ <?php } ?>
|
|
|
+ </tr>
|
|
|
+ </thead>
|
|
|
+ <tbody>
|
|
|
+ <?php $t = 1; ?>
|
|
|
+ <?php foreach ($projOrder as $projPath => $projId) : ?>
|
|
|
+ <?php $projectInfo = $costs[$projId]; ?>
|
|
|
+ <tr class="row-<?php echo ($t = 1 - $t); ?>"
|
|
|
+ data-projId="<?php echo $projectInfo->ID_PROJECT; ?>"
|
|
|
+ data-path="<?php echo $projectInfo->path; ?>">
|
|
|
+ <td class="p2 r nr">
|
|
|
+ <input type="checkbox" name="selectedProject" onclick="return selectProject(this);" value="<?php echo $projectInfo->ID_PROJECT; ?>" />
|
|
|
+ </td>
|
|
|
+ <td class="p2 l nr"><?php echo $projectInfo->path; ?></td>
|
|
|
+ <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>
|
|
|
+ <?php foreach ($months as $month) : ?>
|
|
|
+ <?php if (array_key_exists($month, $projectInfo->costsByMonth)) : ?>
|
|
|
+ <?php $vCost = V::get($month, '', $projectInfo->costsByMonth); ?>
|
|
|
+ <?php $vCostChildOut = number_format($vCost->COST_CHILD, 2); ?>
|
|
|
+ <?php $vCostSelfOut = number_format($vCost->COST_SELF, 2); ?>
|
|
|
+ <?php $vCostTotalOut = number_format($vCost->COST_TOTAL, 2); ?>
|
|
|
+ <?php if ($vCost->COST_CHILD > 0) : ?>
|
|
|
+ <?php $title = "Koszt projektu {$vCostSelfOut} / koszt podprojektów $vCostChildOut"; ?>
|
|
|
+ <?php if ($vCost->COST_SELF > 0) : ?>
|
|
|
+ <td class="cost cost-self_and_child"><span class="ttip" title="<?php echo $title; ?>"><?php echo $vCostTotalOut; ?></span></td>
|
|
|
+ <?php else : ?>
|
|
|
+ <td class="cost cost-only_child"><span class="ttip" title="<?php echo $title; ?>"><?php echo $vCostTotalOut; ?></span></td>
|
|
|
+ <?php endif; ?>
|
|
|
+ <?php else : ?>
|
|
|
+ <td class="cost cost-only_self"><?php echo $vCostTotalOut; ?></td>
|
|
|
+ <?php endif; ?>
|
|
|
+ <?php else : ?>
|
|
|
+ <td style="min-width:30px"> </td>
|
|
|
+ <?php endif; ?>
|
|
|
+ <?php endforeach; ?>
|
|
|
+ </tr>
|
|
|
+ <?php endforeach; ?>
|
|
|
+ </tbody>
|
|
|
+ </table>
|
|
|
+</div>
|
|
|
+<script>
|
|
|
+ jQuery(document).ready(function(){
|
|
|
+ jQuery('.ttip').tooltip();
|
|
|
+ });
|
|
|
+
|
|
|
+ function selectProject(n) {
|
|
|
+ var $n = jQuery(n);
|
|
|
+ var $p = $n.parent().parent();
|
|
|
+ if (n.checked) {
|
|
|
+ $p.addClass('row-selected');
|
|
|
+ } else {
|
|
|
+ $p.removeClass('row-selected');
|
|
|
+ }
|
|
|
+ markSubProjects($p, $p.data('path'), n.checked);
|
|
|
+
|
|
|
+ function markSubProjects($p, path, checked) {
|
|
|
+ var $nextRow = $p.next('tr'),
|
|
|
+ nextPath = $nextRow.data('path'),
|
|
|
+ nextCheckbox = $nextRow.find('input[type="checkbox"]').get(0);
|
|
|
+ if (0 !== nextPath.indexOf(path)) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ if (checked) {
|
|
|
+ $nextRow.addClass('row-selected');
|
|
|
+ } else {
|
|
|
+ $nextRow.removeClass('row-selected');
|
|
|
+ }
|
|
|
+ nextCheckbox.checked = checked;
|
|
|
+ markSubProjects($nextRow, path, checked);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ function showHideAll(n) {
|
|
|
+ if (n.checked) {
|
|
|
+ jQuery('#zestawienie-kosztow-projektow').find('tbody').addClass('showOnlySelected');
|
|
|
+ } else {
|
|
|
+ jQuery('#zestawienie-kosztow-projektow').find('tbody').removeClass('showOnlySelected');
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+</script>
|
|
|
+<?php
|
|
|
+ }
|
|
|
+
|
|
|
+ public function getCostsByYear__OLD($year) {
|
|
|
+ $db = DB::getDB();
|
|
|
+ $costs = array();
|
|
|
+ $sql = "
|
|
|
+ select
|
|
|
+ t.`ID_PROJECT`
|
|
|
+ , t.`M_DIST_DESC`
|
|
|
+ , t.`P_ID`
|
|
|
+ , t.`path`
|
|
|
+ , t.`MONTH`
|
|
|
+ , t.`COST_SELF`
|
|
|
+ , t.`COST_CHILD`
|
|
|
+ , t.`COST_TOTAL`
|
|
|
+ , t.`INCOME_SELF`
|
|
|
+ , t.`INCOME_CHILD`
|
|
|
+ , t.`INCOME_TOTAL`
|
|
|
+ from `test_budget_project_synthetics_view` as t
|
|
|
+ where 1=1
|
|
|
+ and t.`MONTH` like '{$year}-%'
|
|
|
+ ";
|
|
|
+ $res = $db->query($sql);
|
|
|
+ while ($r = $db->fetch($res)) {
|
|
|
+ if (!array_key_exists($r->ID_PROJECT, $costs)) {
|
|
|
+ $projectInfo = new stdClass();
|
|
|
+ $projectInfo->ID_PROJECT = $r->ID_PROJECT;
|
|
|
+ $projectInfo->M_DIST_DESC = $r->M_DIST_DESC;
|
|
|
+ $projectInfo->path = $r->path;
|
|
|
+ $projectInfo->costsByMonth = array();
|
|
|
+ $costs[$r->ID_PROJECT] = $projectInfo;
|
|
|
+ }
|
|
|
+ $cost = new stdClass();
|
|
|
+ $cost->MONTH = $r->MONTH;
|
|
|
+ $cost->COST_SELF = $r->COST_SELF;
|
|
|
+ $cost->COST_CHILD = $r->COST_CHILD;
|
|
|
+ $cost->COST_TOTAL = $r->COST_TOTAL;
|
|
|
+ $cost->INCOME_SELF = $r->INCOME_SELF;
|
|
|
+ $cost->INCOME_CHILD = $r->INCOME_CHILD;
|
|
|
+ $cost->INCOME_TOTAL = $r->INCOME_TOTAL;
|
|
|
+ $monthNum = intval(substr($r->MONTH, 5, 2));
|
|
|
+ $costs[$r->ID_PROJECT]->costsByMonth[$monthNum] = $cost;
|
|
|
+ }
|
|
|
+ return $costs;
|
|
|
+ }
|
|
|
+
|
|
|
+ public function getCostsByYear($year) {
|
|
|
+ $db = DB::getDB();
|
|
|
+ $costs = array();
|
|
|
+ $sql = "
|
|
|
+ select k.`ID_PROJECT` AS `ID_PROJECT`
|
|
|
+ , date_format(k.`K_DATA_OTRZYMANEJ_KORESP`,'%Y-%m') AS `MONTH`
|
|
|
+ , k.`COST_VALUE` AS `COST`
|
|
|
+ , k.`INCOME_VALUE` AS `INCOME`
|
|
|
+ , k.`TRANSFER_OPPOSITE_ID_PROJECT`
|
|
|
+ , k.`K_ZAWARTOS`
|
|
|
+ from `IN7_DZIENNIK_KORESP` k
|
|
|
+ where ((k.`COST_VALUE` > 0) or (k.`INCOME_VALUE` > 0))
|
|
|
+ and k.`K_DATA_OTRZYMANEJ_KORESP` like '{$year}-%'
|
|
|
+ ";
|
|
|
+ //echo'<pre style="border:1px solid red;overflow:auto;max-height:400px">';print_r($sql);echo'</pre>';
|
|
|
+ $res = $db->query($sql);
|
|
|
+ while ($r = $db->fetch($res)) {
|
|
|
+ $vProjIds = array();
|
|
|
+ if ($r->ID_PROJECT > 0) $vProjIds[] = $r->ID_PROJECT;
|
|
|
+ if ($r->TRANSFER_OPPOSITE_ID_PROJECT > 0) $vProjIds[] = $r->TRANSFER_OPPOSITE_ID_PROJECT;
|
|
|
+ foreach ($vProjIds as $vProjId) {
|
|
|
+ if (!array_key_exists($vProjId, $costs)) {
|
|
|
+ $projectInfo = new stdClass();
|
|
|
+ $projectInfo->ID_PROJECT = $vProjId;
|
|
|
+ $projectInfo->M_DIST_DESC = '';
|
|
|
+ $projectInfo->path = '';
|
|
|
+ $projectInfo->costsByMonth = array();
|
|
|
+ $projectInfo->korespByMonth = array();
|
|
|
+ $costs[$vProjId] = $projectInfo;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ $korespInfo = new stdClass();
|
|
|
+ $korespInfo->MONTH = $r->MONTH;
|
|
|
+ $korespInfo->K_ZAWARTOS = $r->K_ZAWARTOS;
|
|
|
+ $monthNum = intval(substr($r->MONTH, 5, 2));
|
|
|
+ if ($r->TRANSFER_OPPOSITE_ID_PROJECT > 0) {
|
|
|
+ $korespInfo->COST = $r->INCOME;
|
|
|
+ $korespInfo->INCOME = $r->COST;
|
|
|
+ $korespInfo->TRANSFER_OPPOSITE_ID_PROJECT = $r->TRANSFER_OPPOSITE_ID_PROJECT;
|
|
|
+ $costs[$r->TRANSFER_OPPOSITE_ID_PROJECT]->korespByMonth[$monthNum][] = $korespInfo;
|
|
|
+ } else {
|
|
|
+ $korespInfo->COST = $r->COST;
|
|
|
+ $korespInfo->INCOME = $r->INCOME;
|
|
|
+ $costs[$r->ID_PROJECT]->korespByMonth[$monthNum][] = $korespInfo;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ $this->_fetchProjectInfo($costs);
|
|
|
+ $this->_reacountCostsFromKoresp($costs);
|
|
|
+ return $costs;
|
|
|
+ }
|
|
|
+
|
|
|
+ private function _fetchProjectInfo(&$costs) {
|
|
|
+ $db = DB::getDB();
|
|
|
+ $projectIds = array_keys($costs);
|
|
|
+ $sqlProjIds = "'" . implode("','", $projectIds) . "'";
|
|
|
+ $sql = "select p.`ID`, p.`path`, p.`M_DIST_DESC`
|
|
|
+ from `IN7_MK_BAZA_DYSTRYBUCJI` p
|
|
|
+ where p.`ID` in({$sqlProjIds})
|
|
|
+ ";
|
|
|
+ $res = $db->query($sql);
|
|
|
+ while ($r = $db->fetch($res)) {
|
|
|
+ $costs[$r->ID]->path = $r->path;
|
|
|
+ $costs[$r->ID]->M_DIST_DESC = $r->M_DIST_DESC;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private function _reacountCostsFromKoresp(&$costs) {
|
|
|
+ foreach ($costs as $vProjId => $vProjInfo) {
|
|
|
+ foreach ($vProjInfo->korespByMonth as $monthNum => $vKorespList) {
|
|
|
+ $vCostInfo = new stdClass();
|
|
|
+ $vCostInfo->COST_SELF = 0;
|
|
|
+ $vCostInfo->COST_CHILD = 0;
|
|
|
+ $vCostInfo->COST_TOTAL = 0;
|
|
|
+ $vCostInfo->INCOME_SELF = 0;
|
|
|
+ $vCostInfo->INCOME_CHILD = 0;
|
|
|
+ $vCostInfo->INCOME_TOTAL = 0;
|
|
|
+ $costs[$vProjId]->costsByMonth[$monthNum] = $vCostInfo;
|
|
|
+ foreach ($vKorespList as $vKoresp) {
|
|
|
+ $costs[$vProjId]->costsByMonth[$monthNum]->COST_SELF += $vKoresp->COST;
|
|
|
+ $costs[$vProjId]->costsByMonth[$monthNum]->INCOME_SELF += $vKoresp->INCOME;
|
|
|
+ }
|
|
|
+ $costs[$vProjId]->costsByMonth[$monthNum]->COST_TOTAL += $costs[$vProjId]->costsByMonth[$monthNum]->COST_SELF;
|
|
|
+ $costs[$vProjId]->costsByMonth[$monthNum]->INCOME_TOTAL += $costs[$vProjId]->costsByMonth[$monthNum]->INCOME_SELF;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ public function buildProjectTree($costs) {
|
|
|
+ $projPaths = array();
|
|
|
+ foreach ($costs as $idProject => $projectInfo) {
|
|
|
+ $projPaths[$projectInfo->path] = $projectInfo->ID_PROJECT;
|
|
|
+ }
|
|
|
+ //echo'<pre style="width:600px;border:1px solid red;max-height:300px;overflow:auto;">projPaths: ';print_r($projPaths);echo'</pre>';
|
|
|
+ uksort($projPaths, array($this, 'sortPathsCallback'));
|
|
|
+ //echo'<pre style="width:600px;border:1px solid red;max-height:300px;overflow:auto;">projPaths sorted: ';print_r($projPaths);echo'</pre>';
|
|
|
+ return $projPaths;
|
|
|
+ }
|
|
|
+
|
|
|
+ public function sortPathsCallback($a, $b) {
|
|
|
+ $ea = explode('-', $a);
|
|
|
+ $eb = explode('-', $b);
|
|
|
+ $la = count($ea);
|
|
|
+ $lb = count($eb);
|
|
|
+ $lmin = min($la, $lb);
|
|
|
+ for ($i = 0; $i < $lmin; $i++) {
|
|
|
+ if ($ea[$i] < $eb[$i]) {
|
|
|
+ return -1;
|
|
|
+ } else if ($ea[$i] > $eb[$i]) {
|
|
|
+ return 1;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return $la - $lb;
|
|
|
+ }
|
|
|
+
|
|
|
+}
|