Explorar el Código

Budget: add plan, add triggers for budget plan to update path from project

Piotr Labudda hace 10 años
padre
commit
379a9706dd
Se han modificado 1 ficheros con 236 adiciones y 107 borrados
  1. 236 107
      SE/se-lib/Route/Budget.php

+ 236 - 107
SE/se-lib/Route/Budget.php

@@ -4,6 +4,11 @@ Lib::loadClass('RouteBase');
 
 class Route_Budget extends RouteBase {
 
+	private $_costs = array();
+	private $_plan = array();
+	private $_projectInfo = array();
+	private $_projectPathsOrder = array();
+
 	public function handleAuth() {
 		if (!User::logged()) {
 			throw new HttpException('Unauthorized', 401);
@@ -44,8 +49,8 @@ class Route_Budget extends RouteBase {
 			exit;
 		}
 
-		$costs = $this->getCostsByYear($args['year']);
-		if (empty($costs)) {
+		$hasData = $this->fetchDataByYear($args['year']);
+		if (!$hasData) {
 			?>
 			<div class="alert alert-warning">
 				Brak danych na wybrany rok.
@@ -103,20 +108,26 @@ jQuery(document).ready(function () {
 		.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 { border-collapse:collapse; border:1px solid #aaa; }
+		.zestawienie-kosztow-tbl td { border:1px solid #aaa; }
 		.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 thead th { border:1px solid #aaa; }
 		.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; }
 
 		.cell-cost { padding:0 2px; min-width:30px; text-align:right; }
-		.cell-cost-only_child { color:#777; }
-		.cell-cost-only_self { color:red; }
-		.cell-cost-self_and_child { color:orange; }
+		.cell-cost-only_self      { color:#197fe6; }
+		.cell-cost-self_and_child { color:#33b2cc; }
+		.cell-cost-only_child     { color:#59a680; }
+		.cell-plan { padding:0 2px; min-width:30px; text-align:right; color:#777; }
+		.cell-procent { padding:0 2px; min-width:20px; text-align:right; color:#777; }
+		.cell-procent-below100 { color:#777; }
+		.cell-procent-100 { color:#777; }
+		.cell-procent-over100 { color:#ff9b00; }
+		.cell-procent-over200 { color:#f00; }
 
 		/* print table background colors */
 		table td, table th { -webkit-print-color-adjust:exact; }
@@ -130,7 +141,6 @@ jQuery(document).ready(function () {
 	}
 
 	function printCostsForYear($year) {
-		$this->_costs = $this->_costs;
 		$months = array();
 		for ($i = 0; $i < 12; $i++) {
 			$months[] = $i + 1;
@@ -141,73 +151,101 @@ jQuery(document).ready(function () {
 <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>
+</div>
 	<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-right"><b>miesiąc</b></span>
+			</td>
+			<?php foreach ($months as $month) { ?>
+				<th class="c" colspan="3"><?php echo sprintf("%02d", $month); ?></th>
+			<?php } ?>
+		</tr>
 		<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"><b>miesiąc</b></span>
 			</td>
 			<?php foreach ($months as $month) { ?>
-				<th class="c"><?php echo sprintf("%02d", $month); ?></th>
+				<th class="c" title="Koszty wprowadzone do korespondencji">Koszty</th>
+				<th class="c" title="Plan budżetu">Plan</th>
+				<th class="c" title="Procent przekroczenia planu">%</th>
 			<?php } ?>
 		</tr>
 	</thead>
 	<tbody>
 	<?php $t = 1; ?>
 	<?php foreach ($this->_projectPathsOrder as $projPath => $projId) : ?>
-		<?php $projectInfo = $this->_costs[$projId]; ?>
-		<?php if (empty($projectInfo)) {
-			//echo'<tr><td colspan="10"><pre>ERROR:EMPTY: Path('.$projPath.') id('.$projId.')</pre></td></tr>';
-			continue;
-		} ?>
+		<?php $projectID   = $projId; ?>
+		<?php $projectDesc = $this->_projectInfo[$projId]->M_DIST_DESC; ?>
+		<?php $projectPath = $this->_projectInfo[$projId]->path; ?>
 		<tr class="row-<?php echo ($t = 1 - $t); ?>"
-				data-proj_id="<?php echo $projectInfo->ID_PROJECT; ?>"
-				data-path="<?php echo $projectInfo->path; ?>">
+				data-proj_id="<?php echo $projectID; ?>"
+				data-path="<?php echo $projectPath; ?>">
 			<td class="p2 r nr">
-				<input type="checkbox" name="selectedProject" onclick="return selectProject(this);" value="<?php echo $projectInfo->ID_PROJECT; ?>" />
+				<input type="checkbox" name="selectedProject" onclick="return selectProject(this);" value="<?php echo $projectID; ?>" />
 			</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>
+			<td class="p2 l nr"><nobr><?php echo $projectPath; ?></nobr></td>
+			<td class="p2" style="max-width:300px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;" title="<?php echo $projectDesc; ?>"><?php echo $projectDesc; ?></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="cell-cost cell-cost-self_and_child"
-					data-month_num="<?php echo $month; ?>"
-					data-cost="<?php echo $vCostTotalOut; ?>"
-					data-proj_path="<?php echo $projectInfo->path; ?>"
-					data-proj_id="<?php echo $projectInfo->ID_PROJECT; ?>">
-				<span class="ttip" title="<?php echo $title; ?>"><?php echo $vCostTotalOut; ?></span>
-			</td>
-						<?php else : ?>
-			<td class="cell-cost cell-cost-only_child"
+				<?php $vMonthCost = $this->getCost($projectID, $month); ?>
+				<?php $monthCostTotal = ($vMonthCost)? $vMonthCost->COST_TOTAL : 0; ?>
+				<?php if (!$vMonthCost) : ?>
+			<td style="min-width:30px">&nbsp;</td>
+				<?php else : ?>
+					<?php
+						$vCostChildOut = number_format($vMonthCost->COST_CHILD, 2);
+						$vCostSelfOut = number_format($vMonthCost->COST_SELF, 2);
+						$vCostTotalOut = number_format($vMonthCost->COST_TOTAL, 2);
+						$title = "Koszt projektu {$vCostSelfOut} / koszt podprojektów $vCostChildOut";
+						$cellCostCls = '';
+						if ($vMonthCost->COST_CHILD > 0) {
+							if ($vMonthCost->COST_SELF > 0) {
+								$cellCostCls = 'cell-cost-self_and_child';
+							} else {
+								$cellCostCls = 'cell-cost-only_child';
+							}
+						} else {
+							$cellCostCls = 'cell-cost-only_self';
+						}
+					?>
+			<td class="cell-cost <?php echo $cellCostCls; ?>"
 					data-month_num="<?php echo $month; ?>"
 					data-cost="<?php echo $vCostTotalOut; ?>"
-					data-proj_path="<?php echo $projectInfo->path; ?>"
-					data-proj_id="<?php echo $projectInfo->ID_PROJECT; ?>">
+					data-proj_path="<?php echo $projectPath; ?>"
+					data-proj_id="<?php echo $projectID; ?>">
 				<span class="ttip" title="<?php echo $title; ?>"><?php echo $vCostTotalOut; ?></span>
 			</td>
-						<?php endif; ?>
-					<?php else : ?>
-			<td class="cell-cost cell-cost-only_self"
-					data-month_num="<?php echo $month; ?>"
-					data-cost="<?php echo $vCostTotalOut; ?>"
-					data-proj_path="<?php echo $projectInfo->path; ?>"
-					data-proj_id="<?php echo $projectInfo->ID_PROJECT; ?>">
-				<?php echo $vCostTotalOut; ?>
-			</td>
-					<?php endif; ?>
+				<?php endif; ?>
+			<td class="cell-plan">
+				<?php $monthPlan = $this->getPlan($projectID, $month); ?>
+				<?php $monthPlanOut = number_format($monthPlan, 2); ?>
+				<?php if ($monthPlan > 0) : ?>
+					<?php echo $monthPlan; ?>
 				<?php else : ?>
-					<td style="min-width:30px">&nbsp;</td>
+					&nbsp;
 				<?php endif; ?>
+			</td>
+			<?php
+				$cellProcentCls = '';
+				$procentOut = '&nbsp;';
+				$monthPlan = $this->getPlan($projectID, $month);
+				if ($monthPlan > 0) {
+					$procentOut = round(($monthCostTotal * 100) / $monthPlan);
+					if ($procentOut > 200) {
+						$cellProcentCls = 'cell-procent-over200';
+					} else if ($procentOut > 100) {
+						$cellProcentCls = 'cell-procent-over100';
+					} else if ($procentOut == 100) {
+						$cellProcentCls = 'cell-procent-100';
+					} else {
+						$cellProcentCls = 'cell-procent-below100';
+					}
+				}
+			?>
+			<td class="cell-procent <?php echo $cellProcentCls; ?>"><?php echo $procentOut; ?></td>
 			<?php endforeach; ?>
 		</tr>
 	<?php endforeach; ?>
@@ -282,16 +320,19 @@ jQuery(document).ready(function() {
 	</div>
 	<table id="proj-koresp-info" style="display:none">
 		<?php foreach ($this->_costs as $projId => $projectInfo) : ?>
+			<?php $projectID   = $projId; ?>
+			<?php $projectDesc = $this->_projectInfo[$projId]->M_DIST_DESC; ?>
+			<?php $projectPath = $this->_projectInfo[$projId]->path; ?>
 			<?php if (!empty($projectInfo->korespByMonth)) : ?>
 				<?php foreach ($projectInfo->korespByMonth as $kMonth => $vKorespMonthList) : ?>
-					<tbody id="row-proj-<?php echo $projectInfo->ID_PROJECT; ?>-koresp-by-month-<?php echo $kMonth; ?>"
+					<tbody id="row-proj-<?php echo $projectID; ?>-koresp-by-month-<?php echo $kMonth; ?>"
 								 data-month_num="<?php echo $kMonth; ?>"
-								 data-proj_path="<?php echo $projectInfo->path; ?>"
-								 data-proj_id="<?php echo $projectInfo->ID_PROJECT; ?>">
+								 data-proj_path="<?php echo $projectPath; ?>"
+								 data-proj_id="<?php echo $projectID; ?>">
 						<tr>
-							<td style="padding:3px;font-size:1em;background:#eee;"><?php echo $projectInfo->path; ?></td>
+							<td style="padding:3px;font-size:1em;background:#eee;"><?php echo $projectPath; ?></td>
 							<td colspan="3" style="padding:3px;font-size:1.2em;background:#eee;">
-								Koszty projektu nr <?php echo $projectInfo->ID_PROJECT; ?>
+								Koszty projektu nr <?php echo $projectID; ?>
 								<!-- - miesiąc <?php echo $year; ?>-<?php echo sprintf("%02d", $kMonth); ?> -->
 							</td>
 						</tr>
@@ -306,7 +347,7 @@ jQuery(document).ready(function() {
 								*/ ?>
 							<tr>
 								<td class="p2 r nr"><?php echo $vKorespInfo->ID; ?></td>
-								<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>
+								<td class="p2" style="max-width:400px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;" title="<?php echo $vKorespInfo->K_ZAWARTOS; ?>"><?php echo $vKorespInfo->K_ZAWARTOS; ?></td>
 								<?php $vKorespCostOut = number_format($vKorespInfo->COST, 2); ?>
 								<td class="cell-cost cell-cost-only_child"><?php echo $vKorespCostOut; ?></td>
 								<td>
@@ -322,7 +363,6 @@ jQuery(document).ready(function() {
 			<?php endif; ?>
 		<?php endforeach; ?>
 	</table>
-</div>
 <script>
 	jQuery(document).ready(function(){
 		jQuery('.ttip').tooltip();
@@ -367,51 +407,70 @@ jQuery(document).ready(function() {
 <?php
 	}
 
-	public function getCostsByYear__OLD($year) {
+	public function getCost($idProject, $month) {
+		if (!array_key_exists($idProject, $this->_costs)) {
+			return null;
+		}
+		if (!array_key_exists($month, $this->_costs[$idProject]->costsByMonth)) {
+			return null;
+		}
+		return $this->_costs[$idProject]->costsByMonth[$month];
+	}
+
+	public function getPlan($idProject, $month) {
+		if (!array_key_exists($idProject, $this->_plan)) {
+			return 0;
+		}
+		if (!array_key_exists($month, $this->_plan[$idProject])) {
+			return 0;
+		}
+		return $this->_plan[$idProject][$month];
+	}
+
+	public function fetchDataByYear($year) {
+		$this->_fetchCostsByYear($year);
+		$this->_fetchPlanByYear($year);
+		$this->_fetchProjectInfo();
+		$this->_buildProjectTree();
+		$this->_reacountCostsFromKoresp();
+		return count($this->_projectInfo) > 1;// $this->_projectInfo[0] - Wszystkie projekty
+	}
+
+	public function _fetchPlanByYear($year) {
 		$db = DB::getDB();
-		$costs = array();
+		$this->_plan = 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}-%'
+			select plan.`ID`
+				, plan.`ID_PROJECT` AS `ID_PROJECT`
+				, plan.`MONTH_1_VALUE`
+				, plan.`MONTH_2_VALUE`
+				, plan.`MONTH_3_VALUE`
+				, plan.`MONTH_4_VALUE`
+				, plan.`MONTH_5_VALUE`
+				, plan.`MONTH_6_VALUE`
+				, plan.`MONTH_7_VALUE`
+				, plan.`MONTH_8_VALUE`
+				, plan.`MONTH_9_VALUE`
+				, plan.`MONTH_10_VALUE`
+				, plan.`MONTH_11_VALUE`
+				, plan.`MONTH_12_VALUE`
+			from `projects_budget_year_month` plan
+			where plan.`year`='{$year}'
+			-- TODO: acl
 		";
+		//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)) {
-			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;
+			$plan = array();
+			for ($i = 1; $i < 12; $i++) {
+				$plan[$i] = V::get("MONTH_{$i}_VALUE", 0, $r);
 			}
-			$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;
+			$this->_plan[$r->ID_PROJECT] = $plan;
 		}
-		return $costs;
+		return $this->_plan;
 	}
 
-	public function getCostsByYear($year) {
+	public function _fetchCostsByYear($year) {
 		$db = DB::getDB();
 		$this->_costs = array();
 		$sql = "
@@ -434,6 +493,7 @@ jQuery(document).ready(function() {
 			from `IN7_DZIENNIK_KORESP` k
 			where ((k.`COST_VALUE` > 0) or (k.`INCOME_VALUE` > 0))
 				and k.`K_DATA_OTRZYMANEJ_KORESP` like '{$year}-%'
+			-- TODO: acl
 		";
 		//echo'<pre style="border:1px solid red;overflow:auto;max-height:400px">';print_r($sql);echo'</pre>';
 		$res = $db->query($sql);
@@ -465,8 +525,6 @@ jQuery(document).ready(function() {
 			{
 				$projectZeroInfo = new stdClass();
 				$projectZeroInfo->ID_PROJECT = 0;
-				$projectZeroInfo->M_DIST_DESC = 'Wszystkie projekty';
-				$projectZeroInfo->path = '0';
 				$projectZeroInfo->costsByMonth = array();
 				$projectZeroInfo->korespByMonth = array();
 				$this->_costs[0] = $projectZeroInfo;
@@ -475,8 +533,6 @@ jQuery(document).ready(function() {
 				if (!array_key_exists($vProjId, $this->_costs)) {
 					$projectInfo = new stdClass();
 					$projectInfo->ID_PROJECT = $vProjId;
-					$projectInfo->M_DIST_DESC = '';
-					$projectInfo->path = '';
 					$projectInfo->costsByMonth = array();
 					$projectInfo->korespByMonth = array();
 					$this->_costs[$vProjId] = $projectInfo;
@@ -502,15 +558,18 @@ jQuery(document).ready(function() {
 				$this->_costs[0]->korespByMonth[$monthNum][] = $korespInfo;
 			}
 		}
-		$this->_fetchProjectInfo();
-		$this->_buildProjectTree();
-		$this->_reacountCostsFromKoresp();
 		return $this->_costs;
 	}
 
 	private function _fetchProjectInfo() {
 		$db = DB::getDB();
-		$projectIds = array_keys($this->_costs);
+		$projectIds = array();
+		$projectsFromCostIds = array_keys($this->_costs);
+		foreach ($projectsFromCostIds as $idProject) $projectIds[$idProject] = true;
+		$projectsFromPlanIds = array_keys($this->_plan);
+		foreach ($projectsFromPlanIds as $idProject) $projectIds[$idProject] = true;
+		foreach ($projectIds as $idProject => $vBool) $this->_projectInfo[$idProject] = new stdClass();
+		$projectIds = array_keys($projectIds);
 		$sqlProjIds = "'" . implode("','", $projectIds) . "'";
 		$sql = "select p.`ID`, p.`P_ID`, p.`path`, p.`M_DIST_DESC`
 			from `IN7_MK_BAZA_DYSTRYBUCJI` p
@@ -518,21 +577,24 @@ jQuery(document).ready(function() {
 		";
 		$res = $db->query($sql);
 		while ($r = $db->fetch($res)) {
-			$this->_costs[$r->ID]->path = $r->path;
-			$this->_costs[$r->ID]->M_DIST_DESC = $r->M_DIST_DESC;
+			$this->_projectInfo[$r->ID]->path = $r->path;
+			$this->_projectInfo[$r->ID]->M_DIST_DESC = $r->M_DIST_DESC;
 		}
+		$this->_projectInfo[0]->path = '0';
+		$this->_projectInfo[0]->M_DIST_DESC = "Wszystkie projekty";
 	}
 
 	private function _reacountCostsFromKoresp() {
 		$projMonthHasCostSelfIds = array();
 		foreach ($this->_costs as $kProjId => $vProjInfo) {
+			$projectPath = $this->_projectInfo[$kProjId]->path;
 			foreach ($vProjInfo->korespByMonth as $kMonthNum => $vKorespList) {
 				$this->_createCostIfNotDefined($kProjId, $kMonthNum);
 				foreach ($vKorespList as $vKoresp) {
 					$this->_costs[$kProjId]->costsByMonth[$kMonthNum]->COST_SELF += $vKoresp->COST;
 					$this->_costs[$kProjId]->costsByMonth[$kMonthNum]->INCOME_SELF += $vKoresp->INCOME;
 				}
-				$projHasCostSelfIds[$kProjId][$kMonthNum] = $vProjInfo->path;
+				$projHasCostSelfIds[$kProjId][$kMonthNum] = $projectPath;
 			}
 		}
 		//echo'<pre style="width:600px;border:1px solid red;max-height:300px;overflow:auto;">$projHasCostSelfIds: ';print_r($projHasCostSelfIds);echo'</pre>';
@@ -576,8 +638,8 @@ jQuery(document).ready(function() {
 
 	public function _buildProjectTree() {
 		$this->_projectPathsOrder = array();
-		foreach ($this->_costs as $idProject => $projectInfo) {
-			$this->_projectPathsOrder[$projectInfo->path] = $projectInfo->ID_PROJECT;
+		foreach ($this->_projectInfo as $idProject => $projectInfo) {
+			$this->_projectPathsOrder[$projectInfo->path] = $idProject;
 		}
 		//echo'<pre style="width:600px;border:1px solid red;max-height:300px;overflow:auto;">projPaths: ';print_r($this->_projectPathsOrder);echo'</pre>';
 		uksort($this->_projectPathsOrder, array($this, 'sortPathsCallback'));
@@ -601,4 +663,71 @@ jQuery(document).ready(function() {
 		return $la - $lb;
 	}
 
+	public function updatePaths() {
+		$sqlList = array();
+		$sqlList['updateAllPaths'] = <<<SQL
+update `projects_budget_year_month` b
+set path = (select coalesce(
+										(select p.`path` from `IN7_MK_BAZA_DYSTRYBUCJI` p where p.`ID`=b.`ID_PROJECT` limit 1)
+										, '?'));
+SQL;
+		$db = DB::getDB();
+		if ($db->has_errors()) {
+			throw new Exception("DB Errors: " . implode("\n<br>", $db->get_errors()));
+		}
+		foreach ($sqlList as $sqlName => $sql) {
+			$res = $db->query($sql);
+			if ($db->has_errors()) {
+				throw new Exception("DB Errors at sql '{$sqlName}': " . implode("\n<br>", $db->get_errors()));
+			}
+		}
+	}
+
+	public function reinstall() {
+		$sqlList = array();
+		$sqlList['RemoveTrigger_BudgetPlan_BeforeInsert'] = "DROP TRIGGER IF EXISTS `projects_budget_year_month_BEFORE_INSERT`";
+		$sqlList['CreateTrigger_BudgetPlan_BeforeInsert'] = "
+CREATE DEFINER=`root`@`localhost` TRIGGER `projects_budget_year_month_BEFORE_INSERT` BEFORE INSERT ON `projects_budget_year_month`
+FOR EACH ROW BEGIN
+	IF NEW.ID_PROJECT IS NOT NULL and NEW.ID_PROJECT>0 THEN
+		SET NEW.path = (select coalesce(
+			(select p.`path` from `IN7_MK_BAZA_DYSTRYBUCJI` p where p.`ID`=NEW.`ID_PROJECT` limit 1)
+			, '?'
+		));
+	END IF;
+END
+		";
+		$sqlList['RemoveTrigger_BudgetPlan_BeforeUpdate'] = "DROP TRIGGER IF EXISTS `projects_budget_year_month_BEFORE_UPDATE `";
+		// throws errors:
+		//  #1146 - Table '{DATABASE_NAME}.P5-MSG:Route_FixZasobPath:ERROR: Loop detected ID=PARENT_ID' doesn't exist
+		//  #1146 - Table '{DATABASE_NAME}.P5-MSG:Route_FixZasobPath:ERROR: Parent item not exists' doesn't exist
+		//  #1146 - Table '{DATABASE_NAME}.P5-MSG:Route_FixZasobPath:ERROR: Loop detected in path' doesn't exist
+		$sqlList['CreateTrigger_BudgetPlan_BeforeUpdate'] = "
+CREATE DEFINER=`root`@`localhost` TRIGGER `projects_budget_year_month_BEFORE_UPDATE` BEFORE UPDATE ON `projects_budget_year_month`
+FOR EACH ROW BEGIN
+	IF NEW.ID_PROJECT IS NULL THEN
+		SET NEW.path = '';
+	ELSEIF OLD.ID_PROJECT IS NULL or NEW.ID_PROJECT<>OLD.ID_PROJECT THEN
+		IF NEW.ID_PROJECT>0 THEN
+			SET NEW.path = (select coalesce(
+							(select p.`path` from `IN7_MK_BAZA_DYSTRYBUCJI` p where p.`ID`=NEW.`ID_PROJECT` limit 1)
+							, '?'));
+		ELSE
+			SET NEW.path = '';
+		END IF;
+	END IF;
+END
+		";
+		$db = DB::getDB();
+		if ($db->has_errors()) {
+			throw new Exception("DB Errors: " . implode("\n<br>", $db->get_errors()));
+		}
+		foreach ($sqlList as $sqlName => $sql) {
+			$res = $db->query($sql);
+			if ($db->has_errors()) {
+				throw new Exception("DB Errors at sql '{$sqlName}': " . implode("\n<br>", $db->get_errors()));
+			}
+		}
+	}
+
 }