def should_invalidate_booking_token_when_event_is_reported( self, mock_update_confirmation_dates): # Given now = datetime.now() booking_made_3_days_ago = now - timedelta(days=3) event_in_4_days = now + timedelta(days=4) event_reported_in_10_days = now + timedelta(days=10) offer = factories.EventOfferFactory() existing_stock = factories.StockFactory( offer=offer, beginningDatetime=event_in_4_days) booking = bookings_factories.BookingFactory( stock=existing_stock, dateCreated=booking_made_3_days_ago, isUsed=True) edited_stock_data = StockEditionBodyModel( id=existing_stock.id, beginningDatetime=event_reported_in_10_days, bookingLimitDatetime=existing_stock.bookingLimitDatetime, price=2, ) # When api.upsert_stocks(offer_id=offer.id, stock_data_list=[edited_stock_data]) # Then updated_booking = Booking.query.get(booking.id) assert updated_booking.isUsed is False assert updated_booking.dateUsed is None assert updated_booking.confirmationDate == booking.confirmationDate
def test_sends_email_if_beginning_date_changes_on_edition( self, mocked_send_email): # Given offer = factories.EventOfferFactory() existing_stock = factories.StockFactory(offer=offer, price=10) beginning = datetime.now() + timedelta(days=10) edited_stock_data = StockEditionBodyModel( id=existing_stock.id, beginningDatetime=beginning, bookingLimitDatetime=existing_stock.bookingLimitDatetime, price=2, ) booking = bookings_factories.BookingFactory(stock=existing_stock) bookings_factories.BookingFactory(stock=existing_stock, isCancelled=True) # When api.upsert_stocks(offer_id=offer.id, stock_data_list=[edited_stock_data]) # Then stock = models.Stock.query.one() assert stock.beginningDatetime == beginning notified_bookings = mocked_send_email.call_args_list[0][0][0] assert notified_bookings == [booking]
def should_update_bookings_confirmation_date_if_report_of_event( self, mock_update_confirmation_dates): # Given now = datetime.now() event_in_4_days = now + timedelta(days=4) event_reported_in_10_days = now + timedelta(days=10) offer = factories.EventOfferFactory() existing_stock = factories.StockFactory( offer=offer, beginningDatetime=event_in_4_days) booking = bookings_factories.BookingFactory(stock=existing_stock, dateCreated=now) edited_stock_data = StockEditionBodyModel( id=existing_stock.id, beginningDatetime=event_reported_in_10_days, bookingLimitDatetime=existing_stock.bookingLimitDatetime, price=2, ) # When api.upsert_stocks(offer_id=offer.id, stock_data_list=[edited_stock_data]) # Then mock_update_confirmation_dates.assert_called_once_with( [booking], event_reported_in_10_days)
def test_fail_if_missing_dates(self): offer = factories.EventOfferFactory() with pytest.raises(api_errors.ApiErrors) as error: api.create_stock(offer=offer, price=10, beginning=None, booking_limit_datetime=None) assert "beginningDatetime" in error.value.errors
def when_beginning_and_booking_limit_datetime_are_updated_for_event( self, app): # given offer = offers_factories.EventOfferFactory() offers_factories.UserOffererFactory( user__email="*****@*****.**", offerer=offer.venue.managingOfferer, ) stock = offers_factories.StockFactory( offer=offer, price=100, quantity=10, ) # when client = TestClient(app.test_client()).with_auth("*****@*****.**") beginning = datetime(2020, 1, 1, 12, 0, 0) booking_limit = datetime(2020, 1, 1, 10, 0, 0) data = { "price": 20, "quantity": 5, "beginningDatetime": beginning.isoformat(), "bookingLimitDatetime": booking_limit.isoformat(), } response = client.patch(f"/stocks/{humanize(stock.id)}", json=data) # then assert response.status_code == 200 stock = Stock.query.one() assert stock.price == 20 assert stock.quantity == 5 assert stock.beginningDatetime == beginning assert stock.bookingLimitDatetime == booking_limit
def test_event_offer(self): offer = factories.EventOfferFactory() first = datetime.datetime.now() + datetime.timedelta(days=1) last = datetime.datetime.now() + datetime.timedelta(days=5) factories.StockFactory(offer=offer, beginningDatetime=first) factories.StockFactory(offer=offer, beginningDatetime=last) assert offer.dateRange == DateTimes(first, last)
def when_booking_limit_datetime_after_beginning_datetime( self, app, db_session): # Given user = users_factories.UserFactory(isAdmin=True) offer = offers_factories.EventOfferFactory() beginningDatetime = datetime(2019, 2, 14) data = { "price": 1222, "offerId": humanize(offer.id), "beginningDatetime": serialize(beginningDatetime), "bookingLimitDatetime": serialize(beginningDatetime + timedelta(days=2)), } # When response = TestClient(app.test_client()).with_auth(user.email).post( "/stocks", json=data) # Then assert response.status_code == 400 assert response.json == { "bookingLimitDatetime": [ "La date limite de réservation pour cette offre est postérieure à la date de début de l'évènement" ] }
def test_does_not_allow_edition_of_beginningDateTime_for_stocks_of_offers_synchronized_with_allocine( self, mock_update_confirmation_dates): # Given offer = factories.EventOfferFactory( lastProvider=offerers_factories.ProviderFactory( localClass="AllocineStocks")) date_in_the_future = datetime.utcnow() + timedelta(days=4) other_date_in_the_future = datetime.utcnow() + timedelta(days=6) existing_stock = factories.StockFactory( offer=offer, price=10, beginningDatetime=date_in_the_future) edited_stock_data = StockEditionBodyModel( id=existing_stock.id, beginningDatetime=other_date_in_the_future, bookingLimitDatetime=other_date_in_the_future, price=10, ) # When with pytest.raises(api_errors.ApiErrors) as error: api.upsert_stocks(offer_id=offer.id, stock_data_list=[edited_stock_data]) # Then assert error.value.errors == { "global": [ "Pour les offres importées, certains champs ne sont pas modifiables" ] }
def should_not_invalidate_booking_token_when_event_is_reported_in_less_than_48_hours( self, mock_mark_as_unused, mock_update_confirmation_dates): # Given now = datetime.now() date_used_in_48_hours = datetime.now() + timedelta(days=2) event_in_3_days = now + timedelta(days=3) event_reported_in_less_48_hours = now + timedelta(days=1) offer = factories.EventOfferFactory() existing_stock = factories.StockFactory( offer=offer, beginningDatetime=event_in_3_days) booking = bookings_factories.BookingFactory( stock=existing_stock, dateCreated=now, isUsed=True, dateUsed=date_used_in_48_hours) edited_stock_data = StockEditionBodyModel( id=existing_stock.id, beginningDatetime=event_reported_in_less_48_hours, bookingLimitDatetime=existing_stock.bookingLimitDatetime, price=2, ) # When api.upsert_stocks(offer_id=offer.id, stock_data_list=[edited_stock_data]) # Then updated_booking = Booking.query.get(booking.id) assert updated_booking.isUsed is True assert updated_booking.dateUsed == date_used_in_48_hours
def test_event_offer_ok_with_beginning_and_booking_limit_datetime(self): offer = factories.EventOfferFactory() validation.check_required_dates_for_stock( offer, beginning=datetime.datetime.now(), booking_limit_datetime=datetime.datetime.now(), )
def test_event_prices(self): offer = offers_factories.EventOfferFactory() validation.check_stock_price(0, offer) validation.check_stock_price(1.5, offer) validation.check_stock_price(310.5, offer) with pytest.raises(ApiErrors) as error: validation.check_stock_price(-1.5, offer) assert error.value.errors["price"] == ["Le prix doit être positif"]
def test_event_offer_must_have_booking_limit_datetime(self): offer = factories.EventOfferFactory() with pytest.raises(ApiErrors) as error: validation.check_required_dates_for_stock( offer, beginning=datetime.datetime.now(), booking_limit_datetime=None, ) assert error.value.errors["bookingLimitDatetime"] == ["Ce paramètre est obligatoire"]
def create_event_booking(quantity=1, price=10, user=None, date_created=None): booking_kwargs = {} if user: booking_kwargs["user"] = user if date_created: booking_kwargs["dateCreated"] = date_created user = user or users_factories.UserFactory() stock = offers_factories.StockFactory( price=price, offer=offers_factories.EventOfferFactory(), ) return bookings_factories.BookingFactory(stock=stock, quantity=quantity, **booking_kwargs)
def test_when_user_has_rights_and_regular_offer(self, client): # Given past = datetime.now() - timedelta(days=2) booking = bookings_factories.IndividualBookingFactory( individualBooking__user__email="*****@*****.**", stock__beginningDatetime=past, stock__offer=offers_factories.EventOfferFactory( extraData={ "theater": { "allocine_movie_id": 165, "allocine_room_id": 987, }, }, subcategoryId=subcategories.CARTE_CINE_MULTISEANCES.id, product__name="An offer you cannot refuse", venue__name="Le Petit Rintintin", ), ) user_offerer = offers_factories.UserOffererFactory(offerer=booking.offerer) pro_user = user_offerer.user # When client = client.with_basic_auth(pro_user.email) response = client.get(f"/v2/bookings/token/{booking.token}") # Then assert response.headers["Content-type"] == "application/json" assert response.status_code == 200 assert response.json == { "bookingId": humanize(booking.id), "dateOfBirth": "", "datetime": format_into_utc_date(booking.stock.beginningDatetime), "ean13": None, "email": "*****@*****.**", "formula": "ABO", "isUsed": False, "offerId": booking.stock.offerId, "offerName": "An offer you cannot refuse", "offerType": "EVENEMENT", "phoneNumber": "", "price": 10.0, "publicOfferId": humanize(booking.stock.offerId), "quantity": 1, "theater": { "allocine_movie_id": 165, "allocine_room_id": 987, }, "userName": "******", "venueAddress": "1 boulevard Poissonnière", "venueDepartmentCode": "75", "venueName": "Le Petit Rintintin", }
def create_event_booking(quantity=1, price=10, user=None, date_used=None): booking_kwargs = {} if user: booking_kwargs["user"] = user booking_kwargs["dateUsed"] = date_used or datetime.now() user = user or users_factories.BeneficiaryGrant18Factory() stock = offers_factories.StockFactory( price=price, offer=offers_factories.EventOfferFactory(), ) return bookings_factories.UsedBookingFactory(stock=stock, quantity=quantity, **booking_kwargs)
def test_with_virtual_offer(self): # Given author = users_factories.ProFactory() offer = offers_factories.EventOfferFactory( author=author, product=offers_factories.DigitalProductFactory( name="Les lièvres pas malins"), venue=offers_factories.VirtualVenueFactory(), ) # When email = make_offer_creation_notification_email(offer) # Then assert email[ "Subject"] == "[Création d’offre - numérique] Les lièvres pas malins"
def test_does_not_allow_missing_dates_for_an_event_offer_on_creation_and_edition( self, mock_update_confirmation_dates): # Given offer = factories.EventOfferFactory() created_stock_data = StockCreationBodyModel(price=10, beginningDatetime=None, bookingLimitDatetime=None) # When with pytest.raises(api_errors.ApiErrors) as error: api.upsert_stocks(offer_id=offer.id, stock_data_list=[created_stock_data]) # Then assert error.value.errors == { "beginningDatetime": ["Ce paramètre est obligatoire"] }
def get_existing_pro_validated_user_with_validated_offerer_with_iban_validated_user_offerer_with_event_offer_with_no_stock( ): user_offerer = offers_factories.UserOffererFactory( validationToken=None, offerer__validationToken=None, user__validationToken=None, ) offers_factories.BankInformationFactory(offerer=user_offerer.offerer) venue = offers_factories.VirtualVenueFactory( managingOfferer=user_offerer.offerer) offer = offers_factories.EventOfferFactory(venue=venue, isActive=True) return { "offer": get_offer_helper(offer), "offerer": get_offerer_helper(user_offerer.offerer), "user": get_pro_helper(user_offerer.user), "venue": get_venue_helper(venue), }
def test_create_event_offer(self): offer = factories.EventOfferFactory() beginning = datetime.datetime(2024, 1, 1, 12, 0, 0) booking_limit = datetime.datetime(2024, 1, 1, 9, 0, 0) stock = api.create_stock( offer=offer, price=10, quantity=7, beginning=beginning, booking_limit_datetime=booking_limit, ) assert stock.offer == offer assert stock.price == 10 assert stock.quantity == 7 assert stock.beginningDatetime == beginning assert stock.bookingLimitDatetime == booking_limit
def test_should_only_index_bookable_offers_stock(self): offer = offers_factories.EventOfferFactory() _not_bookable_stock = offers_factories.EventStockFactory( beginningDatetime=datetime(2019, 1, 5), bookingLimitDatetime=datetime(2019, 1, 3), offer=offer, quantity=1, ) bookable_stock = offers_factories.EventStockFactory( beginningDatetime=datetime(2019, 1, 12), bookingLimitDatetime=datetime(2019, 1, 10), offer=offer, quantity=1, ) data = _build_offer_details_to_be_indexed(offer) assert data["dates"] == [ datetime.timestamp(bookable_stock.beginningDatetime) ]
def test_should_return_mailjet_data_with_correct_information_when_offer_is_an_event(self, build_pc_pro_offer_link): # Given beneficiary = users_factories.BeneficiaryGrant18Factory( publicName="John Doe", firstName="John", lastName="Doe", email="*****@*****.**" ) offer = offer_factories.EventOfferFactory( venue__name="Venue name", product__name="My Event", ) booking = booking_factories.IndividualBookingFactory( user=beneficiary, individualBooking__user=beneficiary, stock__offer=offer, stock__beginningDatetime=datetime(2019, 10, 9, 10, 20, 00), stock__price=12.52, quantity=2, token="12345", ) bookings = [booking] # When mailjet_data = retrieve_offerer_bookings_recap_email_data_after_offerer_cancellation(bookings) # Then assert mailjet_data == { "MJ-TemplateID": 1116333, "MJ-TemplateLanguage": True, "Vars": { "offer_name": "My Event", "lien_offre_pcpro": "http://pc_pro.com/offer_link", "venue_name": "Venue name", "price": "12.52", "is_event": 1, "event_date": "09-Oct-2019", "event_hour": "12h20", "quantity": 2, "reservations_number": 1, "users": [ {"countermark": "12345", "email": "*****@*****.**", "firstName": "John", "lastName": "Doe"} ], }, }
def when_invalid_format_for_booking_limit_datetime(self, app, db_session): # Given user = users_factories.UserFactory(isAdmin=True) offer = offers_factories.EventOfferFactory() data = { "price": 0, "offerId": humanize(offer.id), "beginningDatetime": "2020-10-11T00:00:00Z", "bookingLimitDatetime": "zbbopbjeo", } # When response = TestClient(app.test_client()).with_auth(user.email).post( "/stocks", json=data) # Then assert response.status_code == 400 assert response.json == { "bookingLimitDatetime": ["Format de date invalide"] }
def when_booking_limit_datetime_is_none_for_event(self, app, db_session): # Given user = users_factories.UserFactory(isAdmin=True) offer = offers_factories.EventOfferFactory() beginningDatetime = datetime(2019, 2, 14) data = { "price": 0, "offerId": humanize(offer.id), "bookingLimitDatetime": None, "beginningDatetime": serialize(beginningDatetime), } # When response = TestClient(app.test_client()).with_auth(user.email).post( "/stocks", json=data) # Then assert response.status_code == 400 assert response.json == { "bookingLimitDatetime": ["Ce paramètre est obligatoire"] }
def test_does_not_allow_booking_limit_after_beginning_for_an_event_offer_on_creation_and_edition( self, mock_update_confirmation_dates): # Given offer = factories.EventOfferFactory() beginning_date = datetime.utcnow() + timedelta(days=4) booking_limit = beginning_date + timedelta(days=4) created_stock_data = StockCreationBodyModel( price=10, beginningDatetime=beginning_date, bookingLimitDatetime=booking_limit) # When with pytest.raises(api_errors.ApiErrors) as error: api.upsert_stocks(offer_id=offer.id, stock_data_list=[created_stock_data]) # Then assert error.value.errors == { "bookingLimitDatetime": [ "La date limite de réservation pour cette offre est postérieure à la date de début de l'évènement" ] }
def test_allow_edition_of_price_and_quantity_for_stocks_of_offers_synchronized_with_allocine( self, mock_update_confirmation_dates): # Given offer = factories.EventOfferFactory( lastProvider=offerers_factories.ProviderFactory( localClass="AllocineStocks")) date_in_the_future = datetime.utcnow() + timedelta(days=4) existing_stock = factories.StockFactory( offer=offer, price=10, beginningDatetime=date_in_the_future) edited_stock_data = StockEditionBodyModel( id=existing_stock.id, beginningDatetime=existing_stock.beginningDatetime, bookingLimitDatetime=existing_stock.bookingLimitDatetime, price=4, ) # When api.upsert_stocks(offer_id=offer.id, stock_data_list=[edited_stock_data]) # Then edited_stock = Stock.query.filter_by(id=existing_stock.id).first() assert edited_stock.price == 4
def test_deleted_stock_is_ignored(self): offer = factories.EventOfferFactory() factories.StockFactory(offer=offer, isSoftDeleted=True) assert offer.dateRange == DateTimes()
def test_no_stock(self): offer = factories.EventOfferFactory() assert offer.dateRange == DateTimes()
def test_single_stock(self): offer = factories.EventOfferFactory() stock = factories.StockFactory(offer=offer) assert offer.dateRange == DateTimes(stock.beginningDatetime, stock.beginningDatetime)
def test_find_filtered_offerers_with_keywords(self): offerer_with_only_virtual_venue_with_offer = offerers_factories.OffererFactory(siren="123456785") offerer_with_both_venues_offer_on_both = offerers_factories.OffererFactory(siren="123456782") offerer_with_both_venues_offer_on_virtual = offerers_factories.OffererFactory(siren="123456783") offerer_with_both_venues_offer_on_not_virtual = offerers_factories.OffererFactory(siren="123456784") virtual_venue_with_offer_1 = offers_factories.VenueFactory( managingOfferer=offerer_with_only_virtual_venue_with_offer, isVirtual=True, siret=None ) virtual_venue_with_offer_3 = offers_factories.VenueFactory( managingOfferer=offerer_with_both_venues_offer_on_both, isVirtual=True, siret=None, publicName="Librairie des mots perdus", ) venue_with_offer_3 = offers_factories.VenueFactory( managingOfferer=offerer_with_both_venues_offer_on_both, siret="12345678212345", publicName="Librairie des mots perdus", ) virtual_venue_with_offer_4 = offers_factories.VenueFactory( managingOfferer=offerer_with_both_venues_offer_on_virtual, isVirtual=True, siret=None, publicName="Librairie des mots perdus", ) venue_with_offer_5 = offers_factories.VenueFactory( managingOfferer=offerer_with_both_venues_offer_on_not_virtual, siret="12345678412345", publicName="Librairie des mots perdus", ) offers_factories.VenueFactory(publicName="something else") offers_factories.ThingOfferFactory(venue=virtual_venue_with_offer_1, url="http://url.com") offers_factories.ThingOfferFactory(venue=virtual_venue_with_offer_3, url="http://url.com") offers_factories.ThingOfferFactory(venue=virtual_venue_with_offer_4, url="http://url.com") offers_factories.EventOfferFactory(venue=venue_with_offer_3) offers_factories.EventOfferFactory(venue=venue_with_offer_5) one_keyword_search = filter_offerers_with_keywords_string(Offerer.query.join(Venue), "perdus") partial_keyword_search = filter_offerers_with_keywords_string(Offerer.query.join(Venue), "Libr") two_keywords_search = filter_offerers_with_keywords_string(Offerer.query.join(Venue), "Librairie perd") two_partial_keywords_search = filter_offerers_with_keywords_string(Offerer.query.join(Venue), "Lib perd") assert { offerer_with_both_venues_offer_on_both, offerer_with_both_venues_offer_on_virtual, offerer_with_both_venues_offer_on_not_virtual, } == set(one_keyword_search) assert { offerer_with_both_venues_offer_on_both, offerer_with_both_venues_offer_on_virtual, offerer_with_both_venues_offer_on_not_virtual, } == set(partial_keyword_search) assert { offerer_with_both_venues_offer_on_both, offerer_with_both_venues_offer_on_virtual, offerer_with_both_venues_offer_on_not_virtual, } == set(two_keywords_search) assert { offerer_with_both_venues_offer_on_both, offerer_with_both_venues_offer_on_virtual, offerer_with_both_venues_offer_on_not_virtual, } == set(two_partial_keywords_search)