@@ -225,9 +225,108 @@ def test_wizard_onchange_clears_mismatched_registrant(self):
225225 self .assertFalse (wizard .registrant_id )
226226
227227
228+ @tagged ("post_install" , "-at_install" , "cr_ux" )
229+ class TestBatchApprovalWizardBase (TestChangeRequestBase ):
230+ """Tests for batch approval wizard that don't require pending CRs."""
231+
232+ def _create_wizard (self , cr_ids , action_type = "approve" , ** kwargs ):
233+ """Helper to create a batch wizard via create_from_selection."""
234+ result = (
235+ self .env ["spp.cr.batch.approval.wizard" ].with_context (active_ids = cr_ids ).create_from_selection (action_type )
236+ )
237+ wizard = self .env ["spp.cr.batch.approval.wizard" ].browse (result ["res_id" ])
238+ if kwargs :
239+ wizard .write (kwargs )
240+ return wizard
241+
242+ def test_create_from_selection_no_active_ids (self ):
243+ """Test create_from_selection raises error with no active_ids."""
244+ with self .assertRaises (UserError ):
245+ self .env ["spp.cr.batch.approval.wizard" ].create_from_selection ("approve" )
246+
247+ def test_create_from_selection_returns_action (self ):
248+ """Test create_from_selection returns a valid window action."""
249+ cr_type = self .env ["spp.change.request.type" ].search ([], limit = 1 )
250+ if not cr_type :
251+ self .skipTest ("No CR type available" )
252+ draft_cr = self .env ["spp.change.request" ].create (
253+ {"request_type_id" : cr_type .id , "registrant_id" : self .group .id }
254+ )
255+ result = (
256+ self .env ["spp.cr.batch.approval.wizard" ]
257+ .with_context (active_ids = [draft_cr .id ])
258+ .create_from_selection ("approve" )
259+ )
260+ self .assertEqual (result ["type" ], "ir.actions.act_window" )
261+ self .assertEqual (result ["res_model" ], "spp.cr.batch.approval.wizard" )
262+ self .assertEqual (result ["target" ], "new" )
263+ self .assertTrue (result ["res_id" ])
264+
265+ def test_create_from_selection_action_types (self ):
266+ """Test create_from_selection sets action_type correctly."""
267+ cr_type = self .env ["spp.change.request.type" ].search ([], limit = 1 )
268+ if not cr_type :
269+ self .skipTest ("No CR type available" )
270+ draft_cr = self .env ["spp.change.request" ].create (
271+ {"request_type_id" : cr_type .id , "registrant_id" : self .group .id }
272+ )
273+ for action_type in ("approve" , "reject" , "revision" ):
274+ result = (
275+ self .env ["spp.cr.batch.approval.wizard" ]
276+ .with_context (active_ids = [draft_cr .id ])
277+ .create_from_selection (action_type )
278+ )
279+ wizard = self .env ["spp.cr.batch.approval.wizard" ].browse (result ["res_id" ])
280+ self .assertEqual (wizard .action_type , action_type )
281+
282+ def test_error_message_not_pending (self ):
283+ """Test error message for CR not in pending state."""
284+ cr_type = self .env ["spp.change.request.type" ].search ([], limit = 1 )
285+ if not cr_type :
286+ self .skipTest ("No CR type available" )
287+ draft_cr = self .env ["spp.change.request" ].create (
288+ {"request_type_id" : cr_type .id , "registrant_id" : self .group .id }
289+ )
290+ wizard = self ._create_wizard ([draft_cr .id ])
291+ line = wizard .line_ids [0 ]
292+ self .assertFalse (line .can_process )
293+ self .assertIn ("Not pending approval" , line .error_message )
294+
295+ def test_batch_approve_requires_valid_crs (self ):
296+ """Test batch approve fails if no valid CRs."""
297+ cr_type = self .env ["spp.change.request.type" ].search ([], limit = 1 )
298+ if not cr_type :
299+ self .skipTest ("No CR type available" )
300+ draft_cr = self .env ["spp.change.request" ].create (
301+ {"request_type_id" : cr_type .id , "registrant_id" : self .group .id }
302+ )
303+ wizard = self ._create_wizard ([draft_cr .id ])
304+ self .assertEqual (wizard .valid_count , 0 )
305+ with self .assertRaises (UserError ):
306+ wizard .action_confirm ()
307+
308+ def test_batch_wizard_line_removal (self ):
309+ """Test that lines can be removed from a saved wizard."""
310+ cr_type = self .env ["spp.change.request.type" ].search ([], limit = 1 )
311+ if not cr_type :
312+ self .skipTest ("No CR type available" )
313+ crs = self .env ["spp.change.request" ]
314+ for _i in range (3 ):
315+ crs |= self .env ["spp.change.request" ].create (
316+ {"request_type_id" : cr_type .id , "registrant_id" : self .group .id }
317+ )
318+ wizard = self ._create_wizard (crs .ids )
319+ self .assertEqual (len (wizard .line_ids ), 3 )
320+
321+ # Remove one line
322+ wizard .line_ids [0 ].unlink ()
323+ wizard .invalidate_recordset ()
324+ self .assertEqual (len (wizard .line_ids ), 2 )
325+
326+
228327@tagged ("post_install" , "-at_install" , "cr_ux" )
229328class TestBatchApprovalWizard (TestChangeRequestBase ):
230- """Tests for the batch approval wizard."""
329+ """Tests for batch approval wizard that require pending CRs ."""
231330
232331 @classmethod
233332 def setUpClass (cls ):
@@ -237,7 +336,6 @@ def setUpClass(cls):
237336
238337 def setUp (self ):
239338 super ().setUp ()
240- # Create multiple pending CRs for batch testing
241339 cr_type = self .env ["spp.change.request.type" ].search ([("approval_definition_id" , "!=" , False )], limit = 1 )
242340
243341 if not cr_type :
@@ -254,56 +352,57 @@ def setUp(self):
254352 cr .action_submit_for_approval ()
255353 self .pending_crs |= cr
256354
355+ def _create_wizard (self , cr_ids , action_type = "approve" , ** kwargs ):
356+ """Helper to create a batch wizard via create_from_selection."""
357+ result = (
358+ self .env ["spp.cr.batch.approval.wizard" ].with_context (active_ids = cr_ids ).create_from_selection (action_type )
359+ )
360+ wizard = self .env ["spp.cr.batch.approval.wizard" ].browse (result ["res_id" ])
361+ if kwargs :
362+ wizard .write (kwargs )
363+ return wizard
364+
257365 def test_batch_wizard_initialization (self ):
258366 """Test batch wizard initializes with selected CRs."""
259- wizard = self .env [ "spp.cr.batch.approval.wizard" ]. with_context ( active_ids = self .pending_crs .ids ). create ({} )
367+ wizard = self ._create_wizard ( self .pending_crs .ids )
260368
261369 self .assertEqual (wizard .total_count , 3 )
262370 self .assertEqual (len (wizard .line_ids ), 3 )
263371
264372 def test_batch_wizard_counts (self ):
265373 """Test batch wizard computes valid/invalid counts correctly."""
266- wizard = self .env [ "spp.cr.batch.approval.wizard" ]. with_context ( active_ids = self .pending_crs .ids ). create ({} )
374+ wizard = self ._create_wizard ( self .pending_crs .ids )
267375
268376 # All should be valid if user can approve
269377 self .assertEqual (wizard .total_count , wizard .valid_count + wizard .invalid_count )
270378
271- def test_batch_approve_requires_valid_crs (self ):
272- """Test batch approve fails if no valid CRs."""
273- # Create wizard with draft CR (cannot be approved)
274- cr_type = self .env ["spp.change.request.type" ].search ([], limit = 1 )
275- draft_cr = self .env ["spp.change.request" ].create (
276- {
277- "request_type_id" : cr_type .id ,
278- "registrant_id" : self .group .id ,
279- }
280- )
281-
282- wizard = self .env ["spp.cr.batch.approval.wizard" ].with_context (active_ids = [draft_cr .id ]).create ({})
283-
284- # Should have 0 valid CRs
285- self .assertEqual (wizard .valid_count , 0 )
379+ def test_batch_reject_requires_comment (self ):
380+ """Test batch reject requires a reason."""
381+ wizard = self ._create_wizard (self .pending_crs .ids , action_type = "reject" , comment = "" )
286382
383+ # Should fail without comment
287384 with self .assertRaises (UserError ):
288385 wizard .action_confirm ()
289386
290- def test_batch_reject_requires_comment (self ):
291- """Test batch reject requires a reason."""
292- wizard = (
293- self .env ["spp.cr.batch.approval.wizard" ]
294- .with_context (active_ids = self .pending_crs .ids )
295- .create (
296- {
297- "action_type" : "reject" ,
298- "comment" : "" ,
299- }
300- )
301- )
387+ def test_batch_revision_requires_comment (self ):
388+ """Test batch revision requires notes."""
389+ wizard = self ._create_wizard (self .pending_crs .ids , action_type = "revision" , comment = "" )
302390
303- # Should fail without comment
304391 with self .assertRaises (UserError ):
305392 wizard .action_confirm ()
306393
394+ def test_error_message_mixed_crs (self ):
395+ """Test error messages with mix of pending and draft CRs."""
396+ cr_type = self .env ["spp.change.request.type" ].search ([], limit = 1 )
397+ draft_cr = self .env ["spp.change.request" ].create (
398+ {"request_type_id" : cr_type .id , "registrant_id" : self .group .id }
399+ )
400+ wizard = self ._create_wizard (self .pending_crs .ids + [draft_cr .id ])
401+ self .assertTrue (wizard .total_count > 0 )
402+ invalid_lines = wizard .line_ids .filtered (lambda ln : not ln .can_process )
403+ for line in invalid_lines :
404+ self .assertTrue (line .error_message )
405+
307406
308407@tagged ("post_install" , "-at_install" , "cr_ux" )
309408class TestConflictComparisonWizard (TestChangeRequestBase ):
0 commit comments