api.taskflow.php 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604
  1. <?php
  2. /**
  3. * Extended tasks processing implementation based on task states
  4. */
  5. class TaskFlow {
  6. /**
  7. * Contains system alter config as key=>value
  8. *
  9. * @var array
  10. */
  11. protected $altCfg = array();
  12. /**
  13. * Contains array of all active employee from directory as id=>name
  14. *
  15. * @var array
  16. */
  17. protected $allActiveEmployee = array();
  18. /**
  19. * Contains array of all available employee from directory as id=>name
  20. *
  21. * @var array
  22. */
  23. protected $allEmployee = array();
  24. /**
  25. * Contains all available job types as id=>name
  26. *
  27. * @var array
  28. */
  29. protected $allJobTypes = array();
  30. /**
  31. * Task states instance placeholder
  32. *
  33. * @var object
  34. */
  35. protected $taskStates = '';
  36. /**
  37. * Photostorage object instance for tasks scope
  38. *
  39. * @var object
  40. */
  41. protected $photoStorage = '';
  42. /**
  43. * ADcomments object instance placeholder
  44. *
  45. * @var object
  46. */
  47. protected $adComments = '';
  48. /**
  49. * Contains all warehouse outcome counters as taskid=>count
  50. *
  51. * @vara array
  52. */
  53. protected $allWarehouseOutcomes = array();
  54. /**
  55. * Taskman database abstraction layer
  56. *
  57. * @var object
  58. */
  59. protected $taskmanDb = '';
  60. /**
  61. * System message helper instance placeholder
  62. *
  63. * @var object
  64. */
  65. protected $messages = '';
  66. /**
  67. * Task ranks instance placeholder
  68. *
  69. * @var object
  70. */
  71. protected $taskRanks = '';
  72. /**
  73. * Is TASKRANKS_ENABLED option enabled flag
  74. *
  75. * @var bool
  76. */
  77. protected $taskRanksEnabled = false;
  78. /**
  79. * Predefined routes/URLs/etc
  80. */
  81. const URL_ME = '?module=taskflow';
  82. const URL_TASK = '?module=taskman&edittask=';
  83. const ROUTE_EMREPORT = 'employeereport';
  84. const PROUTE_STATE = 'searchtaskstate';
  85. const PROUTE_PHOTO = 'searchtaskphoto';
  86. const PROUTE_WAREHOUSE = 'searchtaskwarehouse';
  87. const PROUTE_ADCOMMENTS = 'searchtaskadcomments';
  88. const PROUTE_EMPLOYEE = 'searchtaskemployee';
  89. const PROUTE_STARTSEARCH = 'searchtaskbegin';
  90. const PROUTE_DATESTART = 'datestart';
  91. const PROUTE_DATEEND = 'dateend';
  92. const PROUTE_ALLTIME = 'fulltimerange';
  93. const VAL_YES = 'yes';
  94. const VAL_NO = 'no';
  95. const VAL_ANY = 'any';
  96. /**
  97. * Rise up and reach for the sky
  98. * Journey to rainbow nights
  99. * You`ll never take me away
  100. * In rainbow nights I will stay
  101. */
  102. public function __construct() {
  103. $this->loadAlter();
  104. $this->setOptions();
  105. $this->initMessages();
  106. $this->loadEmployee();
  107. $this->initTaskStates();
  108. if ($this->taskRanksEnabled) {
  109. $this->initTaskRanks();
  110. }
  111. }
  112. /**
  113. * Loads system alter config into protected prop
  114. *
  115. * @global object $ubillingConfig
  116. *
  117. * @return void
  118. */
  119. protected function loadAlter() {
  120. global $ubillingConfig;
  121. $this->altCfg = $ubillingConfig->getAlter();
  122. }
  123. /**
  124. * Inits system messages helper protected instance
  125. *
  126. * @return void
  127. */
  128. protected function initMessages() {
  129. $this->messages = new UbillingMessageHelper();
  130. }
  131. /**
  132. * Creates new task ranks instance in protected property
  133. *
  134. * @return void
  135. */
  136. protected function initTaskRanks() {
  137. $this->taskRanks = new Stigma('TASKRANKS');
  138. }
  139. /**
  140. * Sets some object properties due config setup
  141. *
  142. * @return void
  143. */
  144. protected function setOptions() {
  145. if ($this->altCfg['TASKRANKS_ENABLED']) {
  146. $this->taskRanksEnabled = true;
  147. }
  148. }
  149. /**
  150. * Loads available employee from database
  151. *
  152. * @return void
  153. */
  154. protected function loadEmployee() {
  155. $employeeTmp = ts_GetAllEmployeeData();
  156. foreach ($employeeTmp as $io => $each) {
  157. $this->allEmployee[$each['id']] = $each['name'];
  158. if ($each['active']) {
  159. $this->allActiveEmployee[$each['id']] = $each['name'];
  160. }
  161. }
  162. }
  163. /**
  164. * Loads all available jobtypes names from database
  165. *
  166. * @return void
  167. */
  168. protected function loadJobTypes() {
  169. $this->allJobTypes = ts_GetAllJobtypes();
  170. }
  171. /**
  172. * Inits TaskStates instance for further usage
  173. *
  174. * @return void
  175. */
  176. protected function initTaskStates() {
  177. $this->taskStates = new TaskStates();
  178. }
  179. /**
  180. * Inits photostorage instance if required
  181. *
  182. * @return void
  183. */
  184. protected function initPhotostorage() {
  185. if ($this->altCfg['PHOTOSTORAGE_ENABLED']) {
  186. $this->photoStorage = new PhotoStorage('TASKMAN');
  187. }
  188. }
  189. /**
  190. * Inits ADcomments instance for further usage
  191. *
  192. * @return void
  193. */
  194. protected function initADcomments() {
  195. if ($this->altCfg['ADCOMMENTS_ENABLED']) {
  196. $this->adComments = new ADcomments('TASKMAN');
  197. }
  198. }
  199. /**
  200. * Inits taskman database abstraction layer
  201. *
  202. * @return void
  203. */
  204. protected function initTaskmanDb() {
  205. $this->taskmanDb = new NyanORM('taskman');
  206. }
  207. /**
  208. * Loads existing warehouse outcome operations from database
  209. *
  210. * @return void
  211. */
  212. protected function loadWarehouseOutcomes() {
  213. if ($this->altCfg['WAREHOUSE_ENABLED']) {
  214. $outcomes = new NyanORM('wh_out');
  215. $outcomes->where('desttype', '=', 'task');
  216. $all = $outcomes->getAll();
  217. if (!empty($all)) {
  218. foreach ($all as $io => $each) {
  219. if (isset($this->allWarehouseOutcomes[$each['destparam']])) {
  220. $this->allWarehouseOutcomes[$each['destparam']] ++;
  221. } else {
  222. $this->allWarehouseOutcomes[$each['destparam']] = 1;
  223. }
  224. }
  225. }
  226. }
  227. }
  228. /**
  229. * Render primary module controls aka filters
  230. *
  231. * @return string
  232. */
  233. public function renderControls() {
  234. $result = '';
  235. $inputs = wf_HiddenInput(self::PROUTE_STARTSEARCH, 'true'); //do some search flag
  236. $stateFlag = ubRouting::post(self::PROUTE_STATE);
  237. $inputs .= wf_SelectorAC(self::PROUTE_STATE, $this->taskStates->getStateTypes(), __('Task state'), $stateFlag, false) . ' ';
  238. $filterParams = array(self::VAL_ANY => __('No difference'), self::VAL_YES => __('Yes'), self::VAL_NO => __('No'));
  239. if ($this->altCfg['PHOTOSTORAGE_ENABLED']) {
  240. $photoFlag = ubRouting::post(self::PROUTE_PHOTO);
  241. $inputs .= wf_SelectorAC(self::PROUTE_PHOTO, $filterParams, __('Image'), $photoFlag, false) . ' ';
  242. }
  243. if ($this->altCfg['WAREHOUSE_ENABLED']) {
  244. $whFlag = ubRouting::post(self::PROUTE_WAREHOUSE);
  245. $inputs .= wf_SelectorAC(self::PROUTE_WAREHOUSE, $filterParams, __('Warehouse'), $whFlag, false) . ' ';
  246. }
  247. if ($this->altCfg['ADCOMMENTS_ENABLED']) {
  248. $adFlag = ubRouting::post(self::PROUTE_ADCOMMENTS);
  249. $inputs .= wf_SelectorAC(self::PROUTE_ADCOMMENTS, $filterParams, __('Notes'), $adFlag, false) . ' ';
  250. }
  251. if (!empty($this->allActiveEmployee)) {
  252. $employeeParams = array('any' => __('No difference'));
  253. $employeeParams += $this->allActiveEmployee;
  254. $empFlag = ubRouting::post(self::PROUTE_EMPLOYEE);
  255. $inputs .= wf_SelectorAC(self::PROUTE_EMPLOYEE, $employeeParams, __('Worker'), $empFlag, false) . ' ';
  256. }
  257. $timeFlag = ubRouting::checkPost(self::PROUTE_ALLTIME);
  258. $inputs .= wf_CheckInput(self::PROUTE_ALLTIME, __('All time'), false, $timeFlag) . ' ';
  259. $inputs .= wf_Submit(__('Search'));
  260. $result .= wf_Form('', 'POST', $inputs, 'glamour');
  261. return($result);
  262. }
  263. /**
  264. * Performs search of some tasks on selected params
  265. *
  266. * @return string
  267. */
  268. public function performSearch() {
  269. $result = '';
  270. //realy search is required?
  271. if (ubRouting::checkPost(self::PROUTE_STARTSEARCH)) {
  272. //Preloading some data
  273. $this->initPhotostorage();
  274. $this->loadWarehouseOutcomes();
  275. $this->initADcomments();
  276. //search filters setup
  277. $filterState = ubRouting::post(self::PROUTE_STATE);
  278. $filterPhoto = ubRouting::post(self::PROUTE_PHOTO);
  279. $filterWarehouse = ubRouting::post(self::PROUTE_WAREHOUSE);
  280. $filterAdcomments = ubRouting::post(self::PROUTE_ADCOMMENTS);
  281. $filterEmployee = ubRouting::post(self::PROUTE_EMPLOYEE);
  282. $allTimeRange = (ubRouting::checkPost(self::PROUTE_ALLTIME)) ? true : false;
  283. $allUndoneTasks = ts_GetUndoneTasksArray($allTimeRange);
  284. $filteredTasks = array(); // mem overusage? heh.. who cares?! :P
  285. if (!empty($allUndoneTasks)) {
  286. foreach ($allUndoneTasks as $taskId => $taskData) {
  287. $filtersMatched = false;
  288. //primary task state filtering
  289. if ($this->taskStates->getTaskState($taskId) == $filterState) {
  290. $filtersMatched = true;
  291. //photostorage filering
  292. if ($filterPhoto != self::VAL_ANY) {
  293. $imagesCount = $this->photoStorage->getImagesCount($taskId);
  294. if ($filterPhoto == self::VAL_YES AND $imagesCount == 0) {
  295. $filtersMatched = false;
  296. }
  297. if ($filterPhoto == self::VAL_NO AND $imagesCount > 0) {
  298. $filtersMatched = false;
  299. }
  300. }
  301. //warehouse filtering
  302. if ($filterWarehouse != self::VAL_ANY) {
  303. $outcomesCount = 0;
  304. if (isset($this->allWarehouseOutcomes[$taskId])) {
  305. $outcomesCount = $this->allWarehouseOutcomes[$taskId];
  306. }
  307. if ($filterWarehouse == self::VAL_YES AND $outcomesCount == 0) {
  308. $filtersMatched = false;
  309. }
  310. if ($filterWarehouse == self::VAL_NO AND $outcomesCount > 0) {
  311. $filtersMatched = false;
  312. }
  313. }
  314. //ADcomments filtering
  315. if ($filterAdcomments != self::VAL_ANY) {
  316. $adCommentsCount = $this->adComments->getCommentsCount($taskId);
  317. if ($filterAdcomments == self::VAL_YES AND $adCommentsCount == 0) {
  318. $filtersMatched = false;
  319. }
  320. if ($filterAdcomments == self::VAL_NO AND $adCommentsCount > 0) {
  321. $filtersMatched = false;
  322. }
  323. }
  324. if ($filterEmployee != self::VAL_ANY) {
  325. if ($filterEmployee != $taskData['employee']) {
  326. $filtersMatched = false;
  327. }
  328. }
  329. }
  330. if ($filtersMatched) {
  331. $filteredTasks[$taskId] = $taskData;
  332. }
  333. }
  334. //display some tasks list
  335. if (!empty($filteredTasks)) {
  336. $result .= $this->renderFilteredTasks($filteredTasks);
  337. } else {
  338. $result .= $this->messages->getStyledMessage(__('Nothing found'), 'info');
  339. }
  340. } else {
  341. $result .= $this->messages->getStyledMessage(__('Nothing found'), 'info');
  342. }
  343. }
  344. return($result);
  345. }
  346. /**
  347. * Renders filtered tasks array
  348. *
  349. * @param array $filteredTasks
  350. *
  351. * @return string
  352. */
  353. protected function renderFilteredTasks($filteredTasks) {
  354. $result = '';
  355. if (!empty($filteredTasks)) {
  356. //preloading some data required for rendering
  357. $allStateIcons = $this->taskStates->getStateIcons();
  358. $this->loadJobTypes();
  359. $cells = wf_TableCell(__('ID'));
  360. $cells .= wf_TableCell(__('Task state'));
  361. if (@$this->altCfg['PHOTOSTORAGE_ENABLED']) {
  362. $cells .= wf_TableCell(__('Image'));
  363. }
  364. if (@$this->altCfg['WAREHOUSE_ENABLED']) {
  365. $cells .= wf_TableCell(__('Outcoming operations'));
  366. }
  367. if ($this->taskRanksEnabled) {
  368. $cells .= wf_TableCell(__('Quality control'));
  369. }
  370. $cells .= wf_TableCell(__('Date'));
  371. $cells .= wf_TableCell(__('Address'));
  372. $cells .= wf_TableCell(__('Job type'));
  373. $cells .= wf_TableCell(__('Worker'));
  374. $cells .= wf_TableCell(__('Actions'));
  375. $rows = wf_TableRow($cells, 'row1');
  376. foreach ($filteredTasks as $taskId => $taskData) {
  377. $taskState = $this->taskStates->getTaskState($taskId);
  378. $taskStateName = $this->taskStates->getStateName($taskState);
  379. if (isset($allStateIcons[$taskState])) {
  380. $taskStateLabel = wf_img_sized($allStateIcons[$taskState], $taskStateName, 16, 16) . ' ' . $taskStateName;
  381. } else {
  382. $taskStateLabel = $taskState;
  383. }
  384. $cells = wf_TableCell($taskData['id']);
  385. $cells .= wf_TableCell($taskStateLabel);
  386. if (@$this->altCfg['PHOTOSTORAGE_ENABLED']) {
  387. $imagesCount = $this->photoStorage->getImagesCount($taskId);
  388. $cells .= wf_TableCell(web_bool_led($imagesCount));
  389. }
  390. if (@$this->altCfg['WAREHOUSE_ENABLED']) {
  391. $whOutcomesCount = (isset($this->allWarehouseOutcomes[$taskId])) ? $this->allWarehouseOutcomes[$taskId] : 0;
  392. $cells .= wf_TableCell(web_bool_led($whOutcomesCount));
  393. }
  394. if ($this->taskRanksEnabled) {
  395. $eachTaskRank = '';
  396. if ($this->taskRanks->haveState($taskId)) {
  397. $eachTaskRank .= $this->taskRanks->renderItemStates($taskId, 16);
  398. }
  399. $cells .= wf_TableCell($eachTaskRank);
  400. }
  401. $cells .= wf_TableCell($taskData['startdate']);
  402. $cells .= wf_TableCell($taskData['address']);
  403. $cells .= wf_TableCell(@$this->allJobTypes[$taskData['jobtype']]);
  404. $cells .= wf_TableCell($this->allEmployee[$taskData['employee']]);
  405. $taskControl = wf_Link(self::URL_TASK . $taskId, web_icon_search() . ' ' . __('Show'), false, 'ubButton', 'target="_BLANK"');
  406. $cells .= wf_TableCell($taskControl);
  407. $rows .= wf_TableRow($cells, 'row3');
  408. }
  409. $result .= wf_TableBody($rows, '100%', 0, 'sortable');
  410. }
  411. return($result);
  412. }
  413. /**
  414. * Gets advice of the day
  415. *
  416. * @return string
  417. */
  418. public function getAwesomeAdvice() {
  419. $result = '';
  420. $advices = new FGA();
  421. $result = $advices->getAdviceOfTheDay();
  422. return($result);
  423. }
  424. /**
  425. * Renders employee report search form
  426. *
  427. * @return string
  428. */
  429. public function renderEmployeeReportForm() {
  430. $result = '';
  431. $dateStart = (ubRouting::checkPost(self::PROUTE_DATESTART)) ? ubRouting::post(self::PROUTE_DATESTART, 'mres') : date("Y-m-" . '01');
  432. $dateEnd = (ubRouting::checkPost(self::PROUTE_DATEEND)) ? ubRouting::post(self::PROUTE_DATEEND, 'mres') : curdate();
  433. $inputs = wf_DatePickerPreset(self::PROUTE_DATESTART, $dateStart) . ' ' . __('From');
  434. $inputs .= wf_DatePickerPreset(self::PROUTE_DATEEND, $dateEnd) . ' ' . __('To') . ' ';
  435. $inputs .= wf_Submit('Search');
  436. $result .= wf_Form('', 'POST', $inputs, 'glamour');
  437. return($result);
  438. }
  439. /**
  440. * Performs employee report data preprocessing
  441. *
  442. * @return string
  443. */
  444. public function getrEmployeeReportData() {
  445. $result = array();
  446. if (!empty($this->allActiveEmployee)) {
  447. $this->initTaskmanDb();
  448. $dateStart = (ubRouting::checkPost(self::PROUTE_DATESTART)) ? ubRouting::post(self::PROUTE_DATESTART, 'mres') : date("Y-m-" . '01');
  449. $dateEnd = (ubRouting::checkPost(self::PROUTE_DATEEND)) ? ubRouting::post(self::PROUTE_DATEEND, 'mres') : curdate();
  450. $allStateTypes = $this->taskStates->getStateTypes();
  451. //setting date filter
  452. $this->taskmanDb->whereRaw("`startdate` BETWEEN '" . $dateStart . "' AND '" . $dateEnd . "'");
  453. //getting tasks planned for this period
  454. $allTasks = $this->taskmanDb->getAll();
  455. //preparing report data
  456. if (!empty($allTasks)) {
  457. foreach ($allTasks as $io => $each) {
  458. $taskState = $this->taskStates->getTaskState($each['id']);
  459. if (isset($result[$each['employee']])) {
  460. $result[$each['employee']]['TOTALTASKS'] ++;
  461. } else {
  462. //prefilling report data array
  463. $result[$each['employee']]['TOTALTASKS'] = 1;
  464. $result[$each['employee']]['NOSTATE'] = 0;
  465. if (!empty($allStateTypes)) {
  466. foreach ($allStateTypes as $stateType => $typeName) {
  467. $result[$each['employee']][$stateType] = 0;
  468. }
  469. }
  470. }
  471. //task state is set
  472. if (!empty($taskState)) {
  473. @$result[$each['employee']][$taskState] ++;
  474. } else {
  475. $result[$each['employee']]['NOSTATE'] ++;
  476. }
  477. }
  478. }
  479. }
  480. return($result);
  481. }
  482. /**
  483. * Renders task states report around employee
  484. *
  485. * @return string
  486. */
  487. public function renderEmployeeReport() {
  488. $result = '';
  489. if (!empty($this->allActiveEmployee)) {
  490. $reportData = $this->getrEmployeeReportData();
  491. if (!empty($reportData)) {
  492. $allStateTypes = $this->taskStates->getStateTypes();
  493. $allStateIcons = $this->taskStates->getStateIcons();
  494. $cells = wf_TableCell(__('Employee'));
  495. foreach ($allStateTypes as $eachStateId => $eachStateName) {
  496. $stateIcon = $allStateIcons[$eachStateId];
  497. $cells .= wf_TableCell(wf_img_sized($stateIcon, $eachStateName, '10', '10') . ' ' . $eachStateName);
  498. }
  499. $cells .= wf_TableCell(__('Total'));
  500. $cells .= wf_TableCell(__('No state'));
  501. $rows = wf_TableRow($cells, 'row1');
  502. foreach ($reportData as $employeeId => $stateStats) {
  503. $cells = wf_TableCell($this->allEmployee[$employeeId]);
  504. foreach ($allStateTypes as $eachStateId => $eachStateName) {
  505. $cells .= wf_TableCell($stateStats[$eachStateId]);
  506. }
  507. $cells .= wf_TableCell($stateStats['TOTALTASKS']);
  508. $cells .= wf_TableCell($stateStats['NOSTATE']);
  509. $rows .= wf_TableRow($cells, 'row5');
  510. }
  511. $result .= wf_TableBody($rows, '100%', 0, 'sortable');
  512. } else {
  513. $result .= $this->messages->getStyledMessage(__('Nothing found'), 'info');
  514. }
  515. } else {
  516. $result .= $this->messages->getStyledMessage(__('No job types and employee available'), 'warning');
  517. }
  518. $result .= wf_delimiter();
  519. $result .= wf_BackLink(self::URL_ME);
  520. return($result);
  521. }
  522. }