def test_should_mark_offers_and_products_as_incompatible_via_isbn( self, mocked_unindex_offer_ids): # Given product = ProductFactory(id=1, extraData={"isbn": "ABCDEFG"}) product_1 = ProductFactory(id=2, extraData={"isbn": "HIJKLMN"}) product_2 = ProductFactory(id=3, extraData={"isbn": "VWXYZ"}) product_3 = ProductFactory(id=4, extraData={"isbn": "HFGDS"}) offer = OfferFactory(id=1, product=product) offer_1 = OfferFactory(id=2, product=product_1) offer_2 = OfferFactory(id=3, product=product_2) offer_3 = OfferFactory(id=4, product=product_3) isbns_list = ["ABCDEFG", "HIJKLMN", "OPQRSTU", "HFGDS"] queries = 1 # update product queries += 1 # select offer queries += 2 # update offer; commit queries *= 2 # two batches # When with assert_num_queries(queries): bulk_update_is_gcu_compatible_via_isbns(isbns_list, 2, is_compatible=False) # Then assert not product.isGcuCompatible assert not product_1.isGcuCompatible assert product_2.isGcuCompatible assert not product_3.isGcuCompatible assert not offer.isActive assert not offer_1.isActive assert offer_2.isActive assert not offer_3.isActive mocked_unindex_offer_ids.assert_has_calls([call([1, 2]), call([4])])
def test_cancel_bookings_when_offerer_has_one_or_more(): # Given fraudulent_emails_providers = ["example.com"] admin_user = AdminFactory(email="*****@*****.**") beneficiary1 = BeneficiaryGrant18Factory(email="*****@*****.**") beneficiary2 = BeneficiaryGrant18Factory(email="*****@*****.**") fraudulent_user = ProFactory(email="*****@*****.**", ) offerer_with_bookings = OffererFactory() UserOffererFactory(user=fraudulent_user, offerer=offerer_with_bookings) offer1 = OfferFactory(venue__managingOfferer=offerer_with_bookings) offer2 = OfferFactory(venue__managingOfferer=offerer_with_bookings) stock1 = StockFactory(offer=offer1) stock2 = StockFactory(offer=offer2) booking1 = BookingFactory(user=beneficiary1, stock=stock1) booking2 = BookingFactory(user=beneficiary2, stock=stock2) # When suspend_fraudulent_pro_by_email_providers(fraudulent_emails_providers, admin_user, dry_run=False) # Then assert Offerer.query.count() == 1 assert Venue.query.count() == 2 assert Offer.query.count() == 2 assert Stock.query.count() == 2 assert Booking.query.count() == 2 assert booking1.isCancelled assert booking1.status is BookingStatus.CANCELLED assert booking1.cancellationReason is BookingCancellationReasons.FRAUD assert booking2.isCancelled assert booking2.status is BookingStatus.CANCELLED assert booking2.cancellationReason is BookingCancellationReasons.FRAUD
def test_update_last_provider_id(): provider1 = offerers_factories.ProviderFactory() provider2 = offerers_factories.ProviderFactory() venue = VenueFactory() offer1_synced = OfferFactory(venue=venue, idAtProviders=1, lastProvider=provider1) offer2_manual = OfferFactory(venue=venue, idAtProviders=None) offer3_other_venue = OfferFactory(idAtProviders=2, lastProvider=provider1) api.update_last_provider_id(venue, provider2.id) assert offer1_synced.lastProvider == provider2 assert offer2_manual.idAtProviders is None assert offer3_other_venue.lastProvider == provider1
def test_send_offer_link_notification(self, app): """ Test that a push notification to the user is send with a link to the offer. """ # offer.id must be used before the assert_num_queries context manager # because it triggers a SQL query. offer = OfferFactory() offer_id = offer.id user, test_client = create_user_and_test_client(app) # expected queries: # * get user # * get offer # * get FeatureToggle WEBAPP_V2_ENABLED (to build URL) with assert_num_queries(3): response = test_client.post( f"/native/v1/send_offer_link_by_push/{offer_id}") assert response.status_code == 204 assert len(notifications_testing.requests) == 1 notification = notifications_testing.requests[0] assert notification["user_ids"] == [user.id] assert offer.name in notification["message"]["title"] assert "deeplink" in notification
def test_get_user_reported_offers(self, client): user = UserFactory() offers = OfferFactory.create_batch(3) reports = [ OfferReportFactory(user=user, offer=offers[0]), OfferReportFactory(user=user, offer=offers[1]), ] # offers reported by this user should not be returned another_user = UserFactory() OfferReportFactory(user=another_user, offer=offers[2]) client.with_token(user.email) response = client.get("/native/v1/offers/reports") assert response.status_code == 200 response_reports = sorted(response.json["reportedOffers"], key=lambda x: x["offerId"]) assert response_reports == [ { "offerId": reports[0].offerId, "reportedAt": reports[0].reportedAt.isoformat(), "reason": reports[0].reason.value, }, { "offerId": reports[1].offerId, "reportedAt": reports[1].reportedAt.isoformat(), "reason": reports[1].reason.value, }, ]
def should_return_offers_with_id_at_providers_including_different_siret(self, app): # Given current_siret = "32363560700019" expected_venue = VenueFactory(siret=current_siret) other_venue = VenueFactory(siret="7863560700657") offer1 = OfferFactory(venue=expected_venue, idAtProviders="9782742785988@85234081900014") offer2 = OfferFactory(venue=expected_venue, idAtProviders="9782742785988@32363560700019") other_offer = OfferFactory(venue=other_venue, idAtProviders="9782742785988@7863560700657") repository.save(offer1, offer2, other_offer) # When offers_result = _get_titelive_offers_with_old_id_at_providers(expected_venue, current_siret) # Then assert offers_result == [offer1]
def test_report_offer_with_custom_reason(self, app): user, test_client = create_user_and_test_client(app) offer = OfferFactory() # expected queries: # * select offer # * get user # * insert report # * release savepoint # # * reload user # * select offer # * insert email into db # * release savepoint with assert_num_queries(8): data = {"reason": "OTHER", "customReason": "saynul"} response = test_client.post(f"/native/v1/offer/{offer.id}/report", json=data) assert response.status_code == 204 assert OfferReport.query.count() == 1 report = OfferReport.query.first() assert report.user == user assert report.offer == offer assert len(mails_testing.outbox) == 1 email = mails_testing.outbox[0] assert email.sent_data["To"] == "*****@*****.**" assert email.sent_data["Vars"]["user_id"] == user.id assert email.sent_data["Vars"]["offer_id"] == offer.id assert "saynul" in email.sent_data["Vars"]["reason"] assert "offer_url" in email.sent_data["Vars"]
def test_get_user_attributes(): user = BeneficiaryGrant18Factory(deposit__version=1) offer = OfferFactory(product__id=list(TRACKED_PRODUCT_IDS.keys())[0]) b1 = IndividualBookingFactory(individualBooking__user=user, amount=10, stock__offer=offer) b2 = IndividualBookingFactory(individualBooking__user=user, amount=10, dateUsed=datetime(2021, 5, 6), stock__offer=offer) IndividualBookingFactory( individualBooking__user=user, amount=100, status=BookingStatus.CANCELLED) # should be ignored last_date_created = max(booking.dateCreated for booking in [b1, b2]) n_query_get_user = 1 n_query_get_bookings = 1 n_query_get_deposit = 1 n_query_is_pro = 1 n_query_get_last_favorite = 1 with assert_num_queries(n_query_get_user + n_query_get_bookings + n_query_get_deposit + n_query_is_pro + n_query_get_last_favorite): attributes = get_user_attributes(user) assert attributes == UserAttributes( domains_credit=DomainsCredit( all=Credit(initial=Decimal("500"), remaining=Decimal("480.00")), digital=Credit(initial=Decimal("200"), remaining=Decimal("200")), physical=Credit(initial=200, remaining=Decimal("180.00")), ), booking_categories=["FILM"], date_created=user.dateCreated, date_of_birth=user.dateOfBirth, departement_code="75", deposit_expiration_date=user.deposit_expiration_date, eligibility=EligibilityType.AGE18, first_name="Jeanne", is_beneficiary=True, is_pro=False, last_booking_date=last_date_created, last_name="Doux", marketing_push_subscription=True, postal_code=None, products_use_date={"product_brut_x_use": datetime(2021, 5, 6, 0, 0)}, booking_count=2, booking_subcategories=["SUPPORT_PHYSIQUE_FILM"], deposit_activation_date=user.deposit_activation_date, has_completed_id_check=None, user_id=user.id, is_eligible=True, is_email_validated=True, last_favorite_creation_date=None, last_visit_date=None, marketing_email_subscription=True, )
def __init__(self, nb_duplicates, nb_regulars): self.venue = VenueFactory() self.duplicates = [( OfferFactory(idAtProviders= f"duplicate-id-{count}@siret-venue-{self.venue.id}", venue=self.venue), OfferFactory( idAtProviders= f"duplicate-id-{count}@other-siret-venue-{self.venue.id}", venue=self.venue), ) for count in range(nb_duplicates)] self.others = [ OfferFactory( idAtProviders=f"regular-id-{count}@siret-venue-{self.venue.id}", venue=self.venue) for count in range(nb_regulars) ]
def test_update_offer_and_stock_id_at_providers(self): # Given current_siret = "88888888888888" venue = VenueFactory(siret=current_siret) offer = OfferFactory(venue=venue, idAtProviders="1111111111111@22222222222222") other_venue_offer = OfferFactory( venue=venue, idAtProviders="3333333333333@12222222222222") stock = StockFactory(offer=offer, idAtProviders="1111111111111@22222222222222") # When update_offer_and_stock_id_at_providers(venue, "22222222222222") # Then assert offer.idAtProviders == "1111111111111@88888888888888" assert stock.idAtProviders == "1111111111111@88888888888888" assert other_venue_offer.idAtProviders == "3333333333333@12222222222222"
def test_get_no_reported_offers(self, client): user = UserFactory() OfferFactory() client.with_token(user.email) response = client.get("/native/v1/offers/reports") assert response.status_code == 200 assert not response.json["reportedOffers"]
def test_should_mark_offers_and_products_as_incompatible_via_offer_ids( self): # Given offer = OfferFactory(id=1) offer_1 = OfferFactory(id=2) offer_2 = OfferFactory(id=5) repository.save(offer, offer_1, offer_2) offer_ids_list = ["1", "2", "3"] # When bulk_inactivate_offers(offer_ids_list, 2) # Then offers = Offer.query.order_by(Offer.id).all() assert not offers[0].isActive assert not offers[1].isActive assert offers[2].isActive
def should_update_offer_withdrawal_details(self): # Given new_withdrawals_details = "Some withdrawal informations" active_offer_1 = OfferFactory(isActive=True) active_offer_2 = OfferFactory(isActive=True, venue=active_offer_1.venue) inactive_offer = OfferFactory(isActive=False, venue=active_offer_1.venue) different_offerer_offer = OfferFactory() # When batch_update_offer_withdrawal_details_for_offerer( active_offer_1.venue.managingOffererId, new_withdrawals_details, 1 ) # Then assert active_offer_1.withdrawalDetails == new_withdrawals_details assert active_offer_2.withdrawalDetails == new_withdrawals_details assert inactive_offer.withdrawalDetails is None assert different_offerer_offer.withdrawalDetails is None
def test_when_mailjet_status_code_200_sends_email_to_administration_email(self, app): author = users_factories.UserFactory(email="*****@*****.**") offer = OfferFactory(author=author) # When send_offer_rejection_notification_to_administration(offer) # Then assert len(mails_testing.outbox) == 1 assert mails_testing.outbox[0].sent_data["To"] == "*****@*****.**"
def test_reset_stock_quantity(): offer = OfferFactory(idAtProviders="1") venue = offer.venue stock1_no_bookings = StockFactory(offer=offer, quantity=10) stock2_only_cancelled_bookings = StockFactory(offer=offer, quantity=10) CancelledBookingFactory(stock=stock2_only_cancelled_bookings) stock3_mix_of_bookings = StockFactory(offer=offer, quantity=10) BookingFactory(stock=stock3_mix_of_bookings) CancelledBookingFactory(stock=stock3_mix_of_bookings) manually_added_offer = OfferFactory(venue=venue) stock4_manually_added = StockFactory(offer=manually_added_offer, quantity=10) stock5_other_venue = StockFactory(quantity=10) api.reset_stock_quantity(venue) assert stock1_no_bookings.quantity == 0 assert stock2_only_cancelled_bookings.quantity == 0 assert stock3_mix_of_bookings.quantity == 1 assert stock4_manually_added.quantity == 10 assert stock5_other_venue.quantity == 10
def test_send_approval_notification(self, app): author = users_factories.UserFactory(email="*****@*****.**") offer = OfferFactory(name="Test Book", author=author) # When send_offer_validation_notification_to_administration(OfferValidationStatus.APPROVED, offer) # Then assert len(mails_testing.outbox) == 1 assert mails_testing.outbox[0].sent_data["To"] == "*****@*****.**" assert mails_testing.outbox[0].sent_data["Subject"] == "[Création d’offre - 75] Test Book"
def test_report_inappropriate(self): # Given user = BeneficiaryGrant18Factory() offer = OfferFactory() reason = Reason.INAPPROPRIATE.value # When send_report_notification(user, offer, reason, "blabla") # Then assert mails_testing.outbox[0].sent_data[ "To"] == settings.REPORT_OFFER_EMAIL_ADDRESS
def test_report_other(self): # Given user = BeneficiaryGrant18Factory() offer = OfferFactory() reason = Reason.OTHER.value # When send_report_notification(user, offer, reason, "blabla") # Then assert mails_testing.outbox[0].sent_data[ "To"] == settings.SUPPORT_EMAIL_ADDRESS
def test_get_bookings_categories_and_subcategories(): user = BeneficiaryGrant18Factory() offer = OfferFactory(product__id=list(TRACKED_PRODUCT_IDS.keys())[0]) assert _get_bookings_categories_and_subcategories( _get_user_bookings(user)) == ([], []) IndividualBookingFactory(individualBooking__user=user, stock__offer=offer) IndividualBookingFactory(individualBooking__user=user, stock__offer=offer) IndividualBookingFactory(individualBooking__user=user, isCancelled=True) assert _get_bookings_categories_and_subcategories( _get_user_bookings(user)) == (["FILM"], ["SUPPORT_PHYSIQUE_FILM"])
def test_report_offer_unknown_reason(self, app, client): offer = OfferFactory() offer_id = offer.id with assert_num_queries(0): data = {"reason": "UNKNOWN"} response = client.post(f"/native/v1/offer/{offer_id}/report", json=data) assert response.status_code == 400 assert response.json["reason"] == ["unknown reason"] assert OfferReport.query.count() == 0 # no new report assert not mails_testing.outbox
def test_report_offer_custom_reason_too_long(self, app, client): offer = OfferFactory() offer_id = offer.id with assert_num_queries(0): data = {"reason": "OTHER", "customReason": "a" * 513} response = client.post(f"/native/v1/offer/{offer_id}/report", json=data) assert response.status_code == 400 assert response.json["customReason"] == [ "custom reason is too long" ] assert OfferReport.query.count() == 0 # no new report assert not mails_testing.outbox
def should_call_synchronize_on_expected_venue_provider(self, mock_do_sync_venue_provider, app): # Given venue = VenueFactory() offer = OfferFactory(venue=venue) stock = StockFactory(offer=offer) titelive = activate_provider(provider_classname="TiteLiveStocks") venue_provider = create_venue_provider(venue=venue, provider=titelive) repository.save(venue_provider, stock) # When fully_sync_library(venue_id=venue.id) # Then mock_do_sync_venue_provider.assert_called_once_with(venue_provider)
def should_update_id_at_providers_for_offers_and_stocks_with_current_siret(self, mock_repository, app): # Given current_siret = "32363560700019" venue = VenueFactory(siret=current_siret, id=12) offer = OfferFactory(venue=venue, idAtProviders="9782742785988@85234081900014") stock = StockFactory(offer=offer, idAtProviders="9782742785988@85234081900014") # When update_offer_and_stock_id_at_providers(venue_id=12) # Then assert offer.idAtProviders == "9782742785988@32363560700019" assert stock.idAtProviders == "9782742785988@32363560700019" assert mock_repository.save.call_count == 2 assert mock_repository.save.call_args_list == [call(offer), call(stock)]
def test_get_thing_offer(self, app): offer_type = ThingType.MUSEES_PATRIMOINE_ABO offer = OfferFactory(type=str(offer_type)) ThingStockFactory(offer=offer, price=12.34) response = TestClient( app.test_client()).get(f"/native/v1/offer/{offer.id}") assert response.status_code == 200 assert not response.json["stocks"][0]["beginningDatetime"] assert response.json["stocks"][0]["price"] == 1234 assert response.json["category"] == { "categoryType": "Thing", "label": "Musée, arts visuels et patrimoine", "name": "VISITE", } assert response.json["image"] is None
def test_report_offer_twice(self, app): user, test_client = create_user_and_test_client(app) offer = OfferFactory() OfferReportFactory(user=user, offer=offer) # expected queries: # * get user # * get offer # * rollback with assert_num_queries(3): response = test_client.post(f"/native/v1/offer/{offer.id}/report", json={"reason": "PRICE_TOO_HIGH"}) assert response.status_code == 400 assert response.json["code"] == "OFFER_ALREADY_REPORTED" assert OfferReport.query.count() == 1 # no new report assert not mails_testing.outbox
def should_update_quantity_to_booking_amount_for_each_synchronized_stock_on_venue( self, mock_do_sync_venue_provider, app ): # Given titelive = activate_provider(provider_classname="TiteLiveStocks") venue = VenueFactory() offer = OfferFactory(venue=venue, idAtProviders="titelive") stock = StockFactory(offer=offer, quantity=2, lastProviderId=titelive.id, idAtProviders="titelive") booking = BookingFactory(stock=stock) venue_provider = create_venue_provider(venue=venue, provider=titelive) repository.save(venue_provider, booking) # When fully_sync_library(venue_id=venue.id) # Then assert stock.quantity == 1
def test_send_offer_webapp_link_by_email(self, app): offer_id = OfferFactory().id user, test_client = create_user_and_test_client(app) # expected queries: # * get User # * find Offer # * find FeatureToggle WEBAPP_V2_ENABLED (to build URL) # * save email to DB (testing backend) # * release savepoint after saving email with assert_num_queries(5): response = test_client.post( f"/native/v1/send_offer_webapp_link_by_email/{offer_id}") assert response.status_code == 204 assert len(mails_testing.outbox) == 1 mail = mails_testing.outbox[0] assert mail.sent_data["To"] == user.email
def test_get_thing_offer(self, app): product = ProductFactory(thumbCount=1, subcategoryId=subcategories.ABO_MUSEE.id) offer = OfferFactory(product=product, isEducational=True, venue__isPermanent=True) ThingStockFactory(offer=offer, price=12.34) offer_id = offer.id with assert_num_queries(1): response = TestClient( app.test_client()).get(f"/native/v1/offer/{offer_id}") assert response.status_code == 200 assert not response.json["stocks"][0]["beginningDatetime"] assert response.json["stocks"][0]["price"] == 1234 assert response.json["subcategoryId"] == "ABO_MUSEE" assert response.json["isEducational"] assert not response.json["isExpired"] assert response.json["venue"]["isPermanent"]
def test_send_offer_refusing_email(self, ): # Given venue = VenueFactory(name="Sibérie orientale") offer = OfferFactory(name="Michel Strogoff", venue=venue) # When send_offer_validation_status_update_email( offer, OfferValidationStatus.REJECTED, ["*****@*****.**"]) # Then assert len(mails_testing.outbox) == 1 # test number of emails sent assert mails_testing.outbox[0].sent_data["MJ-TemplateID"] == 2613942 assert mails_testing.outbox[0].sent_data["Vars"][ "offer_name"] == "Michel Strogoff" assert mails_testing.outbox[0].sent_data["Vars"][ "venue_name"] == "Sibérie orientale" assert mails_testing.outbox[0].sent_data[ "To"] == "*****@*****.**" assert humanize( offer.id ) in mails_testing.outbox[0].sent_data["Vars"]["pc_pro_offer_link"]
def test_report_offer_malformed(self, app, client): user = UserFactory() offer = OfferFactory() # user.email triggers an SQL request, same for offer.id # therefore, these attributes should be read outside of the # assert_num_queries() block email = user.email offer_id = offer.id # expected queries: # * get user # * rollback with assert_num_queries(2): dst = f"/native/v1/offer/{offer_id}/report" response = client.with_token(email).post(dst, json={"reason": "OTHER"}) assert response.status_code == 400 assert response.json["code"] == "REPORT_MALFORMED" assert OfferReport.query.count() == 0 # no new report assert not mails_testing.outbox