ソースを参照

added Oferta Admin and by Company in Kosztorys

Piotr Labudda 9 年 前
コミット
972273bf8c

+ 57 - 12
SE/se-lib/ProjectKosztorysCennik.php

@@ -146,17 +146,40 @@ class ProjectKosztorysCennik {
     }
   }
 
-  public static function getPriceDefaultCennik($idType) {
-    $item = self::getItemDefaultCennik($idType);
+  public static function updatePriceDefaultCennik($idType, $idCompany, $price, $jednostka) {
+    $item = self::getItemDefaultCennik($idType, $idCompany, $jednostka);
+    $usrLogin = User::getLogin();
+    $sqlObj = array();
+    $sqlObj['CRM_LISTA_ZASOBOW_ID'] = $idType;
+    $sqlObj['OFFER_PRICE_PER_RESOURCE_UNIT'] = $price;
+    $sqlObj['RESOURCE_UNIT_TYPE'] = $jednostka;
+    $sqlObj['OFFER_UNIT_TYPE'] = $jednostka;
+    if (empty($item)) {
+      $sqlObj['COMPANIES_ID'] = $idCompany;
+      $sqlObj['ID_PROJECT'] = 0;
+      $sqlObj['REQUIRED_RESOURCE_UNITS'] = 0;
+      $idInserted = DB::getDB()->ADD_NEW_OBJ('CRM_LISTA_ZASOBOW_OFFERS', (object)$sqlObj);
+      if ($idInserted <= 0) throw new Exception("Nie udało się utworzyć rekordu");
+    } else {
+      $sqlObj['ID'] = $item['ID'];
+      $affected = DB::getDB()->UPDATE_OBJ('CRM_LISTA_ZASOBOW_OFFERS', (object)$sqlObj);
+      if ($affected < 0) throw new Exception("Nie udało się zaktualizować rekordu");
+    }
+  }
+
+  public static function getPriceDefaultCennik($idType, $idCompany = 0, $jednostka = 'zasob') {
+    $item = self::getItemDefaultCennik($idType, $idCompany, $jednostka);
     return (!empty($item)) ? round($item['price'], 2) : 0;
   }
-  public static function getItemDefaultCennik($idType) {
+  public static function getItemDefaultCennik($idType, $idCompany = 0, $jednostka = 'zasob') {
     $cennikRaw = self::_getPrices($idType);
     foreach ($cennikRaw as $item) {// fetch price from Oferta Admin
-      if (!$item['id_company'] && !$item['id_project']) {
-        if (empty($jednostka) || (!empty($jednostka) && $jednostka == $item['unit'])) {
-          return $item;
-        }
+      if ($item['id_project']) continue;
+      if (!empty($idCompany) && !empty($item['id_company']) && $idCompany != $item['id_company']) continue;
+      if (!empty($idCompany) && empty($item['id_company'])) continue;
+      if (empty($idCompany) && !empty($item['id_company'])) continue;
+      if (empty($jednostka) || (!empty($jednostka) && $jednostka == $item['unit'])) {
+        return $item;
       }
     }
     return null;
@@ -188,14 +211,36 @@ class ProjectKosztorysCennik {
       }
     }
     DBG::_('DBG', '>1', 'default cennik: price', $price, __CLASS__, __FUNCTION__, __LINE__);
-    foreach ($cennikRaw as $item) {// fetch price from Project Oferta
-      if ($idProject == $item['id_project'] && !$item['id_company']) {
-        if (empty($jednostka) || (!empty($jednostka) && $jednostka == $item['unit'])) {
-          $price = round($item['price'], 2);
+    if ($idCompany > 0) {// fetch price from Oferta Admin for given Company
+      foreach ($cennikRaw as $item) {
+        if (!$item['id_project'] && $idCompany == $item['id_company']) {
+          if (empty($jednostka) || (!empty($jednostka) && $jednostka == $item['unit'])) {
+            $price = round($item['price'], 2);
+          }
+        }
+      }
+      DBG::_('DBG', '>1', 'default company cennik: price', $price, __CLASS__, __FUNCTION__, __LINE__);
+    }
+    if ($idProject > 0 && $idCompany = 0) {// fetch price from Project Kosztorys
+      foreach ($cennikRaw as $item) {
+        if ($idProject == $item['id_project'] && !$item['id_company']) {
+          if (empty($jednostka) || (!empty($jednostka) && $jednostka == $item['unit'])) {
+            $price = round($item['price'], 2);
+          }
+        }
+      }
+      DBG::_('DBG', '>1', 'project cennik: price', $price, __CLASS__, __FUNCTION__, __LINE__);
+    }
+    if ($idProject > 0 && $idCompany > 0) {// fetch price from Project Oferta for given Company
+      foreach ($cennikRaw as $item) {
+        if ($idProject == $item['id_project'] && $idCompany == $item['id_company']) {
+          if (empty($jednostka) || (!empty($jednostka) && $jednostka == $item['unit'])) {
+            $price = round($item['price'], 2);
+          }
         }
       }
+      DBG::_('DBG', '>1', 'project company cennik: price', $price, __CLASS__, __FUNCTION__, __LINE__);
     }
-    DBG::_('DBG', '>1', 'project cennik: price', $price, __CLASS__, __FUNCTION__, __LINE__);
     return $price;
   }
   public static function _getPrices($idType, $idProject = 0, $idCompany = 0) {

+ 7 - 30
SE/se-lib/Route/ProjektyKosztorysBase.php

@@ -693,48 +693,25 @@ SQL_FUN;
 
 		UI::startTag('div', ['class'=>'jumbotron']);
 		UI::startTag('div', ['class'=>'container']);
-			UI::startTag('div');
 			UI::startTag('div', ['class'=>'btn-group']);
 				if ($idProject > 0) {
 					$activeRoute = V::get('_route', '', $_GET);
 					$route = 'UrlAction_ProjektyKosztorys'; UI::link('default', "Kosztorys", "index.php?_route={$route}&ID_PROJECT={$idProject}", ['className'=>['active'=>($route == $activeRoute)]]);
 					$route = 'UrlAction_ProjektyPrzedmiarKosztorys'; UI::link('default', "Przedmiar", "index.php?_route={$route}&ID_PROJECT={$idProject}&_print=1", ['className'=>['active'=>($route == $activeRoute)]]);
-					$route = 'UrlAction_ProjektyZestawienieSwMikRurKosztorys'; UI::link('default', "zestawienie (światłowód i mikrorurki)", "index.php?_route={$route}&ID_PROJECT={$idProject}&_print=1", ['className'=>['active'=>($route == $activeRoute)]]);
+					$route = 'UrlAction_ProjektyZestawienieSwMikRurKosztorys'; UI::link('default', "Zestawienie (światłowód i mikrorurki)", "index.php?_route={$route}&ID_PROJECT={$idProject}&_print=1", ['className'=>['active'=>($route == $activeRoute)]]);
 					// UI::link('warning', "oferta", "index.php?_route=UrlAction_ProjektyKosztyWstepnychRobot&ID_PROJECT={$idProject}&_task=oferta", ['target'=>'_blank']);
 					// UI::link('warning', "oferta (Admin)", "index.php?_route=UrlAction_ProjektyKosztyWstepnychRobot&ID_PROJECT={$idProject}&_task=ofertaAdmin", ['target'=>'_blank']);
 					// UI::link('warning', "oferta company", "index.php?_route=UrlAction_ProjektyKosztyWstepnychRobot&ID_PROJECT={$idProject}&_task=ofertaCompany", ['target'=>'_blank']);
 					$route = 'UrlAction_ProjektyZamowieniaKosztorys'; UI::link('default', "Zamówienia", "index.php?_route={$route}&ID_PROJECT={$idProject}", ['className'=>['active'=>($route == $activeRoute)]]);
+					$route = 'UrlAction_ProjektyOfertaKosztorys'; UI::link('default disabled', "TODO: Oferty", "index.php?_route={$route}&ID_PROJECT={$idProject}", ['className'=>['active'=>($route == $activeRoute)]]);
 				}
-				UI::link('default', "oferta domyślna (Admin)", "index.php?_route=UrlAction_ProjektyKosztyWstepnychRobot&_task=ofertaDefaultAdmin", ['target'=>'_blank']);
+				UI::link('default', "Oferta domyślna (Admin)", "index.php?_route=UrlAction_ProjektyOfertaAdminKosztorys");
 			UI::endTag('div');// .btn-group
-			UI::endTag('div');
 		UI::endTag('div');// .container
+		$this->additionalPanel($idProject, $idCompany);
 		UI::endTag('div');// .jumbotron
-?>
-		<br>
-		<?php if ('ofertaAdmin' == $task) : ?>
-			<form action="" method="get" class="form-inline">
-				<input type="hidden" name="_route" value="UrlAction_ProjektyKosztyWstepnychRobot">
-				<input type="hidden" name="_task" value="ofertaAdmin">
-				<label for="ID_PROJECT">Nr projektu:</label>
-				<input type="text" name="ID_PROJECT" value="<?php echo $idProject; ?>" class="form-control">
-				<label for="ID_COMPANY">Nr kontrahenta (0 = oferta wewnętrzna/kosztorys)</label>
-				<input type="text" name="ID_COMPANY" value="<?php echo $idCompany; ?>" class="form-control">
-				<input type="submit" value="Wybierz" class="btn btn-primary">
-			</form>
-		<?php elseif ('oferta' == $task || 'ofertaDefaultAdmin' == $task) : ?>
-			<form action="" method="get" class="form-inline">
-				<input type="hidden" name="_route" value="UrlAction_ProjektyKosztyWstepnychRobot">
-				<input type="hidden" name="_task" value="oferta">
-				<input type="hidden" name="ID_PROJECT" value="<?php echo $idProject; ?>">
-				<label for="ID_COMPANY">Nr kontrahenta</label>
-				<input type="text" name="ID_COMPANY" value="<?php echo $idCompany; ?>" class="form-control">
-				<input type="submit" value="Wybierz" class="btn btn-primary">
-			</form>
-		<?php endif; ?>
-  </div>
-</div>
-<?php
+	}
+	public function additionalPanel($idProject, $idCompany = 0) {
 	}
 
 	public function saveOffer($idProject, $idCompany, $args, $admin = false) {
@@ -1470,7 +1447,7 @@ SQL_FUN;
 		<?php if (DBG::isActive()) : ?>console.log('event p5UIBtnAjax:Kosztorys:updateProjektyOferta:ajaxLoaded price', price, 'PL', p5Utils__pricePrintPL(price));<?php endif; ?>
 		var unitType = payload.body.unitType;
 		var label = payload.body.label || '['+id+']';
-		if ('robocizna' != unitType) label += '<br><i style="color:#999">(cena domyślna: ' + p5Utils__pricePrintPL(payload.body.defaultPrice) + ')</i>';
+		label += '<br><i style="color:#999">(cena domyślna: ' + p5Utils__pricePrintPL(payload.body.defaultPrice) + ')</i>';
 		swal({
 			title: 'Cena ' + (('robocizna' == unitType) ? 'robocizny' : 'zasobu') + ' [' + id + ']:',
 			html: label,

+ 1 - 1
SE/se-lib/Route/UrlAction/ProjektyKosztorys.php

@@ -107,7 +107,7 @@ class Route_UrlAction_ProjektyKosztorys extends Route_ProjektyKosztorysBase {
 		$response['id'] = $idType;
 		$response['unitType'] = $unitType;
 		$response['label'] = ProjectKosztorysCennik::getTypeLabel($idType);
-		if ('robocizna' != $unitType) $response['defaultPrice'] = ProjectKosztorysCennik::getPriceDefaultCennik($idType);
+		$response['defaultPrice'] = ProjectKosztorysCennik::getPriceDefaultCennik($idType, 0, $jednostka);
 		$response['price'] = ProjectKosztorysCennik::getPrice($idType, $idProject, $idCompany = 0, $jednostka);
 		$response['msg'] = "";
 		$response['type'] = "success";

+ 593 - 0
SE/se-lib/Route/UrlAction/ProjektyOfertaAdminKosztorys.php

@@ -0,0 +1,593 @@
+<?php
+
+Lib::loadClass('RouteBase');
+Lib::loadClass('ProjectKosztorysSchema');
+Lib::loadClass('ProjectKosztorysModel');
+Lib::loadClass('ProjectKosztorysCennik');
+Lib::loadClass('UI');
+Lib::loadClass('Response');
+Lib::loadClass('Route_ProjektyKosztorysBase');
+
+class Route_UrlAction_ProjektyOfertaAdminKosztorys extends Route_ProjektyKosztorysBase {
+
+	public $_model = array();
+
+	public function defaultAction() {
+		// TODO: check if user is allowed to run this action
+		UI::gora();
+		if (1 != V::get('_print', '', $_GET)) UI::menu();
+		try {
+			$idProject = V::get('ID_PROJECT', 0, $_REQUEST, 'int');
+			$idCompany = V::get('ID_COMPANY', 0, $_REQUEST, 'int');
+			$this->panel($idProject, $idCompany);
+
+			if (1 != V::get('_print', '', $_GET)) {
+				UI::startContainer(['style'=>'text-align:right']);
+				UI::link('link', "<i class=\"glyphicon glyphicon-print\"></i> Drukuj", Request::getPathUri() . "index.php?_route=UrlAction_ProjektyOfertaAdminKosztorys&ID_COMPANY={$idCompany}&_print=1");
+				UI::endContainer();
+			}
+			$this->defaultOferta($idCompany);// TODO: $idCompany
+		} catch (Exception $e) {
+			UI::alert('danger', "Error #" . $e->getCode() .  "|" . $e->getLine() .  ": " . $e->getMessage());
+		}
+		UI::dol();
+	}
+
+	public function additionalPanel($idProject, $idCompany = 0) {
+		UI::startTag('div', ['class'=>'container', 'style'=>'margin-top:1em']);
+			UI::startTag('form', ['action'=>"", 'method'=>'get', 'class'=>'form-inline']);
+				UI::startTag('div', ['class'=>"form-group"]);
+					UI::emptyTag('input', ['type'=>"hidden", 'name'=>"_route", 'value'=>"UrlAction_ProjektyOfertaAdminKosztorys"]);
+					UI::tag('label', ['for'=>'ID_COMPANY', 'style'=>'margin-right:1em'], "Nr kontrahenta (0 = cennik główny)");
+					UI::emptyTag('input', ['type'=>"text", 'name'=>"ID_COMPANY", 'value'=>$idCompany, 'class'=>'form-control', 'style'=>'margin-right:1em']);// TODO: Typespecial for Companies
+					UI::emptyTag('input', ['type'=>"submit", 'value'=>"Wybierz", 'class'=>'btn btn-primary']);
+				UI::endTag('div');// .form-group
+			UI::endTag('form');
+		UI::endTag('div');// .container
+	}
+
+	public function ofertaAdminAction() {
+		// TODO: check if user is allowed to run this action
+		UI::gora();
+		UI::menu();
+		try {
+			$idProject = V::get('ID_PROJECT', 0, $_REQUEST, 'int');
+			$idCompany = V::get('ID_COMPANY', 0, $_REQUEST, 'int');
+			$admin = true;
+
+			$ofertaArgs = compact('idProject', 'idCompany', 'admin');
+			$this->panel($idProject, $idCompany);
+			if ($idProject > 0) {
+				$this->oferta($ofertaArgs);
+			} else {
+				$this->defaultOferta();
+			}
+		} catch (Exception $e) {
+			UI::alert('danger', "Error #" . $e->getCode() .  "|" . $e->getLine() .  ": " . $e->getMessage());
+		}
+		UI::dol();
+	}
+
+	public function ofertaCompanyAction() {
+		// TODO: check if user is allowed to run this action
+		UI::gora();
+		UI::menu();
+		try {
+			$idProject = V::get('ID_PROJECT', 0, $_REQUEST, 'int');
+			$idCompany = V::get('ID_COMPANY', 0, $_REQUEST, 'int');// TODO: $idCompany from ADMIN_USERS
+			$admin = false;
+			$companyAdmin = true;
+
+			$ofertaArgs = compact('idProject', 'idCompany', 'admin', 'companyAdmin');
+			$this->panel($idProject, $idCompany);
+			if ($idProject > 0) {
+				$this->oferta($ofertaArgs);
+			} else {
+				$this->defaultOferta();
+			}
+		} catch (Exception $e) {
+			UI::alert('danger', "Error #" . $e->getCode() .  "|" . $e->getLine() .  ": " . $e->getMessage());
+		}
+		UI::dol();
+	}
+
+	public function ofertaDefaultAdminAction() {
+		// TODO: check if user is allowed to run this action
+		UI::gora();
+		UI::menu();
+		try {
+			$idProject = 0;
+			$idCompany = V::get('ID_COMPANY', 0, $_REQUEST, 'int');
+			$this->panel($idProject, $idCompany);
+			$this->defaultOferta();
+		} catch (Exception $e) {
+			UI::alert('danger', "Error #" . $e->getCode() .  "|" . $e->getLine() .  ": " . $e->getMessage());
+		}
+		UI::dol();
+	}
+
+	public function ofertaAction() {
+		// TODO: check if user is allowed to run this action
+		UI::gora();
+		UI::menu();
+		try {
+			$idProject = V::get('ID_PROJECT', 0, $_REQUEST, 'int');
+			$idCompany = V::get('ID_COMPANY', 0, $_REQUEST, 'int');
+			$admin = false;
+
+			if (!$idProject) throw new Exception("Wrong param in 'ID_PROJECT' - expected integer!");// TODO: show select box if not defined
+			$ofertaArgs = compact('idProject', 'idCompany', 'admin');
+			$this->panel($idProject, $idCompany);
+			$this->oferta($ofertaArgs);
+		} catch (Exception $e) {
+			UI::alert('danger', "Error #" . $e->getCode() .  "|" . $e->getLine() .  ": " . $e->getMessage());
+		}
+		UI::dol();
+	}
+
+	public function saveOffer($idProject, $idCompany, $args, $admin = false) {
+		DBG::_('DBG', '>1', "args", $args, __CLASS__, __FUNCTION__, __LINE__);
+		if (!$admin) return;
+		$cennik = ProjectKosztorysCennik::getCennik($idProject, $idCompany);
+		DBG::_('DBG', '>1', "cennik", $cennik, __CLASS__, __FUNCTION__, __LINE__);
+		$pdo = DB::getPDO();
+		{
+			$add_id_zasob = 0;
+			$add_unit = '';
+			$add_price = 0;
+			$add_quantity = 0;
+			$add__sth = $pdo->prepare("
+				insert into CRM_LISTA_ZASOBOW_OFFERS (
+					CRM_LISTA_ZASOBOW_ID
+					, COMPANIES_ID
+					, ID_PROJECT
+					, OFFER_PRICE_PER_RESOURCE_UNIT
+					, RESOURCE_UNIT_TYPE
+					, OFFER_UNIT_TYPE
+					, REQUIRED_RESOURCE_UNITS
+					, A_RECORD_CREATE_AUTHOR
+					, A_RECORD_CREATE_DATE
+				) values (
+					:id_zasob
+					, :id_company
+					, :id_project
+					, :price
+					, :unit
+					, :unit
+					, :quantity
+					, :author
+					, NOW()
+				)
+			");
+			$add__sth->bindValue(':author', User::getLogin(), PDO::PARAM_STR);
+			$add__sth->bindValue(':id_project', $idProject, PDO::PARAM_INT);
+			$add__sth->bindValue(':id_company', $idCompany, PDO::PARAM_INT);
+			$add__sth->bindValue(':quantity', $add_quantity, PDO::PARAM_STR);
+			$add__sth->bindParam(':id_zasob', $add_id_zasob, PDO::PARAM_INT);
+			$add__sth->bindParam(':price', $add_price, PDO::PARAM_STR);
+			$add__sth->bindParam(':unit', $add_unit, PDO::PARAM_STR);
+		}
+		{
+			$edit_id_company = $idCompany;
+			$edit_id_zasob = 0;
+			$edit_unit = '';
+			$edit_price = 0;
+			$edit_author = 0;
+			$edit_quantity = 0;
+			$edit__sth = $pdo->prepare("
+				update CRM_LISTA_ZASOBOW_OFFERS
+				set CRM_LISTA_ZASOBOW_ID = :id_zasob
+					, COMPANIES_ID = :id_company
+					, ID_PROJECT = :id_project
+					, OFFER_PRICE_PER_RESOURCE_UNIT = :price
+					, RESOURCE_UNIT_TYPE = :unit
+					, OFFER_UNIT_TYPE = :unit
+					, REQUIRED_RESOURCE_UNITS = :quantity
+					, A_RECORD_UPDATE_AUTHOR = :author
+					, A_RECORD_UPDATE_DATE = NOW()
+				where ID = :id
+			");
+			$edit__sth->bindParam(':id', $edit_id, PDO::PARAM_INT);
+			$edit__sth->bindValue(':author', User::getLogin(), PDO::PARAM_STR);
+			$edit__sth->bindValue(':id_project', $idProject, PDO::PARAM_INT);
+			$edit__sth->bindValue(':id_company', $idCompany, PDO::PARAM_INT);
+			$edit__sth->bindValue(':quantity', $edit_quantity, PDO::PARAM_STR);
+			$edit__sth->bindParam(':id_zasob', $edit_id_zasob, PDO::PARAM_INT);
+			$edit__sth->bindParam(':price', $edit_price, PDO::PARAM_STR);
+			$edit__sth->bindParam(':unit', $edit_unit, PDO::PARAM_STR);
+		}
+		$schema = ProjectKosztorysSchema::getSchema();
+		foreach ($schema['config']['layer'] as $idLayer => $layData) {
+			DBG::_('DBG', '>1', "layData", $layData, __CLASS__, __FUNCTION__, __LINE__);
+			foreach ($layData['type'] as $idType => $typeLabel) {
+				$edit_id = V::get("edit_price_id_{$idType}", '', $args);
+				$add_price = V::get("price_{$idType}", '', $args);
+				DBG::_('DBG', '>1', "typeLabel (edit={$edit_id}, price={$add_price})", $typeLabel, __CLASS__, __FUNCTION__, __LINE__);
+				if ($edit_id > 0) {
+					$edit_price = V::get("price_{$idType}", '', $args);
+					$edit_price = str_replace(',', '.', $edit_price);
+					if ($edit_id > 0 && $edit_price > 0) {
+						$edit_id_zasob = $idType;
+						$edit_unit = $layData['jednostka'];
+						// TODO: check if anything change
+						DBG::_('DBG', '>1', "EDIT price for idZasob({$idType}) {price:{$edit_price}, id_offer:{$edit_id}}", $typeLabel, __CLASS__, __FUNCTION__, __LINE__);
+						$edit__sth->execute();
+						// TODO: add to hist
+					}
+				} else {
+					$add_price = V::get("price_{$idType}", '', $args);
+					$add_price = str_replace(',', '.', $add_price);
+					if ($add_price > 0) {
+						$add_id_zasob = $idType;
+						$add_unit = $layData['jednostka'];
+						DBG::_('DBG', '>1', "ADD price for idZasob({$idType}) {price:{$add_price}}", $typeLabel, __CLASS__, __FUNCTION__, __LINE__);
+						$add__sth->execute();
+					}
+				}
+			}
+		}
+	}
+	public function saveDefaultOffer($args) {
+		DBG::_('DBG', '>1', "args", $args, __CLASS__, __FUNCTION__, __LINE__);
+		$cennik = ProjectKosztorysCennik::getDefaultCennik();
+		DBG::_('DBG', '>1', "cennik", $cennik, __CLASS__, __FUNCTION__, __LINE__);
+		$idCompany = 0;
+		$idProject = 0;
+		$pdo = DB::getPDO();
+		{
+			$add_id_zasob = 0;
+			$add_unit = '';
+			$add_price = 0;
+			$add_quantity = 0;
+			$add__sth = $pdo->prepare("
+				insert into CRM_LISTA_ZASOBOW_OFFERS (
+					CRM_LISTA_ZASOBOW_ID
+					, COMPANIES_ID
+					, ID_PROJECT
+					, OFFER_PRICE_PER_RESOURCE_UNIT
+					, RESOURCE_UNIT_TYPE
+					, OFFER_UNIT_TYPE
+					, REQUIRED_RESOURCE_UNITS
+					, A_RECORD_CREATE_AUTHOR
+					, A_RECORD_CREATE_DATE
+				) values (
+					:id_zasob
+					, :id_company
+					, :id_project
+					, :price
+					, :unit
+					, :unit
+					, :quantity
+					, :author
+					, NOW()
+				)
+			");
+			$add__sth->bindValue(':author', User::getLogin(), PDO::PARAM_STR);
+			$add__sth->bindValue(':id_project', $idProject, PDO::PARAM_INT);
+			$add__sth->bindValue(':id_company', $idCompany, PDO::PARAM_INT);
+			$add__sth->bindValue(':quantity', $add_quantity, PDO::PARAM_STR);
+			$add__sth->bindParam(':id_zasob', $add_id_zasob, PDO::PARAM_INT);
+			$add__sth->bindParam(':price', $add_price, PDO::PARAM_STR);
+			$add__sth->bindParam(':unit', $add_unit, PDO::PARAM_STR);
+		}
+		{
+			$edit_id_zasob = 0;
+			$edit_unit = '';
+			$edit_price = 0;
+			$edit_author = 0;
+			$edit_quantity = 0;
+			$edit__sth = $pdo->prepare("
+				update CRM_LISTA_ZASOBOW_OFFERS
+				set CRM_LISTA_ZASOBOW_ID = :id_zasob
+					, COMPANIES_ID = :id_company
+					, ID_PROJECT = :id_project
+					, OFFER_PRICE_PER_RESOURCE_UNIT = :price
+					, RESOURCE_UNIT_TYPE = :unit
+					, OFFER_UNIT_TYPE = :unit
+					, REQUIRED_RESOURCE_UNITS = :quantity
+					, A_RECORD_UPDATE_AUTHOR = :author
+					, A_RECORD_UPDATE_DATE = NOW()
+				where ID = :id
+			");
+			$edit__sth->bindParam(':id', $edit_id, PDO::PARAM_INT);
+			$edit__sth->bindValue(':author', User::getLogin(), PDO::PARAM_STR);
+			$edit__sth->bindValue(':id_project', $idProject, PDO::PARAM_INT);
+			$edit__sth->bindValue(':id_company', $idCompany, PDO::PARAM_INT);
+			$edit__sth->bindValue(':quantity', $edit_quantity, PDO::PARAM_STR);
+			$edit__sth->bindParam(':id_zasob', $edit_id_zasob, PDO::PARAM_INT);
+			$edit__sth->bindParam(':price', $edit_price, PDO::PARAM_STR);
+			$edit__sth->bindParam(':unit', $edit_unit, PDO::PARAM_STR);
+		}
+		$schema = ProjectKosztorysSchema::getSchema();
+		foreach ($schema['config']['layer'] as $idLayer => $layData) {
+			DBG::_('DBG', '>1', "layData", $layData, __CLASS__, __FUNCTION__, __LINE__);
+			foreach ($layData['type'] as $idType => $typeLabel) {
+				DBG::_('DBG', '>1', "typeLabel", $typeLabel, __CLASS__, __FUNCTION__, __LINE__);
+				$edit_id = V::get("edit_price_id_{$idType}", '', $args);
+				if ($edit_id > 0) {
+					$edit_price = V::get("price_{$idType}", '', $args);
+					$edit_price = str_replace(',', '.', $edit_price);
+					if ($edit_id > 0 && $edit_price > 0) {
+						$edit_id_zasob = $idType;
+						$edit_unit = $layData['jednostka'];
+						// TODO: check if anything change
+						$edit__sth->execute();
+						// TODO: add to hist
+					}
+				} else {
+					$add_price = V::get("price_{$idType}", '', $args);
+					$add_price = str_replace(',', '.', $add_price);
+					if ($add_price > 0) {
+						$add_id_zasob = $idType;
+						$add_unit = $layData['jednostka'];
+						$add__sth->execute();
+					}
+				}
+			}
+		}
+	}
+
+	public function defaultOferta($idCompany = 0) {
+		$priceEditJs = (1 != V::get('_print', '', $_GET)) ? Request::getPathUri() . "index.php?_route=UrlAction_ProjektyOfertaAdminKosztorys&_task=updateAdminOfertaAjax&idCompany={$idCompany}" : false;
+		$schema = ProjectKosztorysSchema::getSchema();
+		if (empty($schema['config']['type'])) throw new Exception("Schema error - brak zdefiniowanych typów");
+		$defCennik = ProjectKosztorysCennik::getDefaultCennik();
+		$cennik = ProjectKosztorysCennik::getDefaultCennik($idCompany);
+		$workCennik = ProjectKosztorysCennik::getWorkCennik($idProject = 0, $idCompany);
+		DBG::_('DBG', '>1', "defCennik", $defCennik, __CLASS__, __FUNCTION__, __LINE__);
+		DBG::_('DBG', '>1', "cennik", $cennik, __CLASS__, __FUNCTION__, __LINE__);
+		DBG::_('DBG', '>1', "workCennik", $workCennik, __CLASS__, __FUNCTION__, __LINE__);
+		$title = "Cennik domyślny " . ($idCompany ? "firmy [{$idCompany}]" : '') . " dla Kosztorysów";
+		UI::setTitleJsTag($title);
+		?>
+<div class="container">
+	<h1><?= $title; ?></h1>
+	<table class="tabel table-bordered table-hover" style="width:100%; margin-bottom:6px; page-break-inside:avoid">
+	<tbody>
+		<?php foreach ($schema['config']['layer'] as $idLayer => $layData) : ?>
+			<tr>
+				<td colspan="5" style="padding:0 6px; font-size:1.2em; line-height:2em"> &mdash; <?php echo $layData['label']; ?></td>
+			</tr>
+			<tr>
+				<td style="color:#888; padding:0 6px">id zasobu</td>
+				<td style="color:#888; padding:0 6px">typ</td>
+				<td style="color:#888; padding:0 6px">jednostka miary</td>
+				<td style="color:#888; padding:0 6px; text-align:right">cena jednostkowa
+					<?php if ($priceEditJs && $idCompany > 0) : ?>
+						<button type="button"
+										class="btn btn-xs btn-link"
+										data-toggle="popover"
+										data-trigger="hover"
+										title="Cena jednostkowa"
+										data-content="Cena na czerwono oznacza cenę z cennika głównego, cena na zielono to cena wg oferty danej firmy"><i class="glyphicon glyphicon-question-sign"></i></button>
+					<?php endif; ?>
+				</td>
+				<td style="color:#888; padding:0 6px; text-align:right">cena jedn. (robocizna)</td>
+			</tr>
+			<?php foreach ($layData['type'] as $idType => $typeLabel) : ?>
+				<?php $defPrice = (!empty($defCennik[$idType]['price']))? $defCennik[$idType]['price'] : 0; ?>
+				<?php $price = (!empty($cennik[$idType]) && array_key_exists('price', $cennik[$idType]))? $cennik[$idType]['price'] : $defPrice; ?>
+				<?php
+					$typePrice = 'UNDEFINED';
+					if (!empty($defCennik[$idType]['price'])) $typePrice = 'GLOBAL';
+					if (!empty($cennik[$idType]) && array_key_exists('price', $cennik[$idType])) $typePrice = 'PROJECT';
+				?>
+				<?php $workPrice = (!empty($workCennik[$idType]['price']))? $workCennik[$idType]['price'] : 0; ?>
+				<tr>
+					<td style="width:100px; padding:0 6px"><?php echo $idType; ?></td>
+					<td style="padding:0 6px" title="[<?php echo $idType; ?>] <?php echo $typeLabel; ?>"><?php echo $typeLabel; ?></td>
+					<td style="padding:0 6px"><?php echo $layData['jednostka']; ?></td>
+<!--
+					<td style="padding:3px 6px"><input type="text" class="form-control input-sm" name="price_<?php echo $idType; ?>" value="<?php echo $cennik[$idType]['price']; ?>"/></td>
+ -->
+					 <td
+						 <?php if ($priceEditJs) : ?>
+							 onClick="return p5UI__ButtonAjax(this, 'p5UIBtnAjax:Kosztorys:updateAdminOferta', { href: '<?= "{$priceEditJs}&idType={$idType}&unitType=zasob"; ?>' })"
+						 <?php endif; ?>
+						 class="type_price-<?= $typePrice; ?>"
+						 style="padding:3px 6px; text-align:right">
+						 <?= number_format($price, 2, ',', ' '); ?>
+					</td>
+					 <td
+						 <?php if ($priceEditJs) : ?>
+							 onClick="return p5UI__ButtonAjax(this, 'p5UIBtnAjax:Kosztorys:updateAdminOferta', { href: '<?= "{$priceEditJs}&idType={$idType}&unitType=robocizna"; ?>' })"
+						 <?php endif; ?>
+						 style="padding:3px 6px; text-align:right">
+						 <?= number_format($workPrice, 2, ',', ' '); ?>
+					</td>
+				</tr>
+			<?php endforeach; ?>
+		<?php endforeach; ?>
+	</tbody>
+	</table>
+</div>
+<style type="text/css">
+.type_price-UNDEFINED { color:silver }
+.type_price-UNDEFINED input { color:silver }
+.type_price-GLOBAL { color:red }
+.type_price-GLOBAL input { color:red }
+.type_price-PROJECT { color:green }
+.type_price-PROJECT input { color:green }
+
+/* Print Styles */
+@media print {
+	body { font-size:10px; }
+	th, td { font-size:10px; }
+	h1 { font-size:2em; }
+	h2 { font-size:1.6em; }
+	h3 { font-size:1.4em; }
+	h4 { font-size:1.2em; }
+}
+</style>
+<link rel="stylesheet" type="text/css" href="static/sweetalert2.min.css">
+<script src="static/sweetalert2.min.js"></script>
+<?php if ($priceEditJs) : ?>
+<script>
+(function(){
+var _updateAdminOfertaSaveLink = '<?= $priceEditJs ?>';
+
+jQuery(document).on('p5UIBtnAjax:Kosztorys:updateAdminOferta:click', function(e, n, payload) {
+	<?php if (DBG::isActive()) : ?>console.log('event p5UIBtnAjax:Kosztorys:updateAdminOferta:click', n, payload);<?php endif; ?>
+});
+
+jQuery(document).on('p5UIBtnAjax:Kosztorys:updateAdminOferta:ajaxLoaded', function(e, n, payload) {
+	<?php if (DBG::isActive()) : ?>console.log('event p5UIBtnAjax:Kosztorys:updateAdminOferta:ajaxLoaded', n, payload);<?php endif; ?>
+	if ('success' != payload.type) {
+		jQuery.notify(payload.msg, payload.type);
+		return;
+	}
+	if (payload.body && payload.body.id > 0) {
+		jQuery(n).text(p5Utils__pricePrintPL(payload.body.price));
+	}
+	var id = payload.body.id;
+	var price = payload.body.price;
+	<?php if (DBG::isActive()) : ?>console.log('event p5UIBtnAjax:Kosztorys:updateAdminOferta:ajaxLoaded price', price, 'PL', p5Utils__pricePrintPL(price));<?php endif; ?>
+	var unitType = payload.body.unitType;
+	var label = payload.body.label || '['+id+']';
+	label += '<br><i style="color:#999">(cena domyślna: ' + p5Utils__pricePrintPL(payload.body.defaultPrice) + ')</i>';
+	swal({
+		title: 'Cena ' + (('robocizna' == unitType) ? 'robocizny' : 'zasobu') + ' [' + id + ']:',
+		html: label,
+		animation: false,
+		input: 'text',
+		inputPlaceholder: '0,00',
+		inputValue: (0 === price) ? price : p5Utils__pricePrintPL(price),
+		showCancelButton: true,
+		confirmButtonText: 'Zapisz',
+		showLoaderOnConfirm: true,
+		preConfirm: Kosztorys__saveFormUpdateAdminOferta(id, unitType),
+		allowOutsideClick: false
+	}).then(function(responseBody) {
+		<?php if (DBG::isActive()) : ?>console.log('event p5UIBtnAjax:Kosztorys:savedFormUpdateProjectOferta:ajaxLoaded', responseBody);<?php endif; ?>
+		if ('success' != responseBody.type) {
+			jQuery.notify(responseBody.msg || 'Wystąpiły błędy podczas aktualizacji ceny dla ['+id+']', 'error')
+			return;
+		}
+		jQuery.notify(responseBody.msg || 'Zaktualizowano cenę za ['+id+']', 'success')
+		jQuery.notify('Odśwież stronę żeby zobaczyć zmiany', 'info')
+		jQuery(n).removeClass('type_price-UNDEFINED')
+		jQuery(n).removeClass('type_price-GLOBAL')
+		jQuery(n).addClass('type_price-PROJECT')
+		jQuery(n).text(p5Utils__pricePrintPL(responseBody.price))
+		// TODO: update dom price
+		// if (responseBody.update_data) {
+		// 	budget__renderCosts(responseBody.update_data['costs']);
+		// }
+	}).catch(function(e) {// eg. hit Cancel
+	})
+});
+
+function Kosztorys__saveFormUpdateAdminOferta(idType, type) {
+	var idType = idType, type = type;// TODO: zasob / robocizna
+	return function(price) {
+		return new Promise(function(resolve, reject) {
+			price = p5Utils__parseFloatOrZero(price)
+			if (price < 0) {
+				reject('Kwota musi być nie mniejsza od zera.')
+			} else {
+				superagent
+					.post(_updateAdminOfertaSaveLink + '&idType=' + idType + '&unitType=' + type)
+					.type('json') // header ĺapplication/x-www-form-urlencoded' requires type('form');
+					.send({
+						price: price
+					})
+					.set('Accept', 'application/json')
+					.end(function(err, res) {
+						<?php if (DBG::isActive()) : ?>console.log('#widget::Kosztorys/saveFormUpdateProjectOferta: res:', res, 'res.body:', res.body);<?php endif; ?>
+						if (err || !res.ok || 'application/json' !== res.type) reject("Request error")
+						if (!res.body.id || res.body.id <= 0) reject(res.body.msg || "Wystąpiły błędy podczas dodawaniu kosztu")
+						resolve(res.body)
+					})
+			}
+		})
+	}
+}
+
+$(function () {
+	$('[data-toggle="popover"]').popover()
+})
+
+})();
+</script>
+<?php endif; ?>
+<?php
+	}
+
+	public function updateAdminOfertaAjaxAction() {
+		$args = array();
+		$args['idCompany'] = V::get('idCompany', 0, $_GET, 'int');
+		$args['idType'] = V::get('idType', 0, $_GET, 'int');
+		$args['unitType'] = V::get('unitType', '', $_GET, 'word');
+		Response::sendTryCatchJson(array($this, 'updateAdminOfertaAjax'), $args);
+	}
+	public function updateAdminOfertaAjax($args) {
+		$idCompany = V::get('idCompany', 0, $args, 'int');
+		$idType = V::get('idType', 0, $args, 'int');
+		$unitType = V::get('unitType', '', $args, 'word');
+		if ($idCompany < 0) throw new Exception("Wrong param idCompany");// $idCompany may be equal 0
+		if (empty($idType) || $idType <= 0) throw new Exception("Wrong param idType");
+		if (empty($unitType) || !in_array($unitType, array('zasob', 'robocizna'))) throw new Exception("Wrong param unitType");
+		$response = array();
+		if (DBG::isActive()) $response['_idProject'] = $idCompany;
+		if (DBG::isActive()) $response['_idType'] = $idType;
+		$jednostka = '';
+		if ('robocizna' == $unitType) $jednostka = 'ROBOCIZNA';
+		else if ('zasob' == $unitType) {
+			$schema = ProjectKosztorysSchema::getSchema();
+			foreach ($schema['config']['layer'] as $idLayer => $layData) {
+				if (array_key_exists($idType, $layData['type'])) $jednostka = $layData['jednostka'];
+			}
+		}
+		if (DBG::isActive()) $response['_unit'] = $jednostka;
+
+		$reqJson = Request::getRequestJson();
+		if (!empty($reqJson)) {
+			if (!array_key_exists('price', $reqJson)) throw new Exception("Missing param price");
+			$price = V::get('price', 0, $reqJson, 'float');
+			ProjectKosztorysCennik::updatePriceDefaultCennik($idType, $idCompany, $price, $jednostka);
+		}
+		$response['id'] = $idType;
+		$response['unitType'] = $unitType;
+		$response['label'] = ProjectKosztorysCennik::getTypeLabel($idType);
+		$response['defaultPrice'] = ProjectKosztorysCennik::getPriceDefaultCennik($idType, 0, $jednostka);
+		$response['price'] = ProjectKosztorysCennik::getPrice($idType, $idProject = 0, $idCompany, $jednostka);
+		$response['msg'] = "";
+		$response['type'] = "success";
+		return $response;
+	}
+
+
+
+	public function oferta($args) {
+		$idProject = $args['idProject'];
+		$idCompany = V::get('idCompany', 0, $args);
+		$admin = V::get('admin', false, $args);
+		$companyAdmin = V::get('companyAdmin', false, $args);
+
+		if ($admin && '1' == V::get('save_offer', '', $_POST)) {
+			$this->saveOffer($idProject, $idCompany, $_POST, $admin);
+		}
+		$defCennik = ProjectKosztorysCennik::getDefaultCennik($idCompany);
+		$cennik = ProjectKosztorysCennik::getCennik($idProject, $idCompany);
+
+		$viewLayerDataArgs = compact('idProject', 'idCompany', 'admin', 'companyAdmin');
+		UI::setTitleJsTag("Oferta " . (($idProject)? " [{$idProject}] " : '') . (($idCompany)? " Kontrahent({$idCompany})" : '') . " - Kosztorysy");
+		?>
+<div class="container">
+	<?php if ($admin) : ?>
+		<form action="" method="post">
+	<?php endif; ?>
+	<?php $this->viewLayersData($viewLayerDataArgs); ?>
+	<?php if ($admin || $companyAdmin) : ?>
+		<?php foreach ($cennik as $item) : ?>
+			<input type="hidden" name="edit_price_id_<?php echo $item['id_zasob']; ?>" value="<?php echo $item['ID']; ?>">
+		<?php endforeach; ?>
+			<input type="hidden" name="save_offer" value="1">
+			<hr><input class="btn btn-primary" type="submit" value="Zapisz ofertę">
+		</form>
+	<?php endif; ?>
+</div>
+<?php
+	}
+
+}

+ 7 - 0
SE/se-lib/UI.php

@@ -191,6 +191,13 @@ class UI {
 		if (is_scalar($childrens)) echo $childrens;
 		self::endTag($tag);
 	}
+	public static function emptyTag($tag, $attrs = array()) {
+		$outAttrs = '';
+		if (is_array($attrs)) {
+			foreach ($attrs as $attrName => $val) $outAttrs .= " {$attrName}=\"{$val}\"";
+		}
+		echo '<' . $tag . $outAttrs . '/>';
+	}
 	public static function link($type, $content, $href, $attrs = array()) {
 		$attrs['class'] = V::get('class', '', $attrs);
 		$attrs['class'] .= "btn btn-{$type}";