@@ -86,6 +86,162 @@ protected function tearDown(): void {
8686 $ plugingenerator ->teardown ();
8787 }
8888
89+ /**
90+ * Test rulestemplate on option being completed for user.
91+ *
92+ * @covers \mod_booking\option\fields\competencies
93+ *
94+ * @param array $bdata
95+ * @throws \coding_exception
96+ *
97+ * @dataProvider booking_common_settings_provider
98+ * @runInSeparateProcess
99+ */
100+ public function test_assign_competency_on_option_completion_using_task_for_completion (array $ bdata ): void {
101+ global $ DB , $ CFG ;
102+
103+ [$ user1 , $ user2 , $ booking , $ course , $ competency , $ competency2 ] = $ this ->betty_best_base ($ bdata );
104+ $ sink = $ this ->redirectEmails ();
105+ /** @var mod_booking_generator $plugingenerator */
106+ $ plugingenerator = self ::getDataGenerator ()->get_plugin_generator ('mod_booking ' );
107+ $ lock = $ this ->createMock (\core \lock \lock::class);
108+ $ cronlock = $ this ->createMock (\core \lock \lock::class);
109+ // Create booking option 1.
110+ $ record = new stdClass ();
111+ $ record ->bookingid = $ booking ->id ;
112+ $ record ->text = 'football ' ;
113+ $ record ->chooseorcreatecourse = 1 ; // Connected existing course.
114+ $ record ->courseid = $ course ->id ;
115+ $ record ->description = 'Will start tomorrow ' ;
116+ $ record ->optiondateid_0 = "0 " ;
117+ $ record ->daystonotify_0 = "0 " ;
118+ $ record ->coursestarttime_0 = strtotime ('20 June 2050 15:00 ' );
119+ $ record ->courseendtime_0 = strtotime ('20 July 2050 14:00 ' );
120+ $ record ->teachersforoption = $ user1 ->username ;
121+ $ record ->teachersforoption = 0 ;
122+ $ record ->competencies = [$ competency ->get ('id ' ), $ competency2 ->get ('id ' )];
123+ $ option1 = $ plugingenerator ->create_option ($ record );
124+
125+ singleton_service::destroy_instance ();
126+
127+ $ assignments = $ DB ->get_records ('local_taskflow_assignment ' , ['userid ' => $ user2 ->id ]);
128+ $ this ->assertCount (1 , $ assignments );
129+ $ assignment = array_shift ($ assignments );
130+ $ this ->assertSame ((int )$ assignment ->status , assignment_status_facade::get_status_identifier ('assigned ' ));
131+
132+ // Count should be 1 - assigned.
133+ $ initialcount = count ($ assignmenthistory = $ DB ->get_records ('local_taskflow_history ' , ['assignmentid ' => $ assignment ->id ]));
134+ $ this ->assertSame (1 , $ initialcount );
135+ time_mock::set_mock_time (strtotime ('+ 6 minutes ' , time ()));
136+ $ plugingeneratortf = self ::getDataGenerator ()->get_plugin_generator ('local_taskflow ' );
137+ $ plugingeneratortf ->runtaskswithintime ($ cronlock , $ lock , time ());
138+
139+ // Assigned + assigned mail.
140+ $ countafter = count ($ assignmenthistory = $ DB ->get_records ('local_taskflow_history ' , ['assignmentid ' => $ assignment ->id ]));
141+ $ this ->assertSame ($ initialcount + 1 , $ countafter );
142+
143+ // Create a booking option answer - book user2.
144+ $ result = $ plugingenerator ->create_answer (['optionid ' => $ option1 ->id , 'userid ' => $ user2 ->id ]);
145+
146+ $ this ->assertSame (MOD_BOOKING_BO_COND_ALREADYBOOKED , $ result );
147+ singleton_service::destroy_instance ();
148+
149+ // Complete booking option for user2.
150+ $ settings = singleton_service::get_instance_of_booking_option_settings ($ option1 ->id );
151+ $ option = singleton_service::get_instance_of_booking_option ($ settings ->cmid , $ settings ->id );
152+
153+ $ assignments = $ DB ->get_records ('local_taskflow_assignment ' , ['userid ' => $ user2 ->id ]);
154+ $ this ->assertCount (1 , $ assignments );
155+ $ assignment = array_shift ($ assignments );
156+ // We dont exclude enrolled in this project.
157+ $ this ->assertSame ((int )$ assignment ->status , assignment_status_facade::get_status_identifier ('enrolled ' ));
158+
159+ $ plugingenerator = self ::getDataGenerator ()->get_plugin_generator ('local_taskflow ' );
160+ $ plugingenerator ->runtaskswithintime ($ cronlock , $ lock , time ());
161+
162+ // Should be assigned + assigned msg + enrolled + booking course enrol1 + booking course enrol2.
163+ $ countafter = count ($ assignmenthistory = $ DB ->get_records ('local_taskflow_history ' , ['assignmentid ' => $ assignment ->id ]));
164+ $ this ->assertSame ($ initialcount + 4 , $ countafter );
165+
166+ $ sentmessages = $ DB ->get_records ('local_taskflow_sent_messages ' , ['userid ' => $ user2 ->id ]);
167+ // Assignment mail should be sent.
168+ $ this ->assertCount (1 , $ sentmessages );
169+ $ messagesink = array_filter ($ sink ->get_messages (), function ($ message ) {
170+ return strpos ($ message ->subject , 'Taskflow - ' ) === 0 ;
171+ });
172+ $ messagesinkuser2 = array_filter ($ messagesink , function ($ msg ) use ($ user2 ) {
173+ return $ msg ->to === $ user2 ->email ;
174+ });
175+ $ this ->assertCount (1 , $ messagesinkuser2 );
176+ $ this ->assertCount (3 , $ messagesink );
177+
178+ $ this ->assertSame (0 , $ option ->user_completed_option ());
179+
180+ // setUser_completion now uses a task to complete the option.
181+ $ this ->setUser ($ user2 );
182+ $ option ->toggle_user_completion ($ user2 ->id );
183+
184+ // Run all adhoc tasks now.
185+ $ plugingenerator ->runtaskswithintime ($ cronlock , $ lock , time ());
186+
187+ // Should be assigned + assigned msg + enrolled + booking course enrol1
188+ // + booking course enrol2 + completed status + comp1 completed + comp2 completed.
189+ $ countafter = count ($ assignmenthistory = $ DB ->get_records ('local_taskflow_history ' , ['assignmentid ' => $ assignment ->id ]));
190+ $ this ->assertSame ($ initialcount + 7 , $ countafter );
191+
192+ $ plugingenerator ->runtaskswithintime ($ cronlock , $ lock , time ());
193+
194+ require_once ($ CFG ->dirroot . '/user/lib.php ' );
195+ user_update_user ((object )[
196+ 'id ' => $ user2 ->id ,
197+ 'firstname ' => 'UpdatedFirstName ' ,
198+ 'lastname ' => 'UpdatedLastName ' ,
199+ ]);
200+
201+ // Should be assigned + assigned msg.
202+ $ countafter = count ($ assignmenthistory = $ DB ->get_records ('local_taskflow_history ' , ['assignmentid ' => $ assignment ->id ]));
203+ $ this ->assertSame ($ initialcount + 7 , $ countafter );
204+
205+ $ this ->assertSame (1 , $ option ->user_completed_option ());
206+ $ assignments = $ DB ->get_records ('local_taskflow_assignment ' , ['userid ' => $ user2 ->id ]);
207+ $ this ->assertCount (1 , $ assignments );
208+ $ assignment = array_shift ($ assignments );
209+ $ this ->assertSame ((int )$ assignment ->status , assignment_status_facade::get_status_identifier ('completed ' ));
210+ $ sentmessages = $ DB ->get_records ('local_taskflow_sent_messages ' , ['userid ' => $ user2 ->id ]);
211+ // Should have no msg.
212+ $ this ->assertCount (1 , $ sentmessages );
213+ $ messagesink = array_filter ($ sink ->get_messages (), function ($ message ) {
214+ return strpos ($ message ->subject , 'Taskflow - ' ) === 0 ;
215+ });
216+ $ messagesinkuser2 = array_filter ($ messagesink , function ($ msg ) use ($ user2 ) {
217+ return $ msg ->to === $ user2 ->email ;
218+ });
219+ $ this ->assertCount (1 , $ sentmessages );
220+ $ this ->assertCount (1 , $ messagesinkuser2 );
221+ $ this ->assertCount (3 , $ messagesink );
222+
223+ // Some time passes, we trigger the rule again, status should be unchanged.
224+ time_mock::set_mock_time (strtotime ('+ 6 minutes ' , time ()));
225+
226+ $ rule = (array )$ DB ->get_record ('local_taskflow_rules ' , []);
227+
228+ // Run all adhoc tasks now.
229+ $ event = rule_created_updated::create ([
230+ 'objectid ' => $ rule ['id ' ],
231+ 'context ' => context_system::instance (),
232+ 'other ' => [
233+ 'ruledata ' => $ rule ,
234+ ],
235+ ]);
236+ $ event ->trigger ();
237+ $ plugingenerator ->runtaskswithintime ($ cronlock , $ lock , time ());
238+
239+ $ assignments = $ DB ->get_records ('local_taskflow_assignment ' , ['userid ' => $ user2 ->id ]);
240+ $ this ->assertCount (1 , $ assignments );
241+ $ assignment = array_shift ($ assignments );
242+ $ this ->assertSame ((int )$ assignment ->status , assignment_status_facade::get_status_identifier ('completed ' ));
243+ }
244+
89245
90246 /**
91247 * Test rulestemplate on option being completed for user.
@@ -96,6 +252,7 @@ protected function tearDown(): void {
96252 * @throws \coding_exception
97253 *
98254 * @dataProvider booking_common_settings_provider
255+ * @runInSeparateProcess
99256 */
100257 public function test_assign_competency_on_option_completion (array $ bdata ): void {
101258 global $ DB , $ CFG ;
@@ -248,6 +405,7 @@ public function test_assign_competency_on_option_completion(array $bdata): void
248405 * @throws \coding_exception
249406 *
250407 * @dataProvider booking_common_settings_provider
408+ * @runInSeparateProcess
251409 */
252410 public function test_betty_best_user_update_after_partial_completion (array $ bdata ): void {
253411 global $ DB , $ CFG ;
0 commit comments