@@ -345,3 +345,118 @@ def test_should_get_all(
345
345
sort_by = sort_by ,
346
346
)
347
347
assert list (quotations ) == [self .quotation ] * 4
348
+
349
+
350
+ class TestFeasibilityStudy :
351
+ FEASIBILITY_ID : str = FEASIBILITY_ID
352
+ ACCOUNT_ID : str = ACCOUNT_ID
353
+ WORKSPACE_ID : str = "workspace-id"
354
+ ORDER_ID : str = "test-order-id"
355
+ OPTION_ID : str = "option-123"
356
+
357
+ metadata : dict = {
358
+ "id" : FEASIBILITY_ID ,
359
+ "createdAt" : "created-at" ,
360
+ "updatedAt" : "updated-at" ,
361
+ "accountId" : ACCOUNT_ID ,
362
+ "workspaceId" : WORKSPACE_ID ,
363
+ "orderId" : ORDER_ID ,
364
+ "decision" : "NOT_DECIDED" ,
365
+ "options" : [{"id" : OPTION_ID }],
366
+ "decisionAt" : "decided-at" ,
367
+ }
368
+ feasibility_study = tasking .FeasibilityStudy (
369
+ id = FEASIBILITY_ID ,
370
+ created_at = "created-at" ,
371
+ updated_at = "updated-at" ,
372
+ account_id = ACCOUNT_ID ,
373
+ workspace_id = WORKSPACE_ID ,
374
+ order_id = ORDER_ID ,
375
+ decision = "NOT_DECIDED" ,
376
+ options = [{"id" : OPTION_ID }],
377
+ decided_at = "decided-at" ,
378
+ decision_option = None ,
379
+ )
380
+
381
+ @pytest .mark .parametrize ("feasibility_study_id" , [None , FEASIBILITY_ID ])
382
+ @pytest .mark .parametrize ("workspace_id" , [None , WORKSPACE_ID ])
383
+ @pytest .mark .parametrize ("order_id" , [None , ORDER_ID ])
384
+ @pytest .mark .parametrize ("decision" , [None , ["NOT_DECIDED" , "ACCEPTED" ], ["ACCEPTED" ]])
385
+ @pytest .mark .parametrize (
386
+ "sort_by" ,
387
+ [
388
+ None ,
389
+ tasking .FeasibilityStudySorting .created_at .asc ,
390
+ tasking .FeasibilityStudySorting .updated_at .asc ,
391
+ tasking .FeasibilityStudySorting .decided_at .asc ,
392
+ ],
393
+ ids = str ,
394
+ )
395
+ def test_should_get_all (
396
+ self ,
397
+ requests_mock : req_mock .Mocker ,
398
+ feasibility_study_id : Optional [str ],
399
+ workspace_id : Optional [str ],
400
+ order_id : Optional [str ],
401
+ decision : Optional [List [tasking .FeasibilityStatus ]],
402
+ sort_by : Optional [utils .SortingField ],
403
+ ):
404
+ query_params : dict [str , Any ] = {}
405
+ if feasibility_study_id :
406
+ query_params ["id" ] = feasibility_study_id
407
+ if workspace_id :
408
+ query_params ["workspaceId" ] = workspace_id
409
+ if order_id :
410
+ query_params ["orderId" ] = order_id
411
+ if decision :
412
+ query_params ["decision" ] = decision
413
+ if sort_by :
414
+ query_params ["sort" ] = str (sort_by )
415
+ base_url = f"{ constants .API_HOST } /v2/tasking/feasibility-studies"
416
+ expected = [self .metadata ] * 4
417
+ for page in [0 , 1 ]:
418
+ query_params ["page" ] = page
419
+ query = urllib .parse .urlencode (query_params , doseq = True , safe = "" )
420
+ url = base_url + (query and f"?{ query } " )
421
+ offset = page * 2
422
+ response = {
423
+ "content" : expected [offset : offset + 2 ], # noqa: E203
424
+ "totalPages" : 2 ,
425
+ }
426
+ requests_mock .get (url = url , json = response )
427
+ feasibility_studies = tasking .FeasibilityStudy .all (
428
+ feasibility_study_id = feasibility_study_id ,
429
+ workspace_id = workspace_id ,
430
+ order_id = order_id ,
431
+ decision = decision ,
432
+ sort_by = sort_by ,
433
+ )
434
+ assert list (feasibility_studies ) == [self .feasibility_study ] * 4
435
+
436
+ def test_should_accept (self ):
437
+ feasibility_study = dataclasses .replace (self .feasibility_study , decision_option = None )
438
+ feasibility_study .accept (self .OPTION_ID )
439
+ assert feasibility_study .decision_option .id == self .OPTION_ID # type: ignore[union-attr]
440
+
441
+ def test_should_save (self , requests_mock : req_mock .Mocker ):
442
+ feasibility_study = dataclasses .replace (self .feasibility_study , decision_option = None )
443
+ feasibility_study .accept (self .OPTION_ID )
444
+ patch = {"acceptedOptionId" : self .OPTION_ID }
445
+ url = f"{ constants .API_HOST } /v2/tasking/feasibility-studies/{ self .FEASIBILITY_ID } "
446
+ expected_description = "description"
447
+ expected_json = self .metadata | {"decisionOption" : {"id" : self .OPTION_ID , "description" : expected_description }}
448
+ requests_mock .patch (
449
+ url = url ,
450
+ json = expected_json ,
451
+ additional_matcher = helpers .match_request_body (patch ),
452
+ )
453
+ feasibility_study .save ()
454
+ assert feasibility_study .decision_option .id == self .OPTION_ID # type: ignore[union-attr]
455
+ assert feasibility_study .decision_option .description == expected_description # type: ignore[union-attr]
456
+
457
+ def test_should_raise_if_no_decision_option_on_save (self ):
458
+ feasibility_study = dataclasses .replace (self .feasibility_study , decision_option = None )
459
+ with pytest .raises (
460
+ feasibility_study .NoDecisionOptionChosen , match = "No decision option chosen for this feasibility study."
461
+ ):
462
+ feasibility_study .save ()
0 commit comments