From 2d3757a785b7b9cd668aaaaa1df42e44abce14b8 Mon Sep 17 00:00:00 2001 From: jules cicurel <180195494+jcicurel-pass@users.noreply.github.com> Date: Fri, 27 Dec 2024 12:41:49 +0100 Subject: [PATCH] (PC-33734)[API] feat: turn on ENABLE_COLLECTIVE_NEW_STATUSES FF by default --- api/src/pcapi/core/educational/models.py | 2 +- api/src/pcapi/core/educational/repository.py | 6 +- api/src/pcapi/models/feature.py | 1 - api/src/pcapi/routes/pro/collective_stocks.py | 2 + .../api/test_edit_collective_offer_stock.py | 7 ++ api/tests/core/educational/test_models.py | 10 ++ api/tests/core/offers/test_repository.py | 3 + ...ch_cancel_collective_offer_booking_test.py | 2 +- .../routes/pro/patch_collective_offer_test.py | 111 +++++++----------- ...ch_collective_offers_active_status_test.py | 18 +-- .../patch_collective_offers_archive_test.py | 4 + ...ive_offers_educational_institution_test.py | 16 +-- .../routes/pro/patch_collective_stock_test.py | 63 +++++----- ...plicate_collective_offer_and_stock_test.py | 4 +- 14 files changed, 120 insertions(+), 129 deletions(-) diff --git a/api/src/pcapi/core/educational/models.py b/api/src/pcapi/core/educational/models.py index 4a7cfd90471..044e6441590 100644 --- a/api/src/pcapi/core/educational/models.py +++ b/api/src/pcapi/core/educational/models.py @@ -519,7 +519,7 @@ class CollectiveOffer( server_default="{}", ) - collectiveStock: "CollectiveStock" = relationship( + collectiveStock: sa_orm.Mapped["CollectiveStock"] = relationship( "CollectiveStock", back_populates="collectiveOffer", uselist=False ) diff --git a/api/src/pcapi/core/educational/repository.py b/api/src/pcapi/core/educational/repository.py index 5318479b8a7..6f57c3c8dd6 100644 --- a/api/src/pcapi/core/educational/repository.py +++ b/api/src/pcapi/core/educational/repository.py @@ -491,8 +491,10 @@ def get_collective_stock(collective_stock_id: int) -> educational_models.Collect return ( educational_models.CollectiveStock.query.filter(educational_models.CollectiveStock.id == collective_stock_id) .options( - sa.orm.joinedload(educational_models.CollectiveStock.collectiveOffer).joinedload( - educational_models.CollectiveOffer.venue + sa.orm.joinedload(educational_models.CollectiveStock.collectiveOffer).options( + # needed to avoid a query when we call stock.collectiveOffer.collectiveStock + sa.orm.contains_eager(educational_models.CollectiveOffer.collectiveStock), + sa.orm.joinedload(educational_models.CollectiveOffer.venue), ), sa.orm.joinedload(educational_models.CollectiveStock.collectiveBookings), ) diff --git a/api/src/pcapi/models/feature.py b/api/src/pcapi/models/feature.py index c8f85f7469f..ed51a170db5 100644 --- a/api/src/pcapi/models/feature.py +++ b/api/src/pcapi/models/feature.py @@ -175,7 +175,6 @@ def nameKey(self) -> str: FeatureToggle.ENABLE_BANK_ACCOUNT_SYNC, FeatureToggle.ENABLE_BEAMER, FeatureToggle.ENABLE_CODIR_OFFERERS_REPORT, # only for production - FeatureToggle.ENABLE_COLLECTIVE_NEW_STATUSES, FeatureToggle.ENABLE_CRON_TO_UPDATE_OFFERER_STATS, # only for production FeatureToggle.ENABLE_CULTURAL_SURVEY, FeatureToggle.ENABLE_DMS_LINK_ON_MAINTENANCE_PAGE_FOR_AGE_18, diff --git a/api/src/pcapi/routes/pro/collective_stocks.py b/api/src/pcapi/routes/pro/collective_stocks.py index 940e4fe8c03..43ba2a53dd9 100644 --- a/api/src/pcapi/routes/pro/collective_stocks.py +++ b/api/src/pcapi/routes/pro/collective_stocks.py @@ -80,6 +80,8 @@ def edit_collective_stock( return collective_stock_serialize.CollectiveStockResponseModel.from_orm(collective_stock) except educational_exceptions.CollectiveOfferIsPublicApi: raise ApiErrors({"global": ["Les stocks créés par l'api publique ne sont pas editables."]}, 403) + except educational_exceptions.CollectiveOfferForbiddenAction: + raise ApiErrors({"global": ["Cette action n'est pas autorisée sur l'offre collective liée à ce stock."]}, 403) except offers_exceptions.BookingLimitDatetimeTooLate: raise ApiErrors( {"educationalStock": ["La date limite de confirmation ne peut être fixée après la date de l évènement"]}, diff --git a/api/tests/core/educational/api/test_edit_collective_offer_stock.py b/api/tests/core/educational/api/test_edit_collective_offer_stock.py index 1ffacff2899..2d8f4ea0444 100644 --- a/api/tests/core/educational/api/test_edit_collective_offer_stock.py +++ b/api/tests/core/educational/api/test_edit_collective_offer_stock.py @@ -194,6 +194,7 @@ def test_should_replace_bookingLimitDatetime_with_old_event_datetime_if_provided # stock = CollectiveStock.query.filter_by(id=stock_to_be_updated.id).one() # mocked_async_index_offer_ids.assert_called_once_with([stock.collectiveOfferId]) + @override_features(ENABLE_COLLECTIVE_NEW_STATUSES=False) def test_should_not_allow_stock_edition_when_booking_status_is_REIMBURSED_or_USED(self) -> None: # Given educational_factories.EducationalYearFactory( @@ -285,6 +286,7 @@ def should_update_bookings_cancellation_limit_date_if_beginningDatetime_earlier( booking_updated = CollectiveBooking.query.filter_by(id=booking.id).one() assert booking_updated.cancellationLimitDate == datetime.datetime.utcnow() + @override_features(ENABLE_COLLECTIVE_NEW_STATUSES=False) @time_machine.travel("2020-11-17 15:00:00") def test_should_allow_stock_edition_and_not_modify_cancellation_limit_date_when_booking_cancelled(self) -> None: # Given @@ -474,6 +476,7 @@ def test_can_lower_price_and_edit_price_details_ended(self): @pytest.mark.usefixtures("db_session") class ReturnErrorTest: + @override_features(ENABLE_COLLECTIVE_NEW_STATUSES=False) def test_edit_stock_of_non_approved_offer_fails(self) -> None: # Given offer = educational_factories.CollectiveOfferFactory(validation=OfferValidationStatus.PENDING) @@ -547,6 +550,7 @@ def test_should_not_allow_stock_edition_when_bookingLimitDatetime_not_provided_a stock = CollectiveStock.query.filter_by(id=stock_to_be_updated.id).one() assert stock.beginningDatetime == datetime.datetime(2021, 12, 10) + @override_features(ENABLE_COLLECTIVE_NEW_STATUSES=False) @time_machine.travel("2020-11-17 15:00:00") def test_should_allow_stock_edition_and_not_modify_cancellation_limit_date_when_booking_cancelled(self) -> None: # Given @@ -586,6 +590,7 @@ def test_should_allow_stock_edition_and_not_modify_cancellation_limit_date_when_ stock = CollectiveStock.query.filter_by(id=stock_to_be_updated.id).one() assert stock.beginningDatetime == new_event_date.replace(tzinfo=None) + @override_features(ENABLE_COLLECTIVE_NEW_STATUSES=False) def test_edit_offer_of_cancelled_booking(self) -> None: # Given offer = educational_factories.CollectiveOfferFactory() @@ -627,6 +632,7 @@ def test_edit_offer_of_cancelled_booking(self) -> None: assert stock.price == 1500 assert stock.numberOfTickets == 35 + @override_features(ENABLE_COLLECTIVE_NEW_STATUSES=False) @time_machine.travel("2020-01-05 10:00:00") def test_edit_offer_of_other_status_booking(self) -> None: # Given @@ -672,6 +678,7 @@ def test_edit_offer_of_other_status_booking(self) -> None: # Then assert error.value.errors == {"global": ["Les évènements passés ne sont pas modifiables"]} + @override_features(ENABLE_COLLECTIVE_NEW_STATUSES=False) def test_edit_price_or_ticket_number_if_status_confirmed(self): initial_event_date = datetime.datetime.utcnow() + datetime.timedelta(days=10) initial_booking_limit_date = datetime.datetime.utcnow() + datetime.timedelta(days=5) diff --git a/api/tests/core/educational/test_models.py b/api/tests/core/educational/test_models.py index 7c8fcffe7d7..4f715f45a14 100644 --- a/api/tests/core/educational/test_models.py +++ b/api/tests/core/educational/test_models.py @@ -90,12 +90,20 @@ def test_bookable(self) -> None: collective_stock = factories.CollectiveStockFactory() assert collective_stock.isBookable + @override_features(ENABLE_COLLECTIVE_NEW_STATUSES=False) def test_bookable_if_booking_is_cancelled(self) -> None: collective_stock = factories.CollectiveStockFactory() factories.CollectiveBookingFactory(collectiveStock=collective_stock, status=CollectiveBookingStatus.CANCELLED) assert collective_stock.isBookable + @override_features(ENABLE_COLLECTIVE_NEW_STATUSES=True) + def test_bookable_if_booking_is_cancelled_with_new_statuses(self) -> None: + collective_stock = factories.CollectiveStockFactory() + factories.CollectiveBookingFactory(collectiveStock=collective_stock, status=CollectiveBookingStatus.CANCELLED) + + assert not collective_stock.isBookable + class CollectiveOfferIsSoldOutTest: def test_is_sold_out_property_false(self) -> None: @@ -695,11 +703,13 @@ def test_get_displayed_status_for_offer_with_cancelled_booking(self): class CollectiveOfferTemplateDisplayedStatusTest: + @override_features(ENABLE_COLLECTIVE_NEW_STATUSES=False) @pytest.mark.parametrize("status", set(COLLECTIVE_OFFER_TEMPLATE_STATUSES) - {CollectiveOfferDisplayedStatus.ENDED}) def test_get_offer_displayed_status(self, status): offer = factories.create_collective_offer_template_by_status(status) assert offer.displayedStatus == status + @override_features(ENABLE_COLLECTIVE_NEW_STATUSES=False) def test_get_offer_displayed_status_ended(self): # when ENABLE_COLLECTIVE_NEW_STATUSES FF is off, and ended offer is INACTIVE offer = factories.create_collective_offer_template_by_status(CollectiveOfferDisplayedStatus.ENDED) diff --git a/api/tests/core/offers/test_repository.py b/api/tests/core/offers/test_repository.py index 4e1c2677de6..923207aedb1 100644 --- a/api/tests/core/offers/test_repository.py +++ b/api/tests/core/offers/test_repository.py @@ -1320,6 +1320,7 @@ def admin_user_fixture(): @pytest.mark.usefixtures("db_session") class GetCollectiveOffersTemplateByFiltersTest: + @override_features(ENABLE_COLLECTIVE_NEW_STATUSES=False) def test_status_filter_active(self, admin_user): template = educational_factories.CollectiveOfferTemplateFactory() educational_factories.CollectiveOfferTemplateFactory(validation=offer_mixin.OfferValidationStatus.REJECTED) @@ -1347,6 +1348,7 @@ def test_filter_each_status_with_new_statuses(self, admin_user, offer_status): ) assert result.count() == 0 + @override_features(ENABLE_COLLECTIVE_NEW_STATUSES=False) @pytest.mark.parametrize( "offer_status", set(educational_models.COLLECTIVE_OFFER_TEMPLATE_STATUSES) @@ -1366,6 +1368,7 @@ def test_filter_each_status(self, admin_user, offer_status): ) assert result.count() == 0 + @override_features(ENABLE_COLLECTIVE_NEW_STATUSES=False) def test_filter_ended(self, admin_user): template = educational_factories.create_collective_offer_template_by_status( educational_models.CollectiveOfferDisplayedStatus.ENDED diff --git a/api/tests/routes/pro/patch_cancel_collective_offer_booking_test.py b/api/tests/routes/pro/patch_cancel_collective_offer_booking_test.py index c4c6b93b35b..61826e85fe5 100644 --- a/api/tests/routes/pro/patch_cancel_collective_offer_booking_test.py +++ b/api/tests/routes/pro/patch_cancel_collective_offer_booking_test.py @@ -177,7 +177,7 @@ def test_cancel_unallowed_action(self, client, status): class Returns400Test: - + @override_features(ENABLE_COLLECTIVE_NEW_STATUSES=False) @pytest.mark.parametrize( "status", [ diff --git a/api/tests/routes/pro/patch_collective_offer_test.py b/api/tests/routes/pro/patch_collective_offer_test.py index e6262985745..cc5d73f8ece 100644 --- a/api/tests/routes/pro/patch_collective_offer_test.py +++ b/api/tests/routes/pro/patch_collective_offer_test.py @@ -53,10 +53,10 @@ def auth_client_fixture(client, user_offerer): class Returns200Test: endpoint = "Private API.edit_collective_offer" + @override_features(ENABLE_COLLECTIVE_NEW_STATUSES=True) @time_machine.travel("2019-01-01 12:00:00") @override_settings(ADAGE_API_URL="https://adage_base_url") def test_patch_collective_offer(self, client): - # Given offer = educational_factories.CollectiveOfferFactory( mentalDisabilityCompliant=False, contactEmail="johndoe@yopmail.com", @@ -68,16 +68,14 @@ def test_patch_collective_offer(self, client): interventionArea=["01", "07", "08"], ) booking = educational_factories.CollectiveBookingFactory( - collectiveStock__collectiveOffer=offer, collectiveStock__beginningDatetime=datetime(2020, 1, 1) - ) - offerers_factories.UserOffererFactory( - user__email="user@example.com", - offerer=offer.venue.managingOfferer, + collectiveStock__collectiveOffer=offer, + collectiveStock__beginningDatetime=datetime(2020, 1, 1), + status=CollectiveBookingStatus.PENDING, ) + offerers_factories.UserOffererFactory(user__email="user@example.com", offerer=offer.venue.managingOfferer) domain = educational_factories.EducationalDomainFactory(name="Architecture") national_program = educational_factories.NationalProgramFactory() - # When data = { "name": "New name", "mentalDisabilityCompliant": True, @@ -92,14 +90,12 @@ def test_patch_collective_offer(self, client): "formats": [subcategories.EacFormat.CONCERT.value], } - # WHEN client = client.with_session_auth("user@example.com") with patch( "pcapi.routes.pro.collective_offers.offerers_api.can_offerer_create_educational_offer", ): response = client.patch(f"/collective/offers/{offer.id}", json=data) - # Then assert response.status_code == 200 assert response.json["name"] == "New name" assert response.json["mentalDisabilityCompliant"] @@ -150,32 +146,17 @@ def test_patch_collective_offer(self, client): assert adage_request["sent_data"] == expected_payload assert adage_request["url"] == "https://adage_base_url/v1/prereservation-edit" + @override_features(ENABLE_COLLECTIVE_NEW_STATUSES=True) @override_settings(ADAGE_API_URL="https://adage_base_url") - def test_patch_collective_offer_do_not_notify_educational_redactor_when_no_active_booking( - self, - client, - ): - # Given + def test_patch_collective_offer_do_not_notify_educational_redactor_when_no_booking(self, client): offer = educational_factories.CollectiveOfferFactory() - educational_factories.CollectiveBookingFactory( - collectiveStock__collectiveOffer=offer, status=CollectiveBookingStatus.CANCELLED - ) - offerers_factories.UserOffererFactory( - user__email="user@example.com", - offerer=offer.venue.managingOfferer, - ) - data = { - "name": "New name", - } + offerers_factories.UserOffererFactory(user__email="user@example.com", offerer=offer.venue.managingOfferer) + data = {"name": "New name"} - # WHEN client = client.with_session_auth("user@example.com") - with patch( - "pcapi.routes.pro.collective_offers.offerers_api.can_offerer_create_educational_offer", - ): + with patch("pcapi.routes.pro.collective_offers.offerers_api.can_offerer_create_educational_offer"): response = client.patch(f"/collective/offers/{offer.id}", json=data) - # Then assert response.status_code == 200 assert len(educational_testing.adage_requests) == 0 @@ -227,6 +208,7 @@ def test_patch_collective_offer_update_student_level_college_6(self, client): assert len(offer.students) == 1 assert offer.students[0].value == "Collège - 6e" + @override_features(ENABLE_COLLECTIVE_NEW_STATUSES=False) @pytest.mark.parametrize( "factory", [ @@ -235,7 +217,6 @@ def test_patch_collective_offer_update_student_level_college_6(self, client): ], ) def test_update_venue_both_offer_and_booking(self, auth_client, venue, other_related_venue, factory): - offer = educational_factories.CollectiveOfferFactory(venue=other_related_venue) stock = educational_factories.CollectiveStockFactory(collectiveOffer=offer) @@ -257,6 +238,26 @@ def test_update_venue_both_offer_and_booking(self, auth_client, venue, other_rel assert booking.venueId == venue.id assert cancelled_booking.venueId == venue.id + @override_features(ENABLE_COLLECTIVE_NEW_STATUSES=True) + def test_update_venue_both_offer_and_booking_with_new_statuses(self, auth_client, venue, other_related_venue): + offer = educational_factories.CollectiveOfferFactory(venue=other_related_venue) + stock = educational_factories.CollectiveStockFactory(collectiveOffer=offer) + + booking = educational_factories.PendingCollectiveBookingFactory( + venue=other_related_venue, collectiveStock=stock + ) + + patch_path = "pcapi.routes.pro.collective_offers.offerers_api.can_offerer_create_educational_offer" + with patch(patch_path): + response = auth_client.patch(url_for(self.endpoint, offer_id=offer.id), json={"venueId": venue.id}) + assert response.status_code == 200 + + db.session.refresh(offer) + db.session.refresh(booking) + + assert offer.venueId == venue.id + assert booking.venueId == venue.id + @override_features(ENABLE_COLLECTIVE_NEW_STATUSES=True) @pytest.mark.parametrize("status", educational_testing.STATUSES_ALLOWING_EDIT_DETAILS) def test_patch_collective_offer_allowed_action(self, client, status): @@ -293,21 +294,14 @@ def test_patch_collective_offer_allowed_action(self, client, status): class Returns400Test: + @override_features(ENABLE_COLLECTIVE_NEW_STATUSES=False) def test_patch_non_approved_offer_fails(self, app, client): offer = educational_factories.CollectiveOfferFactory(validation=OfferValidationStatus.PENDING) - offerers_factories.UserOffererFactory( - user__email="user@example.com", - offerer=offer.venue.managingOfferer, - ) + offerers_factories.UserOffererFactory(user__email="user@example.com", offerer=offer.venue.managingOfferer) - data = { - "visualDisabilityCompliant": True, - } - # WHEN + data = {"visualDisabilityCompliant": True} client = client.with_session_auth("user@example.com") - with patch( - "pcapi.routes.pro.collective_offers.offerers_api.can_offerer_create_educational_offer", - ): + with patch("pcapi.routes.pro.collective_offers.offerers_api.can_offerer_create_educational_offer"): response = client.patch(f"/collective/offers/{offer.id}", json=data) assert response.status_code == 400 @@ -563,51 +557,33 @@ def when_user_is_not_attached_to_offerer(self, app, client): ] assert CollectiveOffer.query.get(offer.id).name == "Old name" + @override_features(ENABLE_COLLECTIVE_NEW_STATUSES=False) def test_cannot_update_offer_with_used_booking(self, client): - # Given offer = educational_factories.CollectiveOfferFactory() educational_factories.UsedCollectiveBookingFactory( collectiveStock__collectiveOffer=offer, ) - offerers_factories.UserOffererFactory( - user__email="user@example.com", - offerer=offer.venue.managingOfferer, - ) - data = { - "name": "New name", - } + offerers_factories.UserOffererFactory(user__email="user@example.com", offerer=offer.venue.managingOfferer) + data = {"name": "New name"} - # WHEN client = client.with_session_auth("user@example.com") - with patch( - "pcapi.routes.pro.collective_offers.offerers_api.can_offerer_create_educational_offer", - ): + with patch("pcapi.routes.pro.collective_offers.offerers_api.can_offerer_create_educational_offer"): response = client.patch(f"/collective/offers/{offer.id}", json=data) - # Then assert response.status_code == 403 assert response.json == {"offer": "the used or refund offer can't be edited."} + @override_features(ENABLE_COLLECTIVE_NEW_STATUSES=False) def test_cannot_update_offer_created_by_public_api(self, client): - # Given provider = providers_factories.ProviderFactory() offer = educational_factories.CollectiveOfferFactory(provider=provider) - offerers_factories.UserOffererFactory( - user__email="user@example.com", - offerer=offer.venue.managingOfferer, - ) - data = { - "name": "New name", - } + offerers_factories.UserOffererFactory(user__email="user@example.com", offerer=offer.venue.managingOfferer) + data = {"name": "New name"} - # WHEN client = client.with_session_auth("user@example.com") - with patch( - "pcapi.routes.pro.collective_offers.offerers_api.can_offerer_create_educational_offer", - ): + with patch("pcapi.routes.pro.collective_offers.offerers_api.can_offerer_create_educational_offer"): response = client.patch(f"/collective/offers/{offer.id}", json=data) - # Then assert response.status_code == 403 assert response.json == {"global": ["Collective offer created by public API is only editable via API."]} @@ -634,6 +610,7 @@ def test_patch_collective_offer_replacing_venue_with_different_offerer(self, cli assert response.status_code == 403 assert response.json == {"venueId": "New venue needs to have the same offerer"} + @override_features(ENABLE_COLLECTIVE_NEW_STATUSES=False) def test_update_collective_offer_venue_of_reimbursed_offer_fails(self, client, other_related_venue): offer = educational_factories.ReimbursedCollectiveOfferFactory() offerers_factories.UserOffererFactory(user__email="user@example.com", offerer=offer.venue.managingOfferer) diff --git a/api/tests/routes/pro/patch_collective_offers_active_status_test.py b/api/tests/routes/pro/patch_collective_offers_active_status_test.py index 2afe010665b..0d113ff8ac6 100644 --- a/api/tests/routes/pro/patch_collective_offers_active_status_test.py +++ b/api/tests/routes/pro/patch_collective_offers_active_status_test.py @@ -11,8 +11,8 @@ @pytest.mark.usefixtures("db_session") class Returns204Test: + @testing.override_features(ENABLE_COLLECTIVE_NEW_STATUSES=False) def when_activating_existing_offers(self, client): - # Given offer1 = CollectiveOfferFactory(isActive=False) venue = offer1.venue offer2 = CollectiveOfferFactory(venue=venue, isActive=False) @@ -20,38 +20,33 @@ def when_activating_existing_offers(self, client): offerers_factories.UserOffererFactory(user__email="pro@example.com", offerer=offerer) client = client.with_session_auth("pro@example.com") - # When data = {"ids": [offer1.id, offer2.id], "isActive": True} - with patch( - "pcapi.routes.pro.collective_offers.offerers_api.can_offerer_create_educational_offer", - ): + with patch("pcapi.routes.pro.collective_offers.offerers_api.can_offerer_create_educational_offer"): response = client.with_session_auth("pro@example.com").patch("/collective/offers/active-status", json=data) - # Then assert response.status_code == 204 assert CollectiveOffer.query.get(offer1.id).isActive assert CollectiveOffer.query.get(offer2.id).isActive + @testing.override_features(ENABLE_COLLECTIVE_NEW_STATUSES=False) def when_deactivating_existing_offers(self, client): - # Given offer1 = CollectiveOfferFactory() venue = offer1.venue offer2 = CollectiveOfferFactory(venue=venue) offerer = venue.managingOfferer offerers_factories.UserOffererFactory(user__email="pro@example.com", offerer=offerer) - # When client = client.with_session_auth("pro@example.com") data = {"ids": [offer1.id, offer2.id], "isActive": False} with testing.assert_no_duplicated_queries(): response = client.patch("/collective/offers/active-status", json=data) - # Then assert response.status_code == 204 assert not CollectiveOffer.query.get(offer1.id).isActive assert not CollectiveOffer.query.get(offer2.id).isActive + @testing.override_features(ENABLE_COLLECTIVE_NEW_STATUSES=False) def test_only_approved_offers_patch(self, client): approved_offer = CollectiveOfferFactory(isActive=False) venue = approved_offer.venue @@ -65,9 +60,7 @@ def test_only_approved_offers_patch(self, client): "isActive": True, } - with patch( - "pcapi.routes.pro.collective_offers.offerers_api.can_offerer_create_educational_offer", - ): + with patch("pcapi.routes.pro.collective_offers.offerers_api.can_offerer_create_educational_offer"): client = client.with_session_auth("pro@example.com") response = client.patch("/collective/offers/active-status", json=data) @@ -79,6 +72,7 @@ def test_only_approved_offers_patch(self, client): @pytest.mark.usefixtures("db_session") class Returns403Test: + @testing.override_features(ENABLE_COLLECTIVE_NEW_STATUSES=False) def test_when_activating_all_existing_offers_active_status_when_cultural_partners_not_found(self, client): # Given offer1 = CollectiveOfferFactory(isActive=False) diff --git a/api/tests/routes/pro/patch_collective_offers_archive_test.py b/api/tests/routes/pro/patch_collective_offers_archive_test.py index 1b413c98f26..66d4a580711 100644 --- a/api/tests/routes/pro/patch_collective_offers_archive_test.py +++ b/api/tests/routes/pro/patch_collective_offers_archive_test.py @@ -37,6 +37,7 @@ class Returns204Test: num_queries_error = num_queries_error - 1 # "update dateArchive on collective_offer" is not run num_queries_error = num_queries_error + 1 # rollback due to atomic + @override_features(ENABLE_COLLECTIVE_NEW_STATUSES=False) def when_archiving_existing_offers(self, client): offer1 = factories.CollectiveOfferFactory() venue = offer1.venue @@ -83,6 +84,7 @@ def when_archiving_existing_offers_from_other_offerer(self, client): assert not other_offer.isArchived assert other_offer.isActive + @override_features(ENABLE_COLLECTIVE_NEW_STATUSES=False) def when_archiving_draft_offers(self, client): draft_offer = factories.create_collective_offer_by_status(models.CollectiveOfferDisplayedStatus.DRAFT) venue = draft_offer.venue @@ -103,6 +105,7 @@ def when_archiving_draft_offers(self, client): assert other_offer.isArchived assert not other_offer.isActive + @override_features(ENABLE_COLLECTIVE_NEW_STATUSES=False) def test_archive_rejected_offer(self, client): offer = factories.create_collective_offer_by_status(models.CollectiveOfferDisplayedStatus.REJECTED) venue = offer.venue @@ -201,6 +204,7 @@ def test_archive_offer_unallowed_action_on_one_offer(self, client): @pytest.mark.usefixtures("db_session") class Returns422Test: + @override_features(ENABLE_COLLECTIVE_NEW_STATUSES=False) def when_archiving_already_archived(self, client): offer_already_archived = factories.CollectiveOfferFactory(isActive=False, dateArchived=datetime.utcnow()) venue = offer_already_archived.venue diff --git a/api/tests/routes/pro/patch_collective_offers_educational_institution_test.py b/api/tests/routes/pro/patch_collective_offers_educational_institution_test.py index 45c45668c27..b523c6be5d5 100644 --- a/api/tests/routes/pro/patch_collective_offers_educational_institution_test.py +++ b/api/tests/routes/pro/patch_collective_offers_educational_institution_test.py @@ -22,19 +22,17 @@ @pytest.mark.usefixtures("db_session") @override_settings(ADAGE_API_URL="https://adage_base_url") class Returns200Test: + @override_features(ENABLE_COLLECTIVE_NEW_STATUSES=False) def test_create_offer_institution_link(self, client: Any) -> None: - # Given institution = factories.EducationalInstitutionFactory() stock = factories.CollectiveStockFactory() offer = stock.collectiveOffer offerers_factories.UserOffererFactory(user__email="pro@example.com", offerer=offer.venue.managingOfferer) - # When client = client.with_session_auth("pro@example.com") data = {"educationalInstitutionId": institution.id} response = client.patch(f"/collective/offers/{offer.id}/educational_institution", json=data) - # Then assert response.status_code == 200 offer_db = models.CollectiveOffer.query.filter(models.CollectiveOffer.id == offer.id).one() assert offer_db.institution == institution @@ -43,26 +41,24 @@ def test_create_offer_institution_link(self, client: Any) -> None: assert adage_api_testing.adage_requests[0]["sent_data"] == expected_payload assert adage_api_testing.adage_requests[0]["url"] == "https://adage_base_url/v1/offre-assoc" + @override_features(ENABLE_COLLECTIVE_NEW_STATUSES=False) def test_create_offer_institution_link_to_teacher(self, client) -> None: - # Given institution = factories.EducationalInstitutionFactory(institutionId="0470009E") stock = factories.CollectiveStockFactory() offer = stock.collectiveOffer offerers_factories.UserOffererFactory(user__email="pro@example.com", offerer=offer.venue.managingOfferer) - # When client = client.with_session_auth("pro@example.com") data = {"educationalInstitutionId": institution.id, "teacherEmail": "maria.sklodowska@example.com"} response = client.patch(f"/collective/offers/{offer.id}/educational_institution", json=data) - # Then assert response.status_code == 200 offer_db = models.CollectiveOffer.query.filter(models.CollectiveOffer.id == offer.id).one() assert offer_db.institution == institution assert offer_db.teacher.email == "maria.sklodowska@example.com" + @override_features(ENABLE_COLLECTIVE_NEW_STATUSES=False) def test_change_offer_institution_link(self, client: Any) -> None: - # Given institution1 = factories.EducationalInstitutionFactory() stock = factories.CollectiveStockFactory( collectiveOffer__institution=institution1, @@ -72,19 +68,17 @@ def test_change_offer_institution_link(self, client: Any) -> None: offerers_factories.UserOffererFactory(user__email="pro@example.com", offerer=offer.venue.managingOfferer) institution2 = factories.EducationalInstitutionFactory() - # When client = client.with_session_auth("pro@example.com") data = {"educationalInstitutionId": institution2.id} response = client.patch(f"/collective/offers/{offer.id}/educational_institution", json=data) - # Then assert response.status_code == 200 offer_db = models.CollectiveOffer.query.filter(models.CollectiveOffer.id == offer.id).one() assert offer_db.institution == institution2 assert offer_db.teacher is None + @override_features(ENABLE_COLLECTIVE_NEW_STATUSES=False) def test_delete_offer_institution_link(self, client: Any) -> None: - # Given institution = factories.EducationalInstitutionFactory() stock = factories.CollectiveStockFactory( collectiveOffer__institution=institution, @@ -93,12 +87,10 @@ def test_delete_offer_institution_link(self, client: Any) -> None: offer = stock.collectiveOffer offerers_factories.UserOffererFactory(user__email="pro@example.com", offerer=offer.venue.managingOfferer) - # When client = client.with_session_auth("pro@example.com") data = {"educationalInstitutionId": None} response = client.patch(f"/collective/offers/{offer.id}/educational_institution", json=data) - # Then assert response.status_code == 200 offer_db = models.CollectiveOffer.query.filter(models.CollectiveOffer.id == offer.id).one() assert offer_db.institution is None diff --git a/api/tests/routes/pro/patch_collective_stock_test.py b/api/tests/routes/pro/patch_collective_stock_test.py index a3fc77a4c76..80c1ef1b52e 100644 --- a/api/tests/routes/pro/patch_collective_stock_test.py +++ b/api/tests/routes/pro/patch_collective_stock_test.py @@ -121,9 +121,9 @@ def test_edit_collective_stock_begining_datedame_same_day(self, client): "educationalPriceDetail": "Détail du prix", } + @override_features(ENABLE_COLLECTIVE_NEW_STATUSES=True) @time_machine.travel("2020-11-17 15:00:00") def test_edit_collective_stock_partially(self, client): - # Given _educational_year_2021_2022 = educational_factories.EducationalYearFactory( beginningDate=datetime(2021, 9, 1), expirationDate=datetime(2022, 8, 31) ) @@ -134,13 +134,10 @@ def test_edit_collective_stock_partially(self, client): bookingLimitDatetime=datetime(2021, 12, 1), priceDetail="Détail du prix", ) - educational_factories.CancelledCollectiveBookingFactory(collectiveStock=stock) offerers_factories.UserOffererFactory( - user__email="user@example.com", - offerer=stock.collectiveOffer.venue.managingOfferer, + user__email="user@example.com", offerer=stock.collectiveOffer.venue.managingOfferer ) - # When stock_edition_payload = { "beginningDatetime": "2022-01-17T22:00:00Z", "totalPrice": 1500, @@ -149,7 +146,6 @@ def test_edit_collective_stock_partially(self, client): client.with_session_auth("user@example.com") response = client.patch(f"/collective/stocks/{stock.id}", json=stock_edition_payload) - # Then assert response.status_code == 200 edited_stock = CollectiveStock.query.get(stock.id) assert edited_stock.beginningDatetime == datetime(2022, 1, 17, 22) @@ -352,26 +348,42 @@ def test_edit_collective_stocks_should_not_be_possible_when_user_not_linked_to_o "global": ["Vous n'avez pas les droits d'accès suffisants pour accéder à cette information."] } + @override_features(ENABLE_COLLECTIVE_NEW_STATUSES=False) def test_edit_collective_stocks_should_not_be_possible_when_offer_created_by_public_api(self, client): stock = educational_factories.CollectiveStockFactory( - collectiveOffer__provider=providers_factories.ProviderFactory(), + collectiveOffer__provider=providers_factories.ProviderFactory() ) offerers_factories.UserOffererFactory( - user__email="user@example.com", - offerer=stock.collectiveOffer.venue.managingOfferer, + user__email="user@example.com", offerer=stock.collectiveOffer.venue.managingOfferer ) - # When - stock_edition_payload = { - "totalPrice": 1500, - } + + stock_edition_payload = {"totalPrice": 1500} client.with_session_auth("user@example.com") response = client.patch(f"/collective/stocks/{stock.id}", json=stock_edition_payload) - # Then assert response.status_code == 403 assert response.json == {"global": ["Les stocks créés par l'api publique ne sont pas editables."]} + @override_features(ENABLE_COLLECTIVE_NEW_STATUSES=True) + def test_edit_collective_stocks_should_not_be_possible_when_offer_created_by_public_api_with_new_satuses( + self, client + ): + stock = educational_factories.CollectiveStockFactory( + collectiveOffer__provider=providers_factories.ProviderFactory() + ) + offerers_factories.UserOffererFactory( + user__email="user@example.com", offerer=stock.collectiveOffer.venue.managingOfferer + ) + + stock_edition_payload = {"totalPrice": 1500} + + client.with_session_auth("user@example.com") + response = client.patch(f"/collective/stocks/{stock.id}", json=stock_edition_payload) + + assert response.status_code == 403 + assert response.json == {"global": ["Cette action n'est pas autorisée sur l'offre collective liée à ce stock."]} + class Return400Test: @time_machine.travel("2020-11-17 15:00:00") @@ -458,26 +470,19 @@ def should_not_accept_payload_with_bookingLimitDatetime_after_beginningDatetime( edited_stock = CollectiveStock.query.get(stock.id) assert edited_stock.bookingLimitDatetime == stock.bookingLimitDatetime + @override_features(ENABLE_COLLECTIVE_NEW_STATUSES=False) @time_machine.travel("2020-11-17 15:00:00") def should_edit_stock_when_event_expired(self, client): - # Given - stock = educational_factories.CollectiveStockFactory( - beginningDatetime=datetime.utcnow() - timedelta(minutes=1), - ) + stock = educational_factories.CollectiveStockFactory(beginningDatetime=datetime.utcnow() - timedelta(minutes=1)) offerers_factories.UserOffererFactory( - user__email="user@example.com", - offerer=stock.collectiveOffer.venue.managingOfferer, + user__email="user@example.com", offerer=stock.collectiveOffer.venue.managingOfferer ) - # When - stock_edition_payload = { - "totalPrice": 1500, - } + stock_edition_payload = {"totalPrice": 1500} client.with_session_auth("user@example.com") response = client.patch(f"/collective/stocks/{stock.id}", json=stock_edition_payload) - # Then assert response.status_code == 200 @time_machine.travel("2020-11-17 15:00:00") @@ -598,18 +603,16 @@ def test_create_valid_stock_for_collective_offer(self, client): assert response.status_code == 400 assert response.json == {"beginningDatetime": ["L'évènement ne peut commencer dans le passé."]} + @override_features(ENABLE_COLLECTIVE_NEW_STATUSES=False) @time_machine.travel("2020-11-17 15:00:00") def test_doesnot_edit_offer_if_rejected(self, client): offer = educational_factories.CollectiveOfferFactory(validation=offer_mixin.OfferValidationStatus.REJECTED) stock = educational_factories.CollectiveStockFactory(price=1200, collectiveOffer=offer) offerers_factories.UserOffererFactory( - user__email="user@example.com", - offerer=stock.collectiveOffer.venue.managingOfferer, + user__email="user@example.com", offerer=stock.collectiveOffer.venue.managingOfferer ) - stock_edition_payload = { - "totalPrice": 111, - } + stock_edition_payload = {"totalPrice": 111} response = client.with_session_auth("user@example.com").patch( f"/collective/stocks/{stock.id}", json=stock_edition_payload ) diff --git a/api/tests/routes/pro/post_duplicate_collective_offer_and_stock_test.py b/api/tests/routes/pro/post_duplicate_collective_offer_and_stock_test.py index 36229fe47bd..9e9305030e7 100644 --- a/api/tests/routes/pro/post_duplicate_collective_offer_and_stock_test.py +++ b/api/tests/routes/pro/post_duplicate_collective_offer_and_stock_test.py @@ -198,8 +198,8 @@ def test_duplicate_collective_offer_without_subcategoryId(self, client): assert response.status_code == 201 assert response.json.get("formats") == ["Concert"] + @override_features(ENABLE_COLLECTIVE_NEW_STATUSES=False) def test_duplicate_collective_offer_draft_offer(self, client): - # Given offerer = offerers_factories.OffererFactory() offerers_factories.UserOffererFactory(offerer=offerer, user__email="user@example.com") venue = offerers_factories.VenueFactory(managingOfferer=offerer) @@ -210,8 +210,6 @@ def test_duplicate_collective_offer_draft_offer(self, client): offer_id = offer.id educational_factories.CollectiveStockFactory(collectiveOffer=offer) - # When - response = client.with_session_auth("user@example.com").post(f"/collective/offers/{offer_id}/duplicate") assert response.status_code == 403