1: <?php
2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35:
36:
37: 38: 39:
40: class WorkflowController extends x2base {
41: public $modelClass="Workflow";
42:
43: 44: 45: 46: 47:
48: public function accessRules() {
49: return array(
50: array('allow',
51: 'actions'=>array(
52: 'index','view','getWorkflow','getStageDetails','updateStageDetails',
53: 'startStage','completeStage','revertStage','getStageMembers','getStages',
54: 'changeUi', 'addADeal', 'getStageNameItems', 'getStageNames'),
55: 'users'=>array('@'),
56: ),
57: array('allow',
58: 'actions'=>array('admin','create','update','delete'),
59: 'users'=>array('admin'),
60: ),
61: array('deny',
62: 'users'=>array('*'),
63: ),
64: );
65: }
66:
67:
68: public function actionIndex() {
69: $dataProvider = new CActiveDataProvider('Workflow');
70: $this->render('index',array(
71: 'dataProvider'=>$dataProvider,
72: ));
73: }
74:
75: public function actionAdmin(){
76: $this->redirect('index');
77: }
78:
79: 80: 81: 82:
83: public function actionView($id) {
84:
85:
86: if (!isset ($_GET['perStageWorkflowView'])) {
87: $perStageWorkflowView =
88: Yii::app()->params->profile->miscLayoutSettings['perStageWorkflowView'];
89: } else {
90: $perStageWorkflowView = $_GET['perStageWorkflowView'];
91: if ($perStageWorkflowView !==
92: Yii::app()->params->profile->miscLayoutSettings['perStageWorkflowView']) {
93:
94: $perStageWorkflowView = $perStageWorkflowView === 'true' ? true : false;
95: Profile::setMiscLayoutSetting (
96: 'perStageWorkflowView', $perStageWorkflowView, true);
97: }
98: }
99:
100: $users=isset($_GET['users'])?$_GET['users']:'';
101:
102: if(isset($_GET['stage']) && is_numeric($_GET['stage']))
103: $viewStage = $_GET['stage'];
104: else
105: $viewStage = null;
106:
107:
108: User::addRecentItem('w', $id, Yii::app()->user->getId());
109:
110: $workflows = Workflow::getList(false);
111:
112: $this->render('view',
113: array_merge (
114: array (
115: 'perStageWorkflowView' => $perStageWorkflowView,
116: 'workflows' => $workflows,
117: ),
118: ($perStageWorkflowView ?
119: $this->getPerStageViewParams ($id, $viewStage, $users) :
120: $this->getDragAndDropViewParams ($id, $users)
121: )
122: )
123: );
124: }
125:
126:
127:
128:
129: public function actionCreate() {
130: $workflowModel = new Workflow;
131: $workflowModel->lastUpdated = time();
132:
133: $stages = array();
134:
135: $workflowAttr = filter_input(INPUT_POST,'Workflow', FILTER_DEFAULT, FILTER_REQUIRE_ARRAY);
136: $workflowStages = filter_input(INPUT_POST,'WorkflowStages', FILTER_DEFAULT, FILTER_REQUIRE_ARRAY);
137: if(!empty($workflowAttr) && !empty($workflowStages)) {
138:
139:
140: $workflowModel->attributes = $workflowAttr;
141: $colors = filter_input(INPUT_POST, 'colors', FILTER_DEFAULT, FILTER_REQUIRE_ARRAY);
142: if (!empty($colors)) {
143: $colors = array_filter ($colors, function ($a) { return $a !== ''; });
144: $workflowModel->colors = $colors;
145: }
146:
147: if($workflowModel->save()) {
148: $validStages = true;
149: for($i=0; $i<count($workflowStages); $i++) {
150:
151: $stages[$i] = new WorkflowStage;
152: $stages[$i]->workflowId = $workflowModel->id;
153: $stages[$i]->attributes = $workflowStages[$i+1];
154: $stages[$i]->stageNumber = $i+1;
155: $stages[$i]->roles = $workflowStages[$i+1]['roles'];
156: if(empty($stages[$i]->roles) || in_array('',$stages[$i]->roles))
157: $stages[$i]->roles = array();
158:
159: if(!$stages[$i]->validate())
160: $validStages = false;
161: }
162:
163: if($validStages) {
164:
165: foreach($stages as &$stage) {
166: $stage->save();
167: foreach($stage->roles as $roleId)
168: Yii::app()->db->createCommand()->insert('x2_role_to_workflow',array(
169: 'stageId'=>$stage->id,
170: 'roleId'=>$roleId,
171: 'workflowId'=>$workflowModel->id,
172: ));
173: }
174: if($workflowModel->save())
175: $this->redirect(array('view','id'=>$workflowModel->id));
176: }
177: }
178: }
179:
180: $this->render('create',array(
181: 'model'=>$workflowModel,
182: ));
183: }
184:
185:
186:
187:
188: public function actionUpdate($id) {
189: $workflowModel = $this->loadModel($id);
190:
191: $workflowAttr = filter_input(INPUT_POST,'Workflow', FILTER_DEFAULT, FILTER_REQUIRE_ARRAY);
192: $workflowStages = filter_input(INPUT_POST,'WorkflowStages', FILTER_DEFAULT, FILTER_REQUIRE_ARRAY);
193: if(!empty($workflowAttr) && !empty($workflowStages)) {
194:
195: list($validStages, $newStages, $forDeletion) = $workflowModel->updateStages($workflowStages);
196:
197: $workflowModel->attributes = $workflowAttr;
198: $workflowModel->lastUpdated = time();
199: $colors = filter_input(INPUT_POST, 'colors', FILTER_DEFAULT, FILTER_REQUIRE_ARRAY);
200: if (!empty($colors)) {
201: $colors = array_filter ($colors, function ($a) { return $a !== ''; });
202: $workflowModel->colors = $colors;
203: }
204:
205: if($validStages && $workflowModel->validate()) {
206:
207: WorkflowStage::model()->deleteByPk($forDeletion);
208:
209:
210: Yii::app()->db->createCommand()->delete('x2_role_to_workflow','workflowId='.$id);
211: foreach($newStages as &$stage) {
212: $stage->save();
213: foreach($stage->roles as $roleId){
214: Yii::app()->db->createCommand()->insert('x2_role_to_workflow',array(
215: 'stageId'=>$stage->id,
216: 'roleId'=>$roleId,
217: 'workflowId'=>$id,
218: ));
219: }
220: }
221: if ($workflowModel->save()){
222: $this->redirect(array('view','id'=>$workflowModel->id));
223: }
224: }
225: }
226: $this->render('update',array(
227: 'model'=>$workflowModel,
228: ));
229: }
230:
231:
232:
233: public function actionDelete($id) {
234: if(Yii::app()->request->isPostRequest) {
235:
236: $this->loadModel($id)->delete();
237:
238: 239:
240: if(!isset($_GET['ajax']))
241: $this->redirect(isset($_POST['returnUrl']) ? $_POST['returnUrl'] : array('index'));
242: }
243: else
244: throw new CHttpException(
245: 400,'Invalid request. Please do not repeat this request again.');
246: }
247:
248: 249: 250:
251: public function actionGetWorkflow($workflowId,$modelId,$type) {
252: assert (is_numeric($workflowId));
253: assert (is_numeric($modelId));
254:
255: if(is_numeric($workflowId) && is_numeric($modelId)) {
256:
257:
258:
259:
260: $workflowStatus = Workflow::getWorkflowStatus($workflowId, $modelId, $type);
261: if (sizeof ($workflowStatus['stages']) < 1) return;
262:
263: $model = $this->loadModel($workflowId);
264: $colors = $model->getWorkflowStageColors (sizeof ($workflowStatus['stages']));
265:
266: $this->renderPartial ('_inlineFunnel', array (
267: 'workflowStatus' => $workflowStatus,
268: 'stageCount' => sizeof ($workflowStatus['stages']),
269: 'colors' => $colors,
270: ), false, true);
271: }
272: }
273:
274: 275: 276:
277: public function renderFunnelView (
278: $workflowId, $dateRange, $users='', $modelId=0,
279: $modelType='') {
280:
281: $workflowStatus = Workflow::getWorkflowStatus($workflowId, $modelId, $modelType);
282: $stageCounts = Workflow::getStageCounts (
283: $workflowStatus, $dateRange, $users, $modelType);
284: $stageValues = Workflow::getStageValues(
285: $workflowStatus, $dateRange, $users, $modelType);
286:
287: $model = $this->loadModel($workflowId);
288: $colors = $model->getWorkflowStageColors (sizeof ($stageCounts));
289:
290: $stageNameLinks = Workflow::getStageNameLinks (
291: $workflowStatus, $dateRange, $users);
292:
293: $this->renderPartial ('_funnel', array (
294: 'workflowStatus' => $workflowStatus,
295: 'recordsPerStage' => $stageCounts,
296: 'stageCount' => sizeof ($stageCounts),
297: 'stageValues' => array_map (
298: function ($a) { return (is_null($a) ? '' : Formatter::formatCurrency ($a)); }, $stageValues),
299: 'totalValue' => Formatter::formatCurrency (array_sum ($stageValues)),
300: 'stageNameLinks' => $stageNameLinks,
301: 'colors' => $colors,
302: ));
303:
304: }
305:
306: public function renderInlineFunnelView ($workflowId, $modelId=0, $type='') {
307: $workflowStatus = Workflow::getWorkflowStatus($workflowId,$modelId,$type);
308: }
309:
310:
311: public function actionGetStageDetails($workflowId,$stage,$modelId,$type) {
312: if(is_numeric($workflowId) && is_numeric($stage) && is_numeric($modelId)) {
313:
314: $workflowStatus = Workflow::getWorkflowStatus($workflowId,$modelId,$type);
315: $stageArr = $workflowStatus['stages'][$stage];
316: if(isset($stageArr)) {
317: $model = X2Model::model('Actions')->findByAttributes(array(
318: 'associationId'=>$modelId,
319: 'associationType'=>$type,
320: 'type'=>'workflow',
321: 'workflowId'=>$workflowId,
322: 'stageNumber'=>$stageArr['id']
323: ));
324:
325: if($model->complete != 'Yes')
326: $model->completedBy = Yii::app()->user->name;
327:
328: $editable = true;
329:
330:
331: if(!empty($stageArr['roles'])) {
332: $editable = count(array_intersect(Yii::app()->params->roles,
333: $stageArr['roles'])) > 0;
334: }
335:
336:
337: if(Yii::app()->settings->workflowBackdateWindow > 0 &&
338: (time() - $model->completeDate) >
339: Yii::app()->settings->workflowBackdateWindow) {
340: $editable = false;
341: }
342:
343: if(Yii::app()->user->checkAccess('WorkflowAdmin') || Yii::app()->params->isAdmin)
344: $editable = true;
345:
346: $minDate = Yii::app()->settings->workflowBackdateRange;
347: if($minDate < 0)
348: $minDate = null;
349: else
350: $minDate = '-'.$minDate;
351:
352: if(Yii::app()->user->checkAccess('WorkflowAdmin') || Yii::app()->params->isAdmin)
353: $minDate = null;
354:
355: $this->renderPartialAjax('_workflowDetail',array(
356: 'model'=>$model,
357: 'editable'=>$editable,
358: 'minDate'=>$minDate,
359: 'allowReassignment'=>
360: Yii::app()->settings->workflowBackdateReassignment ||
361: Yii::app()->params->isAdmin,
362: ),false);
363: }
364: }
365: }
366:
367: public function actionUpdateStageDetails($id) {
368:
369: $action = X2Model::model('Actions')->findByPk($id);
370: $previouslyComplete = $action->complete === 'Yes';
371:
372: $model = X2Model::getModelOfTypeWithId(
373: $action->associationType,$action->associationId, true);
374:
375: if(isset($model,$action,$_POST['Actions'])) {
376: $action->setScenario('workflow');
377:
378: $action->createDate = Formatter::parseDate($_POST['Actions']['createDate']);
379: $action->completeDate = Formatter::parseDate($_POST['Actions']['completeDate']);
380: $action->actionDescription = $_POST['Actions']['actionDescription'];
381:
382: if(isset($_POST['Actions']['completedBy']) &&
383: (Yii::app()->params->isAdmin ||
384: Yii::app()->settings->workflowBackdateReassignment)) {
385: $action->completedBy = $_POST['Actions']['completedBy'];
386: }
387:
388:
389: if($action->createDate === false)
390: return;
391:
392: if($action->completeDate === false) {
393: $action->complete = 'No';
394: $action->completedBy = null;
395:
396: $model->updateLastActivity();
397:
398: if($previouslyComplete)
399: Workflow::updateWorkflowChangelog($action,'revert',$model);
400:
401: unset ($action->completeDate);
402: } else {
403: if($action->completeDate < $action->createDate) {
404:
405: $action->completeDate = $action->createDate;
406: }
407: $action->complete = 'Yes';
408:
409: if(!$previouslyComplete)
410: Workflow::updateWorkflowChangelog($action,'complete',$model);
411: }
412: if ($action->save()) {
413: if ($action->complete === 'Yes') {
414: echo 'complete';
415: } else {
416: echo 'success';
417: }
418: }
419: }
420:
421: }
422:
423: 424: 425:
426: public function actionMoveFromStageAToStageB () {
427: if(!(isset($_POST['workflowId']) && isset ($_POST['stageA']) &&
428: isset ($_POST['stageB']) && isset ($_POST['modelId']) && isset ($_POST['type']) &&
429: (!isset ($_POST['comments']) || is_array ($_POST['comments'])))) {
430:
431: throw new CHttpException(
432: 400, 'Invalid request. Please do not repeat this request again.');
433: }
434:
435: $workflowId = (int) $_POST['workflowId'];
436: $stageA = (int) $_POST['stageA'];
437: $stageB = (int) $_POST['stageB'];
438: $modelId = (int) $_POST['modelId'];
439: $comments = isset ($_POST['comments']) ? $_POST['comments'] : array ();
440: $type = $_POST['type'];
441: $model = X2Model::getModelOfTypeWithId($type,$modelId, true);
442:
443: if ($stageA === $stageB || $model === null) {
444: echo 'failure';
445: return;
446: }
447:
448: $retVal = Workflow::moveFromStageAToStageB (
449: $workflowId, $stageA, $stageB, $model, $comments);
450: echo CJSON::encode (array (
451: 'workflowStatus' => Workflow::getWorkflowStatus ($workflowId, $modelId, $type),
452: 'flashes' => array ('error' => isset ($retVal[1]) ? array ($retVal[1]) : array ())
453: ));
454: }
455:
456: public function actionStartStage(
457: $workflowId,$stageNumber,$modelId,$type) {
458:
459: $model = $this->validateParams ($workflowId, $stageNumber, $modelId, $type);
460:
461: $workflowStatus = Workflow::getWorkflowStatus($workflowId,$model->id,$type);
462: $message = '';
463: if (Workflow::validateAction (
464: 'start', $workflowStatus, $stageNumber, '', $message)) {
465:
466: list ($started, $workflowStatus) =
467: Workflow::startStage (
468: $workflowId, $stageNumber, $model, $workflowStatus);
469: assert ($started);
470: }
471: echo CJSON::encode (array (
472: 'workflowStatus' => $workflowStatus,
473: 'flashes' => array (
474: 'error' => !empty ($message) ? array ($message) : array (),
475: 'success' => empty ($message) ?
476: array (Yii::t('workflow', 'Stage started')) : array (),
477: )
478: ));
479: }
480:
481: 482: 483: 484: 485: 486: 487: 488: 489:
490: private function validateParams ($workflowId,$stageNumber,$modelId,$type,$recordName=null) {
491: if(!is_numeric($workflowId) || !is_numeric($stageNumber) ||
492: (!is_numeric($modelId) && $recordName === null)) {
493: throw new CHttpException (400, 'Bad Request');
494: }
495:
496: if (!is_numeric ($modelId)) {
497: $model = X2Model::getModelOfTypeWithName($type,$recordName);
498: } else {
499: $model = X2Model::getModelOfTypeWithId($type,$modelId, true);
500: }
501:
502: if ($model === null) throw new CHttpException (400, 'Bad Request');
503: return $model;
504: }
505:
506: 507: 508: 509: 510: 511: 512:
513: public function actionAjaxAddADeal (
514: $workflowId,$stageNumber,$modelId=null,$type,$recordName=null) {
515:
516: $model = $this->validateParams ($workflowId, $stageNumber, $modelId, $type,$recordName);
517: $workflowStatus = Workflow::getWorkflowStatus($workflowId,$model->id,$type);
518: $message = '';
519: if (Workflow::validateAction (
520: 'start', $workflowStatus, $stageNumber, '', $message)) {
521:
522: list ($started, $workflowStatus) =
523: Workflow::startStage (
524: $workflowId, $stageNumber, $model, $workflowStatus);
525: assert ($started);
526: }
527: echo CJSON::encode (array (
528: 'workflowStatus' => $workflowStatus,
529: 'flashes' => array (
530: 'error' => !empty ($message) ? array ($message) : array (),
531: 'success' => empty ($message) ?
532: array (Yii::t('workflow', 'Stage started')) : array (),
533: )
534: ));
535: }
536:
537: public function actionCompleteStage(
538: $workflowId,$stageNumber,$modelId,$type,$comment='') {
539:
540: $model = $this->validateParams ($workflowId, $stageNumber, $modelId, $type);
541:
542: $workflowStatus = Workflow::getWorkflowStatus($workflowId,$modelId,$type);
543: $message = '';
544: if (Workflow::validateAction (
545: 'complete', $workflowStatus, $stageNumber, $comment, $message)) {
546:
547: list ($completed, $workflowStatus) = Workflow::completeStage (
548: $workflowId, $stageNumber, $model, $comment, true);
549: }
550:
551:
552:
553:
554:
555:
556:
557: echo CJSON::encode (array (
558: 'workflowStatus' => $workflowStatus,
559: 'flashes' => array (
560: 'error' => !empty ($message) ? array ($message) : array (),
561: 'success' => empty ($message) ?
562: array (Yii::t('workflow', 'Stage completed')) : array (),
563: )
564: ));
565: }
566:
567: public function actionRevertStage($workflowId,$stageNumber,$modelId,$type) {
568: $model = $this->validateParams ($workflowId, $stageNumber, $modelId, $type);
569:
570: if ($model === null) throw new CHttpException (400, 'Bad Request');
571: $workflowStatus = Workflow::getWorkflowStatus($workflowId,$modelId,$type);
572: $message = '';
573: if (Workflow::validateAction (
574: 'revert', $workflowStatus, $stageNumber, '', $message)) {
575:
576: list ($completed, $workflowStatus) = Workflow::revertStage (
577: $workflowId, $stageNumber, $model);
578: }
579:
580: echo CJSON::encode (array (
581: 'workflowStatus' => $workflowStatus,
582: 'flashes' => array (
583: 'error' => !empty ($message) ? array ($message) : array (),
584: 'success' => empty ($message) ?
585: array (Yii::t('workflow', 'Stage reverted')) : array (),
586: )
587: ));
588: }
589:
590:
591: 592: 593: 594:
595: public function getStageMemberDataProvider (
596: $type, $workflowId, $dateRange, $stage, $user) {
597:
598: $modelName = X2Model::getModelName ($type);
599: if(!$modelName){
600: $type = 'contacts';
601: $modelName = 'Contacts';
602: }
603: $model = X2Model::model ($modelName);
604: $tableName = $model->tableName ();
605: $stageModel = WorkflowStage::model()->findByAttributes(array(
606: 'workflowId' => $workflowId,
607: 'stageNumber' => $stage,
608: ));
609: $params = array (
610: ':workflowId' => $workflowId,
611: ':stage' => $stageModel->id,
612: ':start' => $dateRange['start'],
613: ':end' => $dateRange['end'],
614: ':type' => $type,
615: );
616:
617: if(!empty($user)){
618: $userString=" AND x2_actions.assignedTo=:user ";
619: $params[':user'] = $user;
620: }else{
621: $userString="";
622: }
623:
624: list ($accessCondition, $accessConditionParams) =
625: $modelName::model ()->getAccessSQLCondition ($tableName);
626: $params = array_merge ($params, $accessConditionParams);
627: $stageMemberSql = Yii::app()->db->createCommand()
628: ->select("$tableName.*, x2_actions.lastUpdated as actionLastUpdated")
629: ->from($tableName)
630: ->join('x2_actions',"$tableName.id = x2_actions.associationId")
631: ->where("x2_actions.workflowId=:workflowId AND x2_actions.stageNumber=:stage AND
632: x2_actions.associationType=:type AND complete!='Yes' AND
633: (completeDate IS NULL OR completeDate=0) AND
634: x2_actions.createDate BETWEEN :start AND :end ".$userString." AND ".$accessCondition
635: )
636: ->getText();
637:
638: $memberCount = Yii::app()->db->createCommand()
639: ->select("COUNT(*)")
640: ->from($tableName)
641: ->join('x2_actions',"$tableName.id = x2_actions.associationId")
642: ->where("x2_actions.workflowId=:workflowId AND x2_actions.stageNumber=:stage AND
643: x2_actions.associationType=:type AND complete!='Yes' AND
644: (completeDate IS NULL OR completeDate=0) AND
645: x2_actions.createDate BETWEEN :start AND :end ".$userString.' AND '.$accessCondition,
646: $params
647: )
648: ->queryScalar();
649:
650: $membersDataProvider = new CSqlDataProvider($stageMemberSql,array(
651: 'totalItemCount'=>$memberCount,
652: 'sort'=>array(
653: 'defaultOrder'=>'lastUpdated DESC',
654: ),
655: 'pagination'=> array('pageSize'=>20),
656: 'params' => $params
657: ));
658:
659: return $membersDataProvider;
660: }
661:
662: public function actionGetStageMembers(
663: $id,$stage,$start,$end,$range, $users,$modelType) {
664:
665: $this->getStageMembers (
666: $id, $stage, $start, $end, $range, $users, $modelType);
667: }
668:
669: public function getStageMembers($workflowId,$stage,$start,$end,$range,
670: $users, $modelType='') {
671:
672: $params = array ();
673:
674: $dateRange=self::getDateRange();
675:
676: if(!is_numeric($workflowId) || !is_numeric($stage))
677: return new CActiveDataProvider();
678:
679: $dataProvider = $this->getStageMemberDataProvider (
680: $modelType, $workflowId, $dateRange, $stage, $users);
681:
682: $gridConfig = array (
683: 'baseScriptUrl'=>Yii::app()->theme->getBaseUrl().'/css/gridview',
684: 'template'=>
685: '<div class="page-title">{title}{buttons}'.
686: '</div>{items}{pager}',
687: 'fixedHeader' => false,
688: 'fullscreen' => false,
689: 'buttons'=>array('columnSelector','autoResize'),
690: );
691: $modelName = X2Model::getModelName($modelType);
692: $this->renderPartial ('_ajaxRequestedStageMembers',
693: array ('gridConfig' => array_merge (
694: $gridConfig,
695: array (
696: 'gvSettingsName' => $modelType.'-stageMembers',
697: 'viewName' => $modelType.'-workflowView',
698: 'defaultGvSettings'=>array(
699: 'name' => 125,
700: 'lastUpdated' => 80,
701: 'assignedTo' => 80,
702: ),
703: 'dataProvider' => $dataProvider,
704: 'id'=>'workflow-stage-grid',
705: 'ajaxUpdate'=>'workflow-stage-grid',
706: 'modelName' => $modelName,
707: 'title' => Modules::displayName(true, $modelType),
708: 'specialColumns'=>array(
709: 'name' => array(
710: 'name'=>'name',
711: 'header'=>Yii::t('app','Name'),
712: 'value'=>'X2Model::getModelLinkMock (
713: "'.$modelName.'",
714: $data[\'nameId\'],
715: array (
716: \'data-qtip-title\' => $data[\'name\']
717: )
718: )',
719: 'type'=>'raw',
720: 'htmlOptions'=>array('width'=>'30%')
721: ),
722: 'lastUpdated' => array(
723: 'name'=>'lastUpdated',
724: 'header'=>X2Model::model($modelName)->getAttributeLabel('lastUpdated'),
725: 'value'=>'Formatter::formatDate($data["lastUpdated"])',
726: 'type'=>'raw',
727: 'htmlOptions'=>array('width'=>'15%')
728: ),
729: 'assignedTo' => array(
730: 'header'=>X2Model::model($modelName)->getAttributeLabel('assignedTo'),
731: 'name'=>'assignedTo',
732: 'value'=>'empty($data["assignedTo"])?'.
733: 'Yii::t("app","Anyone"):User::getUserLinks($data["assignedTo"])',
734: 'type'=>'raw',
735: ),
736: ),
737: )
738: )), false, true);
739:
740: }
741:
742: public function actionGetStageValue($id,$stage,$users,$modelType,$start,$end){
743: $dateRange = self::getDateRange ();
744: $workflow = Workflow::model ()->findByPk ($id);
745: if ($workflow !== null) {
746: $workflowStatus = Workflow::getWorkflowStatus ($id);
747: $counts = Workflow::getStageCounts($workflowStatus, $dateRange, $users, $modelType);
748: $this->renderPartial ('_dataSummary', array (
749: 'stageName' => $workflow->getStageName ($stage),
750: 'count' => $counts[$stage - 1],
751: ));
752: }
753: }
754:
755:
756: public function actionGetStages() {
757: if(isset($_GET['id'])) {
758: $stages = Yii::app()->db->createCommand()
759: ->select('name')
760: ->from('x2_workflow_stages')
761: ->where('workflowId=:id',array(':id'=>$_GET['id']))
762: ->order('id ASC')
763: ->queryColumn();
764:
765: echo CJSON::encode($stages);
766: }
767: }
768:
769: 770: 771:
772: public function actionChangeUI () {
773: if (!isset ($_GET['perStageWorkflowView']) ||
774: !isset ($_GET['id'])) {
775: return;
776: }
777:
778: $perStageWorkflowView = $_GET['perStageWorkflowView'] === 'true' ? true : false;
779: $id = (int) $_GET['id'];
780: $users = isset ($_GET['users']) ? $_GET['users'] : '';
781:
782: Profile::setMiscLayoutSetting ('perStageWorkflowView', $perStageWorkflowView, true);
783:
784: if ($perStageWorkflowView) {
785: $this->renderPartial (
786: '_perStageView', $this->getPerStageViewParams ($id, null, $users), false, true);
787: } else {
788: $this->renderPartial (
789: '_dragAndDropView',$this->getDragAndDropViewParams ($id, $users), false, true);
790: }
791: }
792:
793: 794: 795: 796:
797: protected function performAjaxValidation($model)
798: {
799: if(isset($_POST['ajax']) && $_POST['ajax']==='workflow-form')
800: {
801: echo CActiveForm::validate($model);
802: Yii::app()->end();
803: }
804: }
805:
806: private function getDragAndDropViewParams ($id, $users='') {
807: $model = $this->loadModel($id);
808: if(isset($_GET['modelType'])){
809: $modelType = $_GET['modelType'];
810: }elseif(!empty($model->financialModel)){
811: if(X2Model::getModelName($model->financialModel)){
812: $modelType = $model->financialModel;
813: }else{
814: $modelType = 'contacts';
815: }
816: }else{
817: $modelType = 'contacts';
818: }
819: $dateRange=self::getDateRange();
820:
821: $memberListContainerSelectors = array ();
822: $stageCount = count ($model->stages);
823: for ($i = 1; $i <= $stageCount; $i++) {
824: $memberListContainerSelectors[] = '#workflow-stage-'.$i.' .items';
825: }
826: $workflowStatus = Workflow::getWorkflowStatus ($id);
827: $stagePermissions = Workflow::getStagePermissions ($workflowStatus);
828: $stagesWhichRequireComments = Workflow::getStageCommentRequirements ($workflowStatus);
829: $stageNames = Workflow::getStageNames ($workflowStatus);
830: $colors = $model->getWorkflowStageColors ($stageCount, true);
831: $stageCounts = Workflow::getStageCounts (
832: $workflowStatus, $dateRange, $users, $modelType);
833: $stageValues = Workflow::getStageValues(
834: $workflowStatus, $dateRange, $users, $modelType);
835: return array (
836: 'model'=>$model,
837: 'modelType'=>$modelType,
838: 'dateRange'=>$dateRange,
839: 'users'=>$users,
840: 'colors'=>$colors,
841: 'listItemColors'=>Workflow::getPipelineListItemColors ($colors),
842: 'memberListContainerSelectors'=>$memberListContainerSelectors,
843: 'stagePermissions'=>$stagePermissions,
844: 'stagesWhichRequireComments'=>$stagesWhichRequireComments,
845: 'stageNames'=>$stageNames,
846: 'stageCounts' => $stageCounts,
847: 'stageValues' => $stageValues,
848: );
849: }
850:
851: private function getPerStageViewParams ($id, $viewStage=null, $users='') {
852: $dateRange=self::getDateRange();
853: $model = $this->loadModel($id);
854: $modelType = isset ($_GET['modelType']) ? $_GET['modelType'] : (!empty($model->financialModel)?$model->financialModel:'contacts');
855: $stageCount = count ($model->stages);
856: return array (
857: 'model'=>$model,
858: 'modelType'=>$modelType,
859: 'viewStage'=>$viewStage,
860: 'colors'=>$model->getWorkflowStageColors ($stageCount, true),
861: 'dateRange'=>$dateRange,
862: 'users'=>$users,
863: );
864: }
865:
866: 867: 868:
869: public function actionGetItems($term){
870: X2LinkableBehavior::getItems ($term);
871: }
872:
873: 874: 875:
876: public function actionGetStageNames($workflowId, $optional='true'){
877: $stages = Workflow::getStagesByNumber($workflowId);
878: if ($optional === 'true')
879: echo CJSON::encode (
880: AuxLib::dropdownForJson (array ('any' => Yii::t('app', 'Any')) + $stages));
881: else
882: echo CJSON::encode (AuxLib::dropdownForJson ($stages));
883: }
884:
885: 886: 887:
888: public function actionGetStageNameItems($workflowId, $term){
889: $stageNames = Yii::app()->db->createCommand()
890: ->select('name')
891: ->from('x2_workflow_stages')
892: ->where(
893: 'workflowId=:id and name like :qterm',
894: array(':id'=>$workflowId, ':qterm' => $term.'%'))
895: ->order('stageNumber ASC')
896: ->queryColumn();
897: echo CJSON::encode ($stageNames);
898: }
899:
900: public function actionGetFinancialFields($modelType){
901: $ret = array('' => 'Select a field');
902: $ret = array_merge($ret, Workflow::getCurrencyFields($modelType));
903: echo CJSON::encode($ret);
904: }
905:
906: 907: 908: 909:
910: public static function getDateRange (
911: $startKey='start',$endKey='end',$rangeKey='range') {
912: return X2DateUtil::getDateRange ($startKey, $endKey, $rangeKey, 'custom');
913: }
914:
915: 916: 917: 918: 919: 920:
921: public function ($selectOptions = array(), $model = null, $menuParams = null) {
922: $Processes = Modules::displayName();
923: $Process = Modules::displayName(false);
924: $modelId = isset($model) ? $model->id : 0;
925:
926: 927: 928: 929: 930: 931:
932:
933: $menuItems = array(
934: array(
935: 'name'=>'index',
936: 'label'=>Yii::t('workflow','All {processes}', array(
937: '{processes}' => $Processes,
938: )),
939: 'url'=>array('index')
940: ),
941: array(
942: 'name'=>'create',
943: 'label'=>Yii::t('app','Create'),
944: 'url'=>array('create'),
945: 'visible'=>Yii::app()->params->isAdmin
946: ),
947: array(
948: 'name'=>'edit',
949: 'label'=>Yii::t('workflow','Edit {process}', array(
950: '{process}' => $Process,
951: )),
952: 'url'=>array('update', 'id'=>$modelId),
953: 'visible'=>Yii::app()->params->isAdmin
954: ),
955: array(
956: 'name'=>'funnel',
957: 'label'=>Yii::t('app','Funnel View'),
958: 'url'=>array('view', 'id'=>$modelId, 'perStageWorkflowView'=>'true'),
959: 'linkOptions' => array ('id' => 'funnel-view-menu-item'),
960: ),
961: array(
962: 'name'=>'pipeline',
963: 'label'=>Yii::t('app','Pipeline View'),
964: 'url'=>array('view', 'id'=>$modelId, 'perStageWorkflowView'=>'false'),
965: 'linkOptions' => array ('id' => 'pipeline-view-menu-item'),
966: ),
967: array(
968: 'name'=>'delete',
969: 'label'=>Yii::t('workflow','Delete {process}', array(
970: '{process}' => $Process,
971: )),
972: 'url'=>'#',
973: 'linkOptions'=>array('submit'=>array('delete','id'=>$modelId),
974: 'confirm'=>Yii::t('app','Are you sure you want to delete this item?')),
975: 'visible'=>Yii::app()->params->isAdmin
976: ),
977: );
978:
979: $this->prepareMenu($menuItems, $selectOptions);
980: $this->actionMenu = $this->formatMenu($menuItems, $menuParams);
981: }
982: }
983:
984: