PageRenderTime 27ms CodeModel.GetById 33ms RepoModel.GetById 1ms app.codeStats 0ms

/sens2/Indicators.class.php

https://github.com/bgerp/bgerp
PHP | 440 lines | 239 code | 102 blank | 99 comment | 49 complexity | 32d24257d4f178f923feca17ae5413d1 MD5 | raw file
  1. <?php
  2. /**
  3. * Регистър - описание на всички входове и изходи на контролерите
  4. * Съдържа и текущите им стойности, време за измерване/установяване и евентуално грешки
  5. *
  6. * @category bgerp
  7. * @package sens2
  8. *
  9. * @author Milen Georgiev <milen@download.bg>
  10. * @copyright 2006 - 2014 Experta OOD
  11. * @license GPL 3
  12. *
  13. * @since v 0.1
  14. */
  15. class sens2_Indicators extends core_Detail
  16. {
  17. /**
  18. * Масив в който се намират всички текущи стойности на индикаторите
  19. */
  20. public static $contex;
  21. /**
  22. * Масив с всички задаедени изходи
  23. */
  24. public static $outputs;
  25. /**
  26. * Необходими мениджъри
  27. */
  28. public $loadList = 'plg_RowTools2, sens2_Wrapper, plg_AlignDecimals, plg_RefreshRows, plg_Rejected, plg_State2,plg_Sorting';
  29. /**
  30. * Заглавие
  31. */
  32. public $title = 'Текущи стойности на индикаторите';
  33. /**
  34. * Заглавие ед. ч.
  35. */
  36. public $singleTitle = 'Индикатор';
  37. /**
  38. * На колко време ще се актуализира листа
  39. */
  40. public $refreshRowsTime = 25000;
  41. /**
  42. * Права за писане
  43. */
  44. public $canWrite = 'debug';
  45. /**
  46. * Права за писане
  47. */
  48. public $canEdit = 'debug';
  49. /**
  50. * Права за запис
  51. */
  52. public $canRead = 'ceo, sens, admin';
  53. /**
  54. * Кой може да го разглежда?
  55. */
  56. public $canList = 'ceo, admin, sens';
  57. /**
  58. * Кой може да разглежда сингъла на документите?
  59. */
  60. public $canSingle = 'ceo, admin, sens';
  61. public $canDelete = 'no_one';
  62. /**
  63. * Кой може да променя състоянието на Условията на доставка
  64. */
  65. public $canChangestate = 'sens,admin';
  66. public $masterKey = 'controllerId';
  67. public $listFields = 'title,value,controllerId,error,lastValue,state';
  68. /**
  69. * Описание на модела
  70. */
  71. public function description()
  72. {
  73. $this->FLD('controllerId', 'key(mvc=sens2_Controllers, select=name, allowEmpty)', 'caption=Контролер, mandatory, silent,refreshForm');
  74. $this->FLD('port', 'varchar(64)', 'caption=Порт, mandatory');
  75. $this->FLD('name', 'varchar(64)', 'caption=Наименование,column=none');
  76. $this->FLD('value', 'double(minDecimals=0, maxDecimals=4, smartRound)', 'caption=Стойност,smartCenter,input=none');
  77. $this->FLD('lastValue', 'datetime', 'caption=Към момент,oldFieldName=time,input=none');
  78. $this->FLD('lastUpdate', 'datetime', 'caption=Обновяване,column=none,input=none');
  79. $this->FLD('error', 'varchar(128)', 'caption=Грешки,input=none');
  80. $this->FLD('state', 'enum(active=Активен, rejected=Оттеглен)', 'caption=Състояние,input=none,notNull,value=active');
  81. $this->FLD('uom', 'varchar(16)', 'caption=Мярка,column=none');
  82. $this->FNC('title', 'varchar(64)', 'caption=Заглавие,column=none');
  83. $this->FNC('isOutput', 'enum(yes,no)', 'caption=Изход ли е?,column=none');
  84. $this->setDbUnique('controllerId,port,uom');
  85. $this->setDbUnique('name');
  86. }
  87. /**
  88. *
  89. * @param array $idArr
  90. *
  91. * @return string|core_ET
  92. */
  93. public static function renderIndicator($idArr)
  94. {
  95. $res = '';
  96. if (!$idArr) {
  97. return $res;
  98. }
  99. $rowsArr = array();
  100. foreach ($idArr as $id) {
  101. $rec = self::fetch($id);
  102. if (!$rec) {
  103. continue ;
  104. }
  105. $row = self::recToVerbal($rec);
  106. $row->valAndUom = $row->value . "<span class='measure'>" . $row->uom . '</span>';
  107. $rowsArr[] = $row;
  108. }
  109. $table = cls::get('core_TableView', array('mvc' => get_called_class()));
  110. $res = $table->get($rowsArr, array('title' => 'Индикатор', 'valAndUom' => 'Стойност', 'error' => 'Грешки', 'lastValue' => 'Към момент'));
  111. return $res;
  112. }
  113. /**
  114. * Извиква се след въвеждането на данните от Request във формата ($form->rec)
  115. */
  116. protected static function on_AfterInputEditForm($mvc, &$form)
  117. {
  118. if ($form->isSubmitted()) {
  119. $form->rec->name = str_replace(' ', '_', $form->rec->name);
  120. if (strlen($form->rec->name) && !preg_match('/^[\\p{L}0-9_]+$/u', $form->rec->name)) {
  121. $form->setError('name', 'Наименованието трябва да съдържа само букви, цифри и символа `_`');
  122. }
  123. }
  124. }
  125. /**
  126. * Изпълнява се при подготовката на формата
  127. */
  128. public static function on_AfterPrepareEditForm($mvc, &$res, $data)
  129. {
  130. $form = $data->form;
  131. $rec = $form->rec;
  132. if ($rec->id) {
  133. $form->setField('controllerId', 'input');
  134. $form->setReadOnly('controllerId');
  135. $form->setReadOnly('port');
  136. }
  137. if ($rec->controllerId && !$rec->port) {
  138. $ap = sens2_Controllers::getActivePorts($rec->controllerId);
  139. foreach ($ap as $port => $pRec) {
  140. if (!self::fetch(array("#controllerId = {$rec->controllerId} AND #port = '[#1#]'", $port)) || $port == $rec->port) {
  141. $opt[$port] = $pRec->caption;
  142. }
  143. }
  144. $form->setOptions('port', $opt);
  145. }
  146. }
  147. /**
  148. * Дали порта е изходящ
  149. */
  150. public static function on_CalcIsOutput($mvc, $rec, $escape = true)
  151. {
  152. static $outputs;
  153. if (!$outputs[$rec->controllerId]) {
  154. $drv = sens2_Controllers::getDriver($rec->controllerId);
  155. $outputs[$rec->controllerId] = $drv->getOutputPorts();
  156. }
  157. if ($outputs[$rec->controllerId][$rec->port]) {
  158. $rec->isOutput = 'yes';
  159. } else {
  160. $rec->isOutput = 'no';
  161. }
  162. }
  163. /**
  164. * Изчислява стойността на функционалното поле 'title'
  165. */
  166. public function on_CalcTitle($mvc, $rec)
  167. {
  168. $rec->title = $mvc->getRecTitle($rec);
  169. }
  170. public static function getContex()
  171. {
  172. if (!self::$contex) {
  173. $query = self::getQuery();
  174. while ($iRec = $query->fetch()) {
  175. self::$contex['$' . $iRec->title] = (double) $iRec->value;
  176. $controller = self::getVerbal($iRec, 'controllerId');
  177. self::$contex['$' . $controller . '.' . $iRec->port] = (double) $iRec->value;
  178. }
  179. }
  180. return self::$contex;
  181. }
  182. /**
  183. * Записва текущи данни за вход или изход
  184. * Ако липсва запис за входа/изхода - създава го
  185. */
  186. public static function setValue($controllerId, $port, $value, $time)
  187. {
  188. $ap = sens2_Controllers::getActivePorts($controllerId);
  189. $uom = $ap[$port]->uom;
  190. $query = self::getQuery();
  191. while ($r = $query->fetch(array("#controllerId = {$controllerId} AND #port = '[#1#]'", $port))) {
  192. if ($r->uom != $uom) {
  193. if ($r->state != 'rejected') {
  194. self::reject($r->id);
  195. }
  196. } else {
  197. $rec = $r;
  198. }
  199. }
  200. if (!$rec) {
  201. $rec = new stdClass();
  202. } else {
  203. // Ако имаме повторение на последните данни - не правим запис
  204. if (($rec->value == $value && $rec->lastValue == $time) || ($rec->lastValue > $time)) {
  205. return;
  206. }
  207. }
  208. $rec->controllerId = $controllerId;
  209. $rec->port = $port;
  210. $rec->value = $value;
  211. $rec->uom = $uom;
  212. $rec->lastValue = $time;
  213. $rec->lastUpdate = $time;
  214. $rec->state = 'active';
  215. // Ако имаме грешка, поставяме я в правилното място
  216. $value = trim($value);
  217. if ($value === '') {
  218. $value = 'Празна стойност';
  219. }
  220. if (!is_numeric($value)) {
  221. unset($rec->value, $rec->lastValue);
  222. $rec->error = $value;
  223. } else {
  224. $rec->error = '';
  225. }
  226. self::save($rec);
  227. if (!$rec->error) {
  228. // Записваме и в контекста, ако има такъв
  229. if (self::$contex) {
  230. $title = self::getRecTitle($rec);
  231. self::$contex['$' . $title] = $value;
  232. }
  233. return $rec->id;
  234. }
  235. }
  236. /**
  237. * Връща заглавието на дадения запис (името на порта)
  238. */
  239. public static function getRecTitle($rec, $escape = true)
  240. {
  241. if ($rec->name) {
  242. $title = $rec->name;
  243. if ($escape) {
  244. $res = type_Varchar::escape($title);
  245. }
  246. return $title;
  247. }
  248. $cRec = sens2_Controllers::fetch($rec->controllerId);
  249. $title = sens2_Controllers::getVerbal($cRec, 'name') . '.';
  250. $nameVar = $rec->port . '_name';
  251. if ($cRec->config->{$nameVar}) {
  252. $title .= $cRec->config->{$nameVar};
  253. } else {
  254. $title .= $rec->port;
  255. }
  256. if ($escape) {
  257. $title = type_Varchar::escape($title);
  258. }
  259. return $title;
  260. }
  261. /**
  262. * Филтър на on_AfterPrepareListFilter()
  263. * Малко манипулации след подготвянето на формата за филтриране
  264. *
  265. * @param core_Mvc $mvc
  266. * @param stdClass $data
  267. */
  268. public static function on_BeforePrepareListRecs($mvc, &$res, $data)
  269. {
  270. $data->query->EXT('ctrState', 'sens2_Controllers', 'externalName=state,externalKey=controllerId');
  271. $data->query->where("#ctrState = 'active'");
  272. $data->query->orderBy('#controllerId,#port', 'DESC');
  273. }
  274. /**
  275. * Изпълнява се след подготовката на редовете на листовия изглед
  276. */
  277. public static function on_AfterPrepareListRows($mvc, &$res, $data)
  278. {
  279. if (is_array($data->rows)) {
  280. foreach ($data->rows as $id => &$row) {
  281. if (strlen($data->recs[$id]->value)) {
  282. $row->value .= "<span class='measure'>" . self::getVerbal($data->recs[$id], 'uom') . '</span>';
  283. }
  284. }
  285. }
  286. }
  287. /**
  288. * Добавяме означението за съответната мерна величина
  289. *
  290. * @param core_Mvc $mvc
  291. * @param stdClass $row
  292. * @param stdClass $rec
  293. */
  294. public static function on_AfterRecToVerbal($mvc, $row, $rec)
  295. {
  296. static $configs = array();
  297. static $params = array();
  298. if ($rec->lastValue) {
  299. $color = dt::getColorByTime($rec->lastValue);
  300. $row->lastValue = ht::createElement('span', array('style' => "color:#{$color}"), $row->lastValue);
  301. }
  302. if ($rec->error && $rec->lastUpdate) {
  303. $color = dt::getColorByTime($rec->lastUpdate);
  304. $row->error = ht::createElement('span', array('style' => "font-size:0.8em;color:#{$color}"), $row->error);
  305. }
  306. // Определяне на вербалното име на порта
  307. if (!$configs[$rec->controllerId]) {
  308. $configs[$rec->controllerId] = sens2_Controllers::fetchField($rec->controllerId, 'config');
  309. }
  310. if (!$params[$rec->controllerId]) {
  311. $driver = sens2_Controllers::getDriver($rec->controllerId);
  312. $ctrRec = sens2_Controllers::fetch($rec->controllerId);
  313. $params[$rec->controllerId] = arr::combine($driver->getInputPorts($ctrRec->config), $driver->getOutputPorts($ctrRec->config));
  314. }
  315. $var = $rec->port . '_name';
  316. if ($configs[$rec->controllerId]->{$var}) {
  317. $row->port = type_Varchar::escape($rec->port . ' (' . $configs[$rec->controllerId]->{$var} . ')');
  318. } elseif (!empty($params[$rec->controllerId][$rec->port]->caption)) {
  319. $row->port = $rec->port . ' (' . type_Varchar::escape($params[$rec->controllerId][$rec->port]->caption . ')');
  320. } else {
  321. $row->port = $rec->port;
  322. }
  323. // Може ли потребителя да вижда хронологията на сметката
  324. $attr = array('title' => 'Хронологични записи');
  325. $attr = ht::addBackgroundIcon($attr, 'img/16/clock_history.png');
  326. core_RowToolbar::createIfNotExists($row->_rowTools);
  327. $ddTools = &$row->_rowTools;
  328. $url = array('sens2_DataLogs', 'List', 'indicatorId' => $rec->id);
  329. $ddTools->addLink('Записи', $url, 'ef_icon=img/16/clock_history.png,title=Хронологични записи');
  330. $row->controllerId = sens2_Controllers::getLinkToSingle($rec->controllerId, 'name');
  331. if ($rec->isOutput == 'no') {
  332. $icon = 'property.png';
  333. } else {
  334. $icon = 'hand-point.png';
  335. }
  336. $row->title = ht::createLink($row->title, $url, null, "ef_icon=img/16/{$icon}");
  337. }
  338. }