def test_raise_if_trying_to_cancel_someone_else_s_booking(self): booking = factories.BookingFactory() other_user = users_factories.UserFactory() with pytest.raises(exceptions.BookingDoesntExist): api.cancel_booking_by_beneficiary(other_user, booking) assert not booking.isCancelled assert not booking.cancellationReason
def test_raise_if_booking_is_already_used(self): booking = booking_factories.UsedIndividualBookingFactory() with pytest.raises(exceptions.BookingIsAlreadyUsed): api.cancel_booking_by_beneficiary(booking.individualBooking.user, booking) assert not booking.isCancelled assert booking.status is not BookingStatus.CANCELLED
def test_cancel_booking(self): stock = offers_factories.StockFactory(offer__bookingEmail="*****@*****.**") booking = booking_factories.IndividualBookingFactory.create_batch(20, stock=stock)[0] queries = 1 # select booking queries += 1 # select stock for update queries += 1 # refresh booking queries += 3 # update stock ; update booking ; release savepoint queries += 8 # (update batch attributes): select booking ; individualBooking ; user ; user.bookings ; deposit ; user_offerer ; favorites ; stock queries += 1 # select offer queries += 2 # insert email ; release savepoint queries += 4 # (TODO: optimize) select booking ; stock ; offer ; user queries += 1 # select bookings of same stock with users joinedloaded to avoid N+1 requests queries += 2 # select venue ; offerer queries += 2 # insert email ; release savepoint with assert_num_queries(queries): api.cancel_booking_by_beneficiary(booking.individualBooking.user, booking) # cancellation can trigger more than one request to Batch assert len(push_testing.requests) >= 1 assert booking.isCancelled assert booking.status is BookingStatus.CANCELLED assert booking.cancellationReason == BookingCancellationReasons.BENEFICIARY assert len(mails_testing.outbox) == 2 email_data1 = mails_testing.outbox[0].sent_data assert email_data1["Mj-TemplateID"] == 1091464 # to beneficiary email_data2 = mails_testing.outbox[1].sent_data assert email_data2["MJ-TemplateID"] == 780015 # to offerer
def test_raise_if_trying_to_cancel_someone_else_s_booking(self): booking = booking_factories.IndividualBookingFactory() other_beneficiary = users_factories.BeneficiaryGrant18Factory() with pytest.raises(exceptions.BookingDoesntExist): api.cancel_booking_by_beneficiary(other_beneficiary, booking) assert not booking.isCancelled assert booking.status is not BookingStatus.CANCELLED assert not booking.cancellationReason
def test_cancel_booking(self, mocked_send_raw_email): booking = factories.BookingFactory() api.cancel_booking_by_beneficiary(booking.user, booking) assert booking.isCancelled assert booking.cancellationReason == BookingCancellationReasons.BENEFICIARY email_data1 = mocked_send_raw_email.call_args_list[0][1]["data"] assert email_data1["Mj-TemplateID"] == 1091464 # to beneficiary email_data2 = mocked_send_raw_email.call_args_list[1][1]["data"] assert email_data2["MJ-TemplateID"] == 780015 # to offerer
def test_user_can_cancel_even_if_expired_deposit(self): # The user once booked. booking = factories.BookingFactory() user = booking.user booking_to_cancel = factories.BookingFactory(user=user) # But now their deposit expired. self._expire_deposit(user) # They should be able to cancel their booking. api.cancel_booking_by_beneficiary(user, booking_to_cancel) assert booking_to_cancel.isCancelled
def test_cancel_booking(self): booking = factories.BookingFactory() api.cancel_booking_by_beneficiary(booking.user, booking) assert booking.isCancelled assert booking.cancellationReason == BookingCancellationReasons.BENEFICIARY assert len(mails_testing.outbox) == 2 email_data1 = mails_testing.outbox[0].sent_data assert email_data1["Mj-TemplateID"] == 1091464 # to beneficiary email_data2 = mails_testing.outbox[1].sent_data assert email_data2["MJ-TemplateID"] == 780015 # to offerer
def test_raise_if_event_too_close(self): event_date_too_close_to_cancel_booking = datetime.now() + timedelta( days=1) booking = factories.BookingFactory( stock__beginningDatetime=event_date_too_close_to_cancel_booking, ) with pytest.raises(exceptions.CannotCancelConfirmedBooking) as exc: api.cancel_booking_by_beneficiary(booking.user, booking) assert not booking.isCancelled assert not booking.cancellationReason assert exc.value.errors["booking"] == [ "Impossible d'annuler une réservation plus de 48h après l'avoir " "réservée et moins de 48h avant le début de l'événement" ]
def test_cancel_booking(self, app): booking = booking_factories.IndividualBookingFactory(stock__dnBookedQuantity=1) # open a second connection on purpose and lock the stock engine = create_engine(app.config["SQLALCHEMY_DATABASE_URI"]) with engine.connect() as connection: connection.execute( text("""SELECT * FROM stock WHERE stock.id = :stock_id FOR UPDATE"""), stock_id=booking.stockId ) with pytest.raises(sqlalchemy.exc.OperationalError): api.cancel_booking_by_beneficiary(booking.individualBooking.user, booking) assert models.Booking.query.filter().count() == 1 assert models.Booking.query.filter(models.Booking.isCancelled == True).count() == 0
def test_raise_if_event_too_close_and_booked_long_ago(self): booking_date_too_long_ago_to_cancel_booking = datetime.utcnow() - timedelta(days=2, minutes=1) event_date_too_close_to_cancel_booking = datetime.now() + timedelta(days=1) booking = booking_factories.IndividualBookingFactory( stock__beginningDatetime=event_date_too_close_to_cancel_booking, dateCreated=booking_date_too_long_ago_to_cancel_booking, ) with pytest.raises(exceptions.CannotCancelConfirmedBooking) as exc: api.cancel_booking_by_beneficiary(booking.individualBooking.user, booking) assert not booking.isCancelled assert booking.status is not BookingStatus.CANCELLED assert not booking.cancellationReason assert exc.value.errors["booking"] == [ "Impossible d'annuler une réservation plus de 48h après l'avoir " "réservée et moins de 48h avant le début de l'événement" ]
def test_offer_indexation_on_booking_cycle(app): beneficiary = users_factories.BeneficiaryGrant18Factory() stock = offers_factories.StockFactory(quantity=1) offer = stock.offer assert search_testing.search_store["offers"] == {} search.async_index_offer_ids([offer.id]) assert search_testing.search_store["offers"] == {} search.index_offers_in_queue() assert offer.id in search_testing.search_store["offers"] booking = bookings_api.book_offer(beneficiary, stock.id, quantity=1) search.index_offers_in_queue() assert offer.id not in search_testing.search_store["offers"] bookings_api.cancel_booking_by_beneficiary(beneficiary, booking) search.index_offers_in_queue() assert offer.id in search_testing.search_store["offers"]
def test_cancel_booking_twice(self): booking = booking_factories.IndividualBookingFactory() initial_quantity = booking.stock.dnBookedQuantity api.cancel_booking_by_beneficiary(booking.individualBooking.user, booking) # cancellation can trigger more than one request to Batch assert len(push_testing.requests) >= 1 assert booking.isCancelled assert booking.status is BookingStatus.CANCELLED assert booking.stock.dnBookedQuantity == (initial_quantity - 1) api.cancel_booking_by_beneficiary(booking.individualBooking.user, booking) # cancellation can trigger more than one request to Batch assert len(push_testing.requests) >= 1 assert booking.isCancelled assert booking.status is BookingStatus.CANCELLED assert booking.stock.dnBookedQuantity == (initial_quantity - 1)
def cancel_booking(user: User, booking_id: int) -> None: booking = (Booking.query.join(IndividualBooking).filter( Booking.id == booking_id, IndividualBooking.userId == user.id).first_or_404()) try: bookings_api.cancel_booking_by_beneficiary(user, booking) except exceptions.BookingIsAlreadyUsed: raise ApiErrors({ "code": "ALREADY_USED", "message": "La réservation a déjà été utilisée." }) except exceptions.CannotCancelConfirmedBooking: raise ApiErrors({ "code": "CONFIRMED_BOOKING", "message": "La date limite d'annulation est dépassée." }) except RuntimeError: logger.error( "Unexpected call to cancel_booking_by_beneficiary with non-beneficiary user %s", user.id) raise ApiErrors()
def cancel_booking(booking_id: str): booking = Booking.query.filter_by(id=dehumanize(booking_id)).first_or_404() bookings_api.cancel_booking_by_beneficiary(current_user, booking) return jsonify(serialize_booking_minimal(booking)), 200
def test_raise_if_booking_is_already_used(self): booking = factories.BookingFactory(isUsed=True) with pytest.raises(exceptions.BookingIsAlreadyUsed): api.cancel_booking_by_beneficiary(booking.user, booking) assert not booking.isCancelled
def test_do_not_sync_algolia_if_feature_is_disabled( self, mocked_add_offer_id): booking = factories.BookingFactory() api.cancel_booking_by_beneficiary(booking.user, booking) mocked_add_offer_id.assert_not_called()