def test_should_cancel_old_thing_that_can_expire_booking(self, app) -> None: now = datetime.utcnow() eleven_days_ago = now - timedelta(days=11) two_months_ago = now - timedelta(days=60) book = ProductFactory(subcategoryId=subcategories.LIVRE_PAPIER.id) old_book_booking = booking_factories.IndividualBookingFactory( stock__offer__product=book, dateCreated=eleven_days_ago) dvd = ProductFactory( subcategoryId=subcategories.SUPPORT_PHYSIQUE_FILM.id) old_dvd_booking = booking_factories.IndividualBookingFactory( stock__offer__product=dvd, dateCreated=two_months_ago) handle_expired_bookings.cancel_expired_individual_bookings() assert old_book_booking.isCancelled assert old_book_booking.status is BookingStatus.CANCELLED assert old_book_booking.cancellationDate.timestamp() == pytest.approx( datetime.utcnow().timestamp(), rel=1) assert old_book_booking.cancellationReason == BookingCancellationReasons.EXPIRED assert old_book_booking.stock.dnBookedQuantity == 0 assert old_dvd_booking.isCancelled assert old_dvd_booking.status is BookingStatus.CANCELLED assert old_dvd_booking.cancellationDate.timestamp() == pytest.approx( datetime.utcnow().timestamp(), rel=1) assert old_dvd_booking.cancellationReason == BookingCancellationReasons.EXPIRED assert old_dvd_booking.stock.dnBookedQuantity == 0
def should_only_cancel_old_thing_that_can_expire_bookings_before_start_date( self, app) -> None: now = datetime.utcnow() two_months_ago = now - timedelta(days=60) guitar = ProductFactory( subcategoryId=subcategories.ACHAT_INSTRUMENT.id, ) old_guitar_booking = booking_factories.IndividualBookingFactory( stock__offer__product=guitar, dateCreated=two_months_ago) disc = ProductFactory( subcategoryId=subcategories.SUPPORT_PHYSIQUE_MUSIQUE.id) old_disc_booking = booking_factories.IndividualBookingFactory( stock__offer__product=disc, dateCreated=two_months_ago) vod = ProductFactory(subcategoryId=subcategories.VOD.id) old_vod_booking = booking_factories.IndividualBookingFactory( stock__offer__product=vod, dateCreated=two_months_ago) handle_expired_bookings.cancel_expired_individual_bookings() assert old_guitar_booking.isCancelled assert old_guitar_booking.status is BookingStatus.CANCELLED assert old_guitar_booking.cancellationDate.timestamp( ) == pytest.approx(datetime.utcnow().timestamp(), rel=1) assert old_guitar_booking.cancellationReason == BookingCancellationReasons.EXPIRED assert old_disc_booking.isCancelled assert old_disc_booking.status is BookingStatus.CANCELLED assert old_disc_booking.cancellationDate.timestamp() == pytest.approx( datetime.utcnow().timestamp(), rel=1) assert old_disc_booking.cancellationReason == BookingCancellationReasons.EXPIRED assert not old_vod_booking.isCancelled assert old_vod_booking.status is not BookingStatus.CANCELLED assert not old_vod_booking.cancellationDate assert not old_vod_booking.cancellationReason
def test_handle_expired_bookings_should_cancel_expired_individual_and_educational_bookings( self, app) -> None: # Given now = datetime.utcnow() yesterday = now - timedelta(days=1) two_months_ago = now - timedelta(days=60) tomorrow = now + timedelta(days=1) expired_pending_educational_booking: Booking = booking_factories.PendingEducationalBookingFactory( educationalBooking__confirmationLimitDate=yesterday) non_expired_pending_educational_booking: Booking = booking_factories.PendingEducationalBookingFactory( educationalBooking__confirmationLimitDate=tomorrow) dvd = ProductFactory( subcategoryId=subcategories.SUPPORT_PHYSIQUE_FILM.id) expired_individual_booking = booking_factories.IndividualBookingFactory( stock__offer__product=dvd, dateCreated=two_months_ago) book = ProductFactory(subcategoryId=subcategories.LIVRE_PAPIER.id) book_individual_recent_booking = booking_factories.IndividualBookingFactory( stock__offer__product=book) # When handle_expired_bookings.handle_expired_bookings() # Then assert expired_pending_educational_booking.status == BookingStatus.CANCELLED assert expired_individual_booking.status == BookingStatus.CANCELLED assert book_individual_recent_booking.status != BookingStatus.CANCELLED assert non_expired_pending_educational_booking.status == BookingStatus.PENDING
def test_fill_individual_booking_deposit_id(caplog): already_filled_bookings = bookings_factories.IndividualBookingFactory.create_batch(3) db.session.execute("ALTER TABLE booking DISABLE TRIGGER booking_update;") to_update_bookings = bookings_factories.IndividualBookingFactory.create_batch( 3, individualBooking__attached_deposit="forced_none" ) not_updated_booking = bookings_factories.IndividualBookingFactory( amount=0, dateCreated=(datetime.utcnow() + relativedelta(years=3)), individualBooking__attached_deposit="forced_none", ) warning_booking = bookings_factories.IndividualBookingFactory( amount=10, dateCreated=(datetime.utcnow() + relativedelta(years=3)), individualBooking__attached_deposit="forced_none", ) db.session.execute("ALTER TABLE booking ENABLE TRIGGER booking_update;") with caplog.at_level(logging.WARNING): fill_individual_booking_deposit_id(3) for booking in already_filled_bookings + to_update_bookings: assert booking.individualBooking.depositId == booking.individualBooking.user.deposit.id assert not not_updated_booking.individualBooking.depositId assert not warning_booking.individualBooking.depositId assert caplog.messages == [f"Booking with amount > 0 made after deposit expiration date id={warning_booking.id}"]
def test_should_send_two_emails_to_offerer_when_expired_books_bookings_and_other_bookings_cancelled( self): offerer = OffererFactory() expired_today_dvd_booking = booking_factories.IndividualBookingFactory( stock__offer__name="Intouchables", stock__offer__bookingEmail="*****@*****.**", stock__offer__subcategoryId=subcategories.SUPPORT_PHYSIQUE_FILM.id, ) expired_today_book_booking = booking_factories.IndividualBookingFactory( stock__offer__name="Les misérables", stock__offer__bookingEmail="*****@*****.**", stock__offer__subcategoryId=subcategories.LIVRE_PAPIER.id, ) send_expired_individual_bookings_recap_email_to_offerer( offerer, [expired_today_dvd_booking, expired_today_book_booking]) assert len(mails_testing.outbox) == 2 assert mails_testing.outbox[0].sent_data["Mj-TemplateID"] == 3095184 assert mails_testing.outbox[0].sent_data["Vars"][ "withdrawal_period"] == 10 assert mails_testing.outbox[0].sent_data["Vars"]["bookings"][0][ "offer_name"] == "Les misérables" assert mails_testing.outbox[1].sent_data["Mj-TemplateID"] == 3095184 assert mails_testing.outbox[1].sent_data["Vars"][ "withdrawal_period"] == 30 assert mails_testing.outbox[1].sent_data["Vars"]["bookings"][0][ "offer_name"] == "Intouchables"
def test_cancel_all_bookings_from_stock(self, app): stock = offers_factories.StockFactory(dnBookedQuantity=1) booking_1 = booking_factories.IndividualBookingFactory(stock=stock) booking_2 = booking_factories.IndividualBookingFactory(stock=stock) used_booking = booking_factories.UsedIndividualBookingFactory(stock=stock) cancelled_booking = booking_factories.CancelledIndividualBookingFactory(stock=stock) api.cancel_bookings_when_offerer_deletes_stock(stock) # cancellation can trigger more than one request to Batch assert len(push_testing.requests) >= 1 assert models.Booking.query.filter().count() == 4 assert models.Booking.query.filter(models.Booking.isCancelled == True).count() == 3 assert models.Booking.query.filter(models.Booking.isUsed == True).count() == 1 assert booking_1.isCancelled assert booking_1.status is BookingStatus.CANCELLED assert booking_1.cancellationReason == BookingCancellationReasons.OFFERER assert booking_2.isCancelled assert booking_2.status is BookingStatus.CANCELLED assert booking_2.cancellationReason == BookingCancellationReasons.OFFERER assert not used_booking.isCancelled assert used_booking.status is not BookingStatus.CANCELLED assert not used_booking.cancellationReason assert cancelled_booking.isCancelled assert cancelled_booking.status is BookingStatus.CANCELLED assert cancelled_booking.cancellationReason == BookingCancellationReasons.BENEFICIARY
def test_make_offerer_driven_cancellation_email_for_offerer_event_when_other_booking( self, app): # Given other_beneficiary = users_factories.BeneficiaryGrant18Factory() stock = offers_factories.EventStockFactory(beginningDatetime=datetime( 2019, 7, 20, 12, 0, 0, tzinfo=timezone.utc), price=20, quantity=10) booking1 = bookings_factories.IndividualBookingFactory(stock=stock, token="98765") booking2 = bookings_factories.IndividualBookingFactory( individualBooking__user=other_beneficiary, stock=stock, token="12345") # When with patch("pcapi.utils.mailing.find_ongoing_bookings_by_stock", return_value=[booking2]): email = make_offerer_driven_cancellation_email_for_offerer( booking1) # Then email_html = BeautifulSoup(email["Html-part"], "html.parser") html_recap_table = email_html.find("table", {"id": "recap-table"}).text assert "Prénom" in html_recap_table assert "Nom" in html_recap_table assert "Email" in html_recap_table assert other_beneficiary.firstName in html_recap_table assert other_beneficiary.lastName in html_recap_table assert other_beneficiary.email in html_recap_table assert booking2.token in html_recap_table
def test_should_return_mailjet_data_when_multiple_bookings_and_offer_is_a_thing(self, build_pc_pro_offer_link): # Given beneficiary = users_factories.BeneficiaryGrant18Factory( publicName="John Doe", firstName="John", lastName="Doe", email="*****@*****.**" ) offer = offer_factories.ThingOfferFactory( venue__name="La petite librairie", venue__publicName="La grande librairie", product__name="Le récit de voyage", ) booking = booking_factories.IndividualBookingFactory( user=beneficiary, individualBooking__user=beneficiary, stock__offer=offer, stock__price=0, token="12346", quantity=6, ) other_beneficiary = users_factories.BeneficiaryGrant18Factory( publicName="James Bond", firstName="James", lastName="Bond", email="*****@*****.**" ) booking2 = booking_factories.IndividualBookingFactory( user=other_beneficiary, individualBooking__user=other_beneficiary, stock__offer=offer, stock__price=0, token="12345", quantity=1, ) bookings = [booking, booking2] # 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": "Le récit de voyage", "lien_offre_pcpro": "http://pc_pro.com/offer_link", "venue_name": "La grande librairie", "price": "Gratuit", "is_event": 0, "event_date": "", "event_hour": "", "quantity": 7, "reservations_number": 2, "users": [ {"countermark": "12346", "email": "*****@*****.**", "firstName": "John", "lastName": "Doe"}, {"countermark": "12345", "email": "*****@*****.**", "firstName": "James", "lastName": "Bond"}, ], }, }
def test_should_send_two_emails_to_beneficiary_when_they_book_and_other_things_have_soon_to_be_expired_bookings( self, build_soon_to_be_expired_bookings_recap_email_data_for_beneficiary ): # given now = datetime.utcnow() user = users_factories.BeneficiaryGrant18Factory( email="*****@*****.**") created_5_days_ago = now - timedelta(days=5) created_23_days_ago = now - timedelta(days=23) book = ProductFactory(subcategoryId=subcategories.LIVRE_PAPIER.id) soon_to_be_expired_book_booking = booking_factories.IndividualBookingFactory( stock__offer__product=book, stock__offer__name="Fondation", stock__offer__venue__name="Première Fondation", dateCreated=created_5_days_ago, user=user, ) cd = ProductFactory( subcategoryId=subcategories.SUPPORT_PHYSIQUE_MUSIQUE.id) soon_to_be_expired_cd_booking = booking_factories.IndividualBookingFactory( stock__offer__product=cd, stock__offer__name="Fondation et Empire", stock__offer__venue__name="Seconde Fondation", dateCreated=created_23_days_ago, user=user, ) # when send_soon_to_be_expired_individual_bookings_recap_email_to_beneficiary( user, [soon_to_be_expired_book_booking, soon_to_be_expired_cd_booking]) # then call1 = call(beneficiary=user, bookings=[soon_to_be_expired_book_booking], days_before_cancel=5, days_from_booking=5) call2 = call(beneficiary=user, bookings=[soon_to_be_expired_cd_booking], days_before_cancel=7, days_from_booking=23) calls = [call1, call2] build_soon_to_be_expired_bookings_recap_email_data_for_beneficiary.assert_has_calls( calls, any_order=False) assert build_soon_to_be_expired_bookings_recap_email_data_for_beneficiary.call_count == 2 assert len(mails_testing.outbox) == 2 # test number of emails sent assert mails_testing.outbox[0].sent_data["MJ-TemplateID"] == 12345 assert mails_testing.outbox[1].sent_data["MJ-TemplateID"] == 12345
def test_should_send_email_to_offerer_when_expired_bookings_cancelled( self, app): offerer = OffererFactory() expired_today_dvd_booking = booking_factories.IndividualBookingFactory( stock__offer__bookingEmail="*****@*****.**") expired_today_cd_booking = booking_factories.IndividualBookingFactory( stock__offer__bookingEmail="*****@*****.**") send_expired_individual_bookings_recap_email_to_offerer( offerer, [expired_today_cd_booking, expired_today_dvd_booking]) assert len(mails_testing.outbox) == 1 assert mails_testing.outbox[0].sent_data["Mj-TemplateID"] == 3095184 assert mails_testing.outbox[0].sent_data["Vars"]
def test_insufficient_funds_when_user_has_negative_deposit(self): # The user once booked. user = users_factories.BeneficiaryGrant18Factory(deposit__version=1) factories.IndividualBookingFactory(individualBooking__user=user) assert user.wallet_balance == 490 # But now their deposit expired. self._expire_deposit(user) # They are not allowed to book non-free offers anymore. with pytest.raises(sqlalchemy.exc.InternalError) as exc: factories.IndividualBookingFactory(individualBooking__user=user) assert "insufficientFunds" in exc.args[0]
def test_user_can_cancel_even_if_expired_deposit(self): # The user once booked. booking = factories.IndividualBookingFactory() user = booking.individualBooking.user booking_to_cancel = factories.IndividualBookingFactory( individualBooking__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 assert booking_to_cancel.status is BookingStatus.CANCELLED
def should_update_bookings_cancellation_limit_dates_for_event_beginning_in_a_week(self): # Given recent_booking = booking_factories.IndividualBookingFactory( stock__beginningDatetime=datetime.now() + timedelta(days=90) ) old_booking = booking_factories.IndividualBookingFactory( stock=recent_booking.stock, dateCreated=(datetime.now() - timedelta(days=7)) ) # When updated_bookings = api.update_cancellation_limit_dates( bookings_to_update=[recent_booking, old_booking], new_beginning_datetime=datetime.now() + timedelta(days=7) ) # Then assert updated_bookings == [recent_booking, old_booking] assert recent_booking.cancellationLimitDate == old_booking.cancellationLimitDate == datetime(2020, 11, 19, 15)
def test_should_return_bookings_by_beneficiary_id(self, app): # Given beneficiary_1 = BeneficiaryGrant18Factory() beneficiary_2 = BeneficiaryGrant18Factory() offer = EventOfferFactory() stock = EventStockFactory(offer=offer) booking1 = booking_factories.IndividualBookingFactory(individualBooking__user=beneficiary_1, stock=stock) booking_factories.IndividualBookingFactory(individualBooking__user=beneficiary_2, stock=stock) # When result = BeneficiaryBookingsSQLRepository().get_beneficiary_bookings(beneficiary_id=beneficiary_1.id) # Then assert len(result.bookings) == 1 assert result.bookings[0].id == booking1.id
def test_deposit_balance(self): deposit = users_factories.DepositGrantFactory() bookings_factories.IndividualBookingFactory( individualBooking__attached_deposit=deposit, isUsed=True, amount=10) bookings_factories.IndividualBookingFactory( individualBooking__attached_deposit=deposit, isUsed=False, amount=1) assert db.session.query(func.get_deposit_balance( deposit.id, False)).first()[0] == 289 assert db.session.query(func.get_deposit_balance( deposit.id, True)).first()[0] == 290
def test_should_returns_204_with_cancellation_allowed(self, client): # Given stock = offers_factories.EventStockFactory( offer__name="Chouette concert") booking = bookings_factories.IndividualBookingFactory(stock=stock) ApiKeyFactory(offerer=booking.offerer) # When response = client.patch( f"/v2/bookings/cancel/token/{booking.token}", headers={"Authorization": "Bearer " + DEFAULT_CLEAR_API_KEY}, ) # Then # cancellation can trigger more than one request to Batch assert len(push_testing.requests) >= 1 assert response.status_code == 204 updated_booking = Booking.query.one() assert updated_booking.isCancelled assert updated_booking.status is BookingStatus.CANCELLED assert push_testing.requests[-1] == { "group_id": "Cancel_booking", "message": { "body": """Ta réservation "Chouette concert" a été annulée par l'offreur.""", "title": "Réservation annulée", }, "user_ids": [booking.individualBooking.userId], }
def test_should_sends_email_to_beneficiary_when_pro_cancels_booking(self): # Given booking = booking_factories.IndividualBookingFactory( individualBooking__user__email="*****@*****.**", user__firstName="Jeanne", ) # When send_warning_to_user_after_pro_booking_cancellation(booking) # Then assert mails_testing.outbox[0].sent_data == { "FromEmail": "*****@*****.**", "MJ-TemplateID": 1116690, "MJ-TemplateLanguage": True, "To": "*****@*****.**", "Vars": { "event_date": "", "event_hour": "", "is_event": 0, "is_free_offer": 0, "is_thing": 1, "is_online": 0, "offer_name": booking.stock.offer.name, "offer_price": "10.00", "offerer_name": booking.offerer.name, "user_first_name": "Jeanne", "user_last_name": "Doux", "venue_name": booking.venue.name, "env": "-development", }, }
def test_use_activation_code_instead_of_token_if_possible(self): booking = bookings_factories.IndividualBookingFactory( individualBooking__user__email="*****@*****.**", quantity=10, stock__price=0, stock__offer__product__subcategoryId=subcategories.VOD.id, stock__offer__product__url="http://example.com?token={token}&offerId={offerId}&email={email}", stock__offer__name="Super offre numérique", dateCreated=datetime.utcnow(), ) offers_factories.ActivationCodeFactory(stock=booking.stock, booking=booking, code="code_toto") mediation = offers_factories.MediationFactory(offer=booking.stock.offer) email_data = retrieve_data_for_beneficiary_booking_confirmation_email(booking.individualBooking) expected = get_expected_base_email_data( booking, mediation, all_but_not_virtual_thing=0, all_things_not_virtual_thing=0, event_date="", event_hour="", is_event=0, is_single_event=0, offer_name="Super offre numérique", offer_price="Gratuit", can_expire=0, offer_token="code_toto", is_digital_booking_with_activation_code_and_no_expiration_date=1, code_expiration_date="", has_offer_url=1, digital_offer_url=f"http://example.com?token=code_toto&offerId={humanize(booking.stock.offer.id)}&[email protected]", expiration_delay="", ) assert email_data == expected
def test_returns_payments_matching_message(self, app): # given beneficiary = users_factories.BeneficiaryGrant18Factory() booking = bookings_factories.IndividualBookingFactory(individualBooking__user=beneficiary) offerer = booking.offerer transaction1 = create_payment_message(name="XML1") transaction2 = create_payment_message(name="XML2") transaction3 = create_payment_message(name="XML3") uuid1, uuid2, uuid3 = uuid.uuid4(), uuid.uuid4(), uuid.uuid4() payments = [ create_payment(booking, offerer, 5, transaction_end_to_end_id=uuid1, payment_message=transaction1), create_payment(booking, offerer, 5, transaction_end_to_end_id=uuid2, payment_message=transaction2), create_payment(booking, offerer, 5, transaction_end_to_end_id=uuid1, payment_message=transaction3), create_payment(booking, offerer, 5, transaction_end_to_end_id=uuid3, payment_message=transaction1), create_payment(booking, offerer, 5, transaction_end_to_end_id=uuid1, payment_message=transaction1), ] repository.save(*payments) # when matching_payments = payment_queries.find_payments_by_message("XML1") # then assert len(matching_payments) == 3 for payment in matching_payments: assert payment.paymentMessageName == "XML1"
def test_booking_completed_url_gets_normalized(): booking = factories.IndividualBookingFactory( token="ABCDEF", individualBooking__user__email="*****@*****.**", stock__offer__url="example.com?token={token}&email={email}", ) assert booking.completedUrl == "http://example.com?token=ABCDEF&[email protected]"
def test_does_not_modify_statuses_on_given_payments_if_a_payment_id_is_not_found( self, app): # given booking = booking_factories.IndividualBookingFactory() offerer = booking.offerer transaction1 = create_payment_message(name="XML1") transaction2 = create_payment_message(name="XML2") uuid1, uuid2 = uuid.uuid4(), uuid.uuid4() payment1 = create_payment(booking, offerer, 5, transaction_end_to_end_id=uuid1, payment_message=transaction1) payment2 = create_payment(booking, offerer, 5, transaction_end_to_end_id=uuid2, payment_message=transaction2) repository.save(payment1, payment2) # when do_ban_payments("XML1", [payment1.id, 123456]) # then assert payment1.currentStatus.status == TransactionStatus.PENDING assert payment2.currentStatus.status == TransactionStatus.PENDING
def expect_the_booking_to_be_cancelled_by_current_user(self, app): # Given in_four_days = datetime.utcnow() + timedelta(days=4) stock = offers_factories.EventStockFactory( beginningDatetime=in_four_days) booking = bookings_factories.IndividualBookingFactory(stock=stock) # When client = TestClient(app.test_client()).with_session_auth(booking.email) response = client.put(f"/bookings/{humanize(booking.id)}/cancel") booking = Booking.query.get(booking.id) # Then assert response.status_code == 200 assert booking.isCancelled assert booking.status is BookingStatus.CANCELLED assert response.json == { "amount": 10.0, "completedUrl": None, "id": humanize(booking.id), "isCancelled": True, "quantity": booking.quantity, "stock": { "price": 10.0 }, "stockId": humanize(stock.id), "token": booking.token, "activationCode": None, "qrCode": None, }
def test_toggle_visibility(self, app): user = users_factories.BeneficiaryGrant18Factory(email=self.identifier) access_token = create_access_token(identity=self.identifier) booking = booking_factories.IndividualBookingFactory( individualBooking__user=user, displayAsEnded=None) booking_id = booking.id test_client = TestClient(app.test_client()) test_client.auth_header = {"Authorization": f"Bearer {access_token}"} response = test_client.post( f"/native/v1/bookings/{booking_id}/toggle_display", json={"ended": True}) assert response.status_code == 204 db.session.refresh(booking) assert booking.displayAsEnded response = test_client.post( f"/native/v1/bookings/{booking_id}/toggle_display", json={"ended": False}) assert response.status_code == 204 db.session.refresh(booking) assert not booking.displayAsEnded
def test_only_suspend_beneficiary_users_in_given_emails_providers_list( self): # Given fraudulent_emails_providers = ["example.com"] admin_user = AdminFactory() beneficiary_fraudulent_user = BeneficiaryGrant18Factory( email="*****@*****.**") beneficiary_fraudulent_user_with_uppercase_domain = BeneficiaryGrant18Factory( email="*****@*****.**") beneficiary_fraudulent_user_with_subdomain = BeneficiaryGrant18Factory( email="*****@*****.**") non_beneficiary_fraudulent_user = UserFactory( email="*****@*****.**") booking_factories.IndividualBookingFactory( individualBooking__user=beneficiary_fraudulent_user, stock__price=1) # When suspend_fraudulent_beneficiary_users_by_email_providers( fraudulent_emails_providers, admin_user, dry_run=False) # Then assert not beneficiary_fraudulent_user.isActive assert not beneficiary_fraudulent_user_with_uppercase_domain.isActive # Do not handle sub-domains assert beneficiary_fraudulent_user_with_subdomain.isActive assert non_beneficiary_fraudulent_user.isActive
def test_should_raises_resource_gone_error_if_not_used(self, app): booking = factories.IndividualBookingFactory(isUsed=False) with pytest.raises(api_errors.ResourceGoneError) as exc: validation.check_can_be_mark_as_unused(booking) assert exc.value.errors["booking"] == [ "Cette réservation n'a pas encore été validée" ]
def test_basics(self): offerer = offers_factories.OffererFactory(name="offerer", siren="123456") booking = bookings_factories.IndividualBookingFactory( stock__offer__venue__managingOfferer=offerer) reimbursement = BookingReimbursement(booking, PhysicalOffersReimbursement(), Decimal(10)) batch_date = datetime.utcnow() payment = create_payment_for_booking(reimbursement, batch_date) assert payment.bookingId == booking.id assert payment.amount == 10 assert payment.reimbursementRule == PhysicalOffersReimbursement( ).description assert payment.reimbursementRate == PhysicalOffersReimbursement().rate assert payment.comment is None assert payment.author == "batch" assert payment.transactionLabel == "pass Culture Pro - remboursement 1ère quinzaine 01-2021" assert payment.batchDate == batch_date assert payment.iban is None assert payment.bic is None assert payment.recipientName == "offerer" assert payment.recipientSiren == "123456"
def test_mark_as_used_when_stock_starts_soon(self): booking = booking_factories.IndividualBookingFactory( stock__beginningDatetime=datetime.now() + timedelta(days=1) ) api.mark_as_used(booking) assert booking.isUsed assert booking.status is BookingStatus.USED
def test_should_return_digital_thing_specific_data_for_email_when_offer_is_a_digital_thing(self): booking = bookings_factories.IndividualBookingFactory( quantity=10, stock__price=0, stock__offer__product__subcategoryId=subcategories.VOD.id, stock__offer__product__url="http://example.com", stock__offer__name="Super offre numérique", dateCreated=datetime.utcnow(), ) mediation = offers_factories.MediationFactory(offer=booking.stock.offer) email_data = retrieve_data_for_beneficiary_booking_confirmation_email(booking.individualBooking) expected = get_expected_base_email_data( booking, mediation, all_but_not_virtual_thing=0, all_things_not_virtual_thing=0, event_date="", event_hour="", is_event=0, is_single_event=0, offer_name="Super offre numérique", offer_price="Gratuit", can_expire=0, has_offer_url=1, digital_offer_url="http://example.com", expiration_delay="", ) assert email_data == expected
def should_pass_when_event_begins_in_more_than_72_hours_and_booking_created_more_than_48_hours_ago( self): next_week = datetime.utcnow() + timedelta(weeks=1) three_days_ago = datetime.utcnow() - timedelta(days=3) booking = factories.IndividualBookingFactory( stock__beginningDatetime=next_week, dateCreated=three_days_ago) validation.check_is_usable(booking)
def test_reject_approved_offer_with_bookings( self, mocked_send_cancel_booking_notification, mocked_send_offer_validation_notification_to_administration, mocked_send_offer_validation_status_update_email, mocked_validate_csrf_token, app, ): users_factories.AdminFactory(email="*****@*****.**") with freeze_time("2020-11-17 15:00:00") as frozen_time: offer = offers_factories.OfferFactory(validation=OfferValidationStatus.APPROVED, isActive=True) stock = offers_factories.StockFactory(offer=offer, price=10) unused_booking = booking_factories.IndividualBookingFactory(stock=stock) used_booking = booking_factories.UsedBookingFactory(stock=stock) frozen_time.move_to("2020-12-20 15:00:00") data = dict(validation=OfferValidationStatus.REJECTED.value) client = TestClient(app.test_client()).with_session_auth("*****@*****.**") response = client.post(f"/pc/back-office/offer/edit/?id={offer.id}", form=data) assert response.status_code == 302 assert offer.validation == OfferValidationStatus.REJECTED assert offer.lastValidationDate == datetime.datetime(2020, 12, 20, 15) assert unused_booking.isCancelled assert unused_booking.status is BookingStatus.CANCELLED assert not used_booking.isCancelled assert used_booking.status is not BookingStatus.CANCELLED mocked_send_cancel_booking_notification.assert_called_once_with([unused_booking.id])