PageRenderTime 45ms CodeModel.GetById 20ms RepoModel.GetById 1ms app.codeStats 0ms

/app/protected/modules/workflows/tests/unit/WorkflowDocumentationTest.php

https://bitbucket.org/zurmo/zurmo
PHP | 408 lines | 296 code | 23 blank | 89 comment | 0 complexity | 15e8841efaa2ca350fb1278fa2ff448d MD5 | raw file
Possible License(s): LGPL-3.0, LGPL-2.1, BSD-2-Clause, AGPL-3.0, BSD-3-Clause, GPL-2.0
  1. <?php
  2. /*********************************************************************************
  3. * Zurmo is a customer relationship management program developed by
  4. * Zurmo, Inc. Copyright (C) 2015 Zurmo Inc.
  5. *
  6. * Zurmo is free software; you can redistribute it and/or modify it under
  7. * the terms of the GNU Affero General Public License version 3 as published by the
  8. * Free Software Foundation with the addition of the following permission added
  9. * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK
  10. * IN WHICH THE COPYRIGHT IS OWNED BY ZURMO, ZURMO DISCLAIMS THE WARRANTY
  11. * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS.
  12. *
  13. * Zurmo is distributed in the hope that it will be useful, but WITHOUT
  14. * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  15. * FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
  16. * details.
  17. *
  18. * You should have received a copy of the GNU Affero General Public License along with
  19. * this program; if not, see http://www.gnu.org/licenses or write to the Free
  20. * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  21. * 02110-1301 USA.
  22. *
  23. * You can contact Zurmo, Inc. with a mailing address at 27 North Wacker Drive
  24. * Suite 370 Chicago, IL 60606. or at email address contact@zurmo.com.
  25. *
  26. * The interactive user interfaces in original and modified versions
  27. * of this program must display Appropriate Legal Notices, as required under
  28. * Section 5 of the GNU Affero General Public License version 3.
  29. *
  30. * In accordance with Section 7(b) of the GNU Affero General Public License version 3,
  31. * these Appropriate Legal Notices must retain the display of the Zurmo
  32. * logo and Zurmo copyright notice. If the display of the logo is not reasonably
  33. * feasible for technical reasons, the Appropriate Legal Notices must display the words
  34. * "Copyright Zurmo Inc. 2015. All rights reserved".
  35. ********************************************************************************/
  36. class WorkflowDocumentationTest extends WorkflowBaseTest
  37. {
  38. protected static $jimmy;
  39. public static function setUpBeforeClass()
  40. {
  41. parent::setUpBeforeClass();
  42. SecurityTestHelper::createSuperAdmin();
  43. $super = User::getByUsername('super');
  44. Yii::app()->user->userModel = $super;
  45. //Setup test data owned by the super user.
  46. OpportunityTestHelper::createOpportunityStagesIfDoesNotExist();
  47. ContactsModule::loadStartingData();
  48. $jimmy = UserTestHelper::createBasicUserWithEmailAddress('jimmy');
  49. self::$jimmy = $jimmy;
  50. }
  51. public function setUp()
  52. {
  53. parent::setUp();
  54. Yii::app()->user->userModel = User::getByUsername('super');
  55. }
  56. /**
  57. * A simple workflow that is only triggered on a new account being created. If the owner is jimmy it means
  58. * that the description will be updated with some text.
  59. */
  60. public function testUpdateDescriptionWhenAccountIsCreatedAndOwnerIsJim()
  61. {
  62. $super = User::getByUsername('super');
  63. $contactStates = ContactState::getAll();
  64. //Create workflow
  65. $workflow = new Workflow();
  66. $workflow->setDescription ('aDescription');
  67. $workflow->setIsActive (true);
  68. $workflow->setOrder (1);
  69. $workflow->setModuleClassName('AccountsModule');
  70. $workflow->setName ('myFirstWorkflow');
  71. $workflow->setTriggerOn (Workflow::TRIGGER_ON_NEW);
  72. $workflow->setType (Workflow::TYPE_ON_SAVE);
  73. $workflow->setTriggersStructure('1');
  74. //Add Trigger
  75. $trigger = new TriggerForWorkflowForm('AccountsModule', 'Account', Workflow::TYPE_ON_SAVE);
  76. $trigger->attributeIndexOrDerivedType = 'owner';
  77. $trigger->value = self::$jimmy->id;
  78. $trigger->operator = 'equals';
  79. $workflow->addTrigger($trigger);
  80. //Add action
  81. $action = new ActionForWorkflowForm('Opportunity', Workflow::TYPE_ON_SAVE);
  82. $action->type = ActionForWorkflowForm::TYPE_UPDATE_SELF;
  83. $attributes = array( 'description' => array('shouldSetValue' => '1',
  84. 'type' => WorkflowActionAttributeForm::TYPE_STATIC,
  85. 'value' => 'my new description')
  86. );
  87. $action->setAttributes(array(ActionForWorkflowForm::ACTION_ATTRIBUTES => $attributes));
  88. $workflow->addAction($action);
  89. //Create the saved Workflow
  90. $savedWorkflow = new SavedWorkflow();
  91. SavedWorkflowToWorkflowAdapter::resolveWorkflowToSavedWorkflow($workflow, $savedWorkflow);
  92. $saved = $savedWorkflow->save();
  93. $this->assertTrue($saved);
  94. $account = AccountTestHelper::createAccountByNameForOwner('my account', self::$jimmy);
  95. $this->assertTrue($account->id > 0);
  96. $this->assertEquals('my new description', $account->description);
  97. }
  98. public function testCreateARelatedContactOnAnOpportunityWhenOpportunityBecomesClosedWon()
  99. {
  100. $super = User::getByUsername('super');
  101. $contactStates = ContactState::getAll();
  102. //Create workflow
  103. $workflow = new Workflow();
  104. $workflow->setDescription ('aDescription');
  105. $workflow->setIsActive (true);
  106. $workflow->setOrder (1);
  107. $workflow->setModuleClassName('OpportunitiesModule');
  108. $workflow->setName ('myFirstWorkflow');
  109. $workflow->setTriggerOn (Workflow::TRIGGER_ON_NEW_AND_EXISTING);
  110. $workflow->setType (Workflow::TYPE_ON_SAVE);
  111. $workflow->setTriggersStructure('1');
  112. //Add Trigger
  113. $trigger = new TriggerForWorkflowForm('OpportunitiesModule', 'Opportunity', Workflow::TYPE_ON_SAVE);
  114. $trigger->attributeIndexOrDerivedType = 'stage';
  115. $trigger->value = 'Prospecting';
  116. $trigger->operator = 'equals';
  117. $workflow->addTrigger($trigger);
  118. //Add action
  119. $action = new ActionForWorkflowForm('Opportunity', Workflow::TYPE_ON_SAVE);
  120. $action->type = ActionForWorkflowForm::TYPE_CREATE;
  121. $action->relation = 'contacts';
  122. $attributes = array( 'lastName' => array('shouldSetValue' => '1',
  123. 'type' => WorkflowActionAttributeForm::TYPE_STATIC,
  124. 'value' => 'smith'),
  125. 'firstName' => array('shouldSetValue' => '1',
  126. 'type' => WorkflowActionAttributeForm::TYPE_STATIC,
  127. 'value' => 'john'),
  128. 'owner__User' => array('shouldSetValue' => '1',
  129. 'type' => WorkflowActionAttributeForm::TYPE_STATIC,
  130. 'value' => Yii::app()->user->userModel->id),
  131. 'state' => array('shouldSetValue' => '1',
  132. 'type' => WorkflowActionAttributeForm::TYPE_STATIC,
  133. 'value' => $contactStates[0]->id),
  134. );
  135. $action->setAttributes(array(ActionForWorkflowForm::ACTION_ATTRIBUTES => $attributes));
  136. $workflow->addAction($action);
  137. //Create the saved Workflow
  138. $savedWorkflow = new SavedWorkflow();
  139. SavedWorkflowToWorkflowAdapter::resolveWorkflowToSavedWorkflow($workflow, $savedWorkflow);
  140. $saved = $savedWorkflow->save();
  141. $this->assertTrue($saved);
  142. $opportunity = OpportunityTestHelper::createOpportunityByNameForOwner('some opp', $super);
  143. $this->assertTrue($opportunity->id > 0);
  144. $this->assertEquals(0, $opportunity->contacts->count());
  145. //Change opportunity to Prospecting
  146. $opportunity->stage->value = 'Prospecting';
  147. $this->assertTrue(WorkflowTriggersUtil::areTriggersTrueBeforeSave($workflow, $opportunity));
  148. $saved = $opportunity->save();
  149. $this->assertTrue($saved);
  150. $this->assertEquals(1, $opportunity->contacts->count());
  151. $this->assertEquals('smith', $opportunity->contacts[0]->lastName);
  152. }
  153. public function testAWorkflowProcess()
  154. {
  155. //todo: write a full set of tests to document workflow
  156. }
  157. public function testUpdateRelatedCatalogItemOnAProductBySellPriceCriteria()
  158. {
  159. $super = User::getByUsername('super');
  160. $contactStates = ContactState::getAll();
  161. //Create workflow
  162. $workflow = new Workflow();
  163. $workflow->setDescription ('aDescription');
  164. $workflow->setIsActive (true);
  165. $workflow->setOrder (1);
  166. $workflow->setModuleClassName('ProductsModule');
  167. $workflow->setName ('myFirstProductWorkflow');
  168. $workflow->setTriggerOn (Workflow::TRIGGER_ON_NEW_AND_EXISTING);
  169. $workflow->setType (Workflow::TYPE_ON_SAVE);
  170. $workflow->setTriggersStructure('1');
  171. //Add Trigger
  172. $trigger = new TriggerForWorkflowForm('ProductsModule', 'Product', Workflow::TYPE_ON_SAVE);
  173. $trigger->attributeIndexOrDerivedType = 'sellPrice';
  174. $trigger->value = 600;
  175. $trigger->operator = 'greaterThanOrEqualTo';
  176. $workflow->addTrigger($trigger);
  177. //Add action
  178. $currencies = Currency::getAll();
  179. $action = new ActionForWorkflowForm('Product', Workflow::TYPE_ON_SAVE);
  180. $action->type = ActionForWorkflowForm::TYPE_UPDATE_RELATED;
  181. $action->relation = 'productTemplate';
  182. $attributes = array( 'description' => array('shouldSetValue' => '1',
  183. 'type' => WorkflowActionAttributeForm::TYPE_STATIC,
  184. 'value' => 'Set Price'),
  185. 'priceFrequency' => array('shouldSetValue' => '1',
  186. 'type' => WorkflowActionAttributeForm::TYPE_STATIC,
  187. 'value' => 2),
  188. 'listPrice' => array('shouldSetValue' => '1',
  189. 'type' => WorkflowActionAttributeForm::TYPE_STATIC,
  190. 'value' => 800,
  191. 'currencyId' => $currencies[0]->id),
  192. 'cost' => array('shouldSetValue' => '1',
  193. 'type' => WorkflowActionAttributeForm::TYPE_STATIC,
  194. 'value' => 700,
  195. 'currencyId' => $currencies[0]->id),
  196. );
  197. $action->setAttributes(array(ActionForWorkflowForm::ACTION_ATTRIBUTES => $attributes));
  198. $workflow->addAction($action);
  199. //Create the saved Workflow
  200. $savedWorkflow = new SavedWorkflow();
  201. SavedWorkflowToWorkflowAdapter::resolveWorkflowToSavedWorkflow($workflow, $savedWorkflow);
  202. $saved = $savedWorkflow->save();
  203. $this->assertTrue($saved);
  204. $productTemplate = ProductTemplateTestHelper::createProductTemplateByName('superProductTemplate');
  205. $productTemplates = ProductTemplate::getByName('superProductTemplate');
  206. $product = ProductTestHelper::createProductByNameForOwner('Test Product', $super);
  207. $this->assertTrue($product->id > 0);
  208. $product->productTemplate = $productTemplates[0];
  209. //Change product sell price
  210. $product->sellPrice->value = 650;
  211. $this->assertTrue(WorkflowTriggersUtil::areTriggersTrueBeforeSave($workflow, $product));
  212. $saved = $product->save();
  213. $this->assertTrue($saved);
  214. $productId = $product->id;
  215. $product->forget();
  216. $product = Product::getById($productId);
  217. $this->assertEquals('Set Price', $product->productTemplate->description);
  218. $this->assertEquals(2, $product->productTemplate->priceFrequency);
  219. $this->assertEquals(700, $product->productTemplate->cost->value);
  220. $this->assertEquals(800, $product->productTemplate->listPrice->value);
  221. }
  222. /**
  223. * Tests that a bug involving createdByUser is resolved. The issue was that createdByUser is not set until
  224. * after the workflow observer is called beforeSave. This behavior was changed and now this test passes
  225. */
  226. public function testProcessBeforeSaveOnCreatedByUserEquals()
  227. {
  228. Yii::app()->user->userModel = User::getByUsername('super');
  229. //Create workflow
  230. $workflow = new Workflow();
  231. $workflow->setDescription ('aDescription');
  232. $workflow->setIsActive (true);
  233. $workflow->setOrder (5);
  234. $workflow->setModuleClassName('AccountsModule');
  235. $workflow->setName ('myFirstWorkflow');
  236. $workflow->setTriggerOn (Workflow::TRIGGER_ON_NEW_AND_EXISTING);
  237. $workflow->setType (Workflow::TYPE_ON_SAVE);
  238. $workflow->setTriggersStructure('1');
  239. //Add trigger
  240. $trigger = new TriggerForWorkflowForm('AccountsTestModule', 'Account', $workflow->getType());
  241. $trigger->attributeIndexOrDerivedType = 'createdByUser';
  242. $trigger->value = Yii::app()->user->userModel->id;
  243. $trigger->operator = 'equals';
  244. $workflow->addTrigger($trigger);
  245. //Add action
  246. $action = new ActionForWorkflowForm('Account', Workflow::TYPE_ON_SAVE);
  247. $action->type = ActionForWorkflowForm::TYPE_UPDATE_SELF;
  248. $attributes = array('name' => array('shouldSetValue' => '1',
  249. 'type' => WorkflowActionAttributeForm::TYPE_STATIC,
  250. 'value' => 'jason'));
  251. $action->setAttributes(array(ActionForWorkflowForm::ACTION_ATTRIBUTES => $attributes));
  252. $workflow->addAction($action);
  253. //Create the saved Workflow
  254. $savedWorkflow = new SavedWorkflow();
  255. SavedWorkflowToWorkflowAdapter::resolveWorkflowToSavedWorkflow($workflow, $savedWorkflow);
  256. $saved = $savedWorkflow->save();
  257. $this->assertTrue($saved);
  258. //Confirm that the workflow processes and the attribute gets updated
  259. $model = new Account();
  260. $model->name = 'aValue';
  261. $this->assertTrue($model->save());
  262. $this->assertEquals('jason', $model->name);
  263. }
  264. /**
  265. * A test to show that the modifiedByUser works ok as a trigger with 'equals' on a newly created model.
  266. * @see testProcessBeforeSaveOnCreatedByUserEquals
  267. */
  268. public function testProcessBeforeSaveOnModifiedByUserEquals()
  269. {
  270. Yii::app()->user->userModel = User::getByUsername('super');
  271. //Create workflow
  272. $workflow = new Workflow();
  273. $workflow->setDescription ('aDescription');
  274. $workflow->setIsActive (true);
  275. $workflow->setOrder (5);
  276. $workflow->setModuleClassName('AccountsModule');
  277. $workflow->setName ('myFirstWorkflow');
  278. $workflow->setTriggerOn (Workflow::TRIGGER_ON_NEW_AND_EXISTING);
  279. $workflow->setType (Workflow::TYPE_ON_SAVE);
  280. $workflow->setTriggersStructure('1');
  281. //Add trigger
  282. $trigger = new TriggerForWorkflowForm('AccountsTestModule', 'Account', $workflow->getType());
  283. $trigger->attributeIndexOrDerivedType = 'modifiedByUser';
  284. $trigger->value = Yii::app()->user->userModel->id;
  285. $trigger->operator = 'equals';
  286. $workflow->addTrigger($trigger);
  287. //Add action
  288. $action = new ActionForWorkflowForm('Account', Workflow::TYPE_ON_SAVE);
  289. $action->type = ActionForWorkflowForm::TYPE_UPDATE_SELF;
  290. $attributes = array('name' => array('shouldSetValue' => '1',
  291. 'type' => WorkflowActionAttributeForm::TYPE_STATIC,
  292. 'value' => 'jason'));
  293. $action->setAttributes(array(ActionForWorkflowForm::ACTION_ATTRIBUTES => $attributes));
  294. $workflow->addAction($action);
  295. //Create the saved Workflow
  296. $savedWorkflow = new SavedWorkflow();
  297. SavedWorkflowToWorkflowAdapter::resolveWorkflowToSavedWorkflow($workflow, $savedWorkflow);
  298. $saved = $savedWorkflow->save();
  299. $this->assertTrue($saved);
  300. //Confirm that the workflow processes and the attribute gets updated
  301. $model = new Account();
  302. $model->name = 'aValue';
  303. $this->assertTrue($model->save());
  304. $this->assertEquals('jason', $model->name);
  305. }
  306. /**
  307. * Tests subscribing a contact to a marketing list
  308. */
  309. public function testSubscribeToListAction()
  310. {
  311. Yii::app()->user->userModel = User::getByUsername('super');
  312. //Create marketing list
  313. $marketingList = MarketingListTestHelper::createMarketingListByName('testList');
  314. $marketingListId = $marketingList->id;
  315. $this->assertEquals(0, $marketingList->marketingListMembers->count());
  316. //Create workflow
  317. $workflow = new Workflow();
  318. $workflow->setDescription ('aDescription');
  319. $workflow->setIsActive (true);
  320. $workflow->setOrder (5);
  321. $workflow->setModuleClassName('ContactsModule');
  322. $workflow->setName ('myFirstWorkflow');
  323. $workflow->setTriggerOn (Workflow::TRIGGER_ON_NEW_AND_EXISTING);
  324. $workflow->setType (Workflow::TYPE_ON_SAVE);
  325. $workflow->setTriggersStructure('1');
  326. //Add action
  327. $action = new ActionForWorkflowForm('Contact', Workflow::TYPE_ON_SAVE);
  328. $action->type = ActionForWorkflowForm::TYPE_SUBSCRIBE_TO_LIST;
  329. $attributes = array('marketingList' => array(
  330. 'type' => WorkflowActionAttributeForm::TYPE_STATIC,
  331. 'value' => $marketingListId));
  332. $action->setAttributes(array(ActionForWorkflowForm::ACTION_ATTRIBUTES => $attributes));
  333. $workflow->addAction($action);
  334. //Create the saved Workflow
  335. $savedWorkflow = new SavedWorkflow();
  336. SavedWorkflowToWorkflowAdapter::resolveWorkflowToSavedWorkflow($workflow, $savedWorkflow);
  337. $saved = $savedWorkflow->save();
  338. $this->assertTrue($saved);
  339. //Confirm that the workflow processes and the contact gets updated
  340. $contact = ContactTestHelper::createContactByNameForOwner('jason', Yii::app()->user->userModel);
  341. $marketingList->forget();
  342. $marketingList = MarketingList::getById($marketingListId);
  343. $this->assertEquals(1, $marketingList->marketingListMembers->count());
  344. $this->assertEquals(0, $marketingList->marketingListMembers[0]->unsubscribed);
  345. }
  346. /**
  347. * Tests that a bug involving creating a required custom picklist on projects causes the workflow
  348. * to break when creating a task
  349. */
  350. public function testProcessWorkflowForTaskWhenProjectAsARequiredCustomPicklist()
  351. {
  352. Yii::app()->user->userModel = User::getByUsername('super');
  353. //Create a required picklist for projects
  354. ModulesSearchWithDataProviderTestHelper::createDropDownAttribute(new Project(), 'pick', true);
  355. //Create workflow
  356. $workflow = new Workflow();
  357. $workflow->setDescription ('aDescription');
  358. $workflow->setIsActive (true);
  359. $workflow->setOrder (5);
  360. $workflow->setModuleClassName('TasksModule');
  361. $workflow->setName ('myFirstWorkflow');
  362. $workflow->setTriggerOn (Workflow::TRIGGER_ON_NEW_AND_EXISTING);
  363. $workflow->setType (Workflow::TYPE_BY_TIME);
  364. $workflow->setTriggersStructure('1');
  365. //Add trigger
  366. $trigger = new TimeTriggerForWorkflowForm('TasksModule', 'Task', $workflow->getType());
  367. $trigger->attributeIndexOrDerivedType = 'dueDateTime';
  368. $trigger->valueType = MixedDateTypesSearchFormAttributeMappingRules::TYPE_IS_TIME_FOR;
  369. $trigger->durationInterval = 5;
  370. $trigger->durationType = TimeDurationUtil::DURATION_TYPE_MONTH;
  371. $trigger->durationSign = TimeDurationUtil::DURATION_SIGN_NEGATIVE;
  372. $workflow->setTimeTrigger($trigger);
  373. //Create the saved Workflow
  374. $savedWorkflow = new SavedWorkflow();
  375. SavedWorkflowToWorkflowAdapter::resolveWorkflowToSavedWorkflow($workflow, $savedWorkflow);
  376. $saved = $savedWorkflow->save();
  377. $this->assertTrue($saved);
  378. //Confirm that the workflow processes
  379. $model = new Task();
  380. $model->name = 'aTask';
  381. $model->dueDateTime = DateTimeUtil::convertTimestampToDbFormatDateTime(time());
  382. $this->assertTrue($model->save());
  383. }
  384. }
  385. ?>