def test_should_not_create_educational_booking_when_stock_does_not_exist( self): # Given offers_factories.EducationalEventStockFactory( beginningDatetime=datetime.datetime(2021, 5, 15)) educational_institution = educational_factories.EducationalInstitutionFactory( ) educational_factories.EducationalYearFactory() educational_redactor = educational_factories.EducationalRedactorFactory( email="*****@*****.**") requested_stock_id = 4875 redactor_informations = AuthenticatedInformation( email=educational_redactor.email, civility=educational_redactor.civility, firstname=educational_redactor.firstName, lastname=educational_redactor.lastName, uai=educational_institution.institutionId, ) # When with pytest.raises(offers_exceptions.StockDoesNotExist): educational_api.book_educational_offer( redactor_informations=redactor_informations, stock_id=requested_stock_id, ) # Then saved_bookings = EducationalBooking.query.all() assert len(saved_bookings) == 0
def test_should_not_create_educational_booking_when_offer_is_not_an_event( self): # Given educational_institution = educational_factories.EducationalInstitutionFactory( ) educational_factories.EducationalYearFactory() educational_redactor = educational_factories.EducationalRedactorFactory( email="*****@*****.**") stock = offers_factories.ThingStockFactory( beginningDatetime=datetime.datetime(2021, 5, 15), offer__isEducational=True) redactor_informations = AuthenticatedInformation( email=educational_redactor.email, civility=educational_redactor.civility, firstname=educational_redactor.firstName, lastname=educational_redactor.lastName, uai=educational_institution.institutionId, ) # When with pytest.raises(exceptions.OfferIsNotEvent) as error: educational_api.book_educational_offer( redactor_informations=redactor_informations, stock_id=stock.id, ) # Then assert error.value.errors == { "offer": [f"L'offre {stock.offer.id} n'est pas une offre évènementielle"] } saved_bookings = EducationalBooking.query.join(Booking).filter( Booking.stockId == stock.id).all() assert len(saved_bookings) == 0
def test_should_not_create_educational_booking_when_stock_is_not_bookable( self, mocked_get_and_lock_stock): # Given stock = mock.MagicMock() stock.isBookable = False stock.id = 1 mocked_get_and_lock_stock.return_value = stock educational_redactor = educational_factories.EducationalRedactorFactory( email="*****@*****.**") educational_institution = educational_factories.EducationalInstitutionFactory( ) redactor_informations = AuthenticatedInformation( email=educational_redactor.email, civility=educational_redactor.civility, firstname=educational_redactor.firstName, lastname=educational_redactor.lastName, uai=educational_institution.institutionId, ) # When with pytest.raises(exceptions.StockNotBookable) as error: educational_api.book_educational_offer( redactor_informations=redactor_informations, stock_id=stock.id, ) # Then assert error.value.errors == { "stock": [f"Le stock {stock.id} n'est pas réservable"] } saved_bookings = EducationalBooking.query.join(Booking).filter( Booking.stockId == stock.id).all() assert len(saved_bookings) == 0
def test_when_booking_is_educational_and_refused_by_principal(self, client): # Given redactor = educational_factories.EducationalRedactorFactory( civility="M.", firstName="Jean", lastName="Doudou", email="*****@*****.**", ) refused_eac_booking = bookings_factories.EducationalBookingFactory( dateCreated=datetime.utcnow() - timedelta(days=5), educationalBooking__educationalRedactor=redactor, educationalBooking__status=EducationalBookingStatus.REFUSED, ) pro_user = users_factories.ProFactory() offers_factories.UserOffererFactory(user=pro_user, offerer=refused_eac_booking.offerer) url = f"/v2/bookings/token/{refused_eac_booking.token}" # When response = client.with_basic_auth(pro_user.email).get(url) # Then assert response.status_code == 403 assert ( response.json["educationalBooking"] == "Cette réservation pour une offre éducationnelle a été refusée par le chef d'établissement" )
def test_should_not_create_educational_booking_when_educational_institution_unknown( self): # Given stock = offers_factories.EducationalEventStockFactory( beginningDatetime=datetime.datetime(2021, 5, 15)) educational_factories.EducationalInstitutionFactory() educational_factories.EducationalYearFactory() educational_redactor = educational_factories.EducationalRedactorFactory( email="*****@*****.**") provided_institution_id = "AU3568Unknown" redactor_informations = AuthenticatedInformation( email=educational_redactor.email, civility=educational_redactor.civility, firstname=educational_redactor.firstName, lastname=educational_redactor.lastName, uai=provided_institution_id, ) # When with pytest.raises(exceptions.EducationalInstitutionUnknown) as error: educational_api.book_educational_offer( redactor_informations=redactor_informations, stock_id=stock.id, ) # Then assert error.value.errors == { "educationalInstitution": ["Cette institution est inconnue"] } saved_bookings = EducationalBooking.query.join(Booking).filter( Booking.stockId == stock.id).all() assert len(saved_bookings) == 0
def test_should_send_email_on_educational_booking_creation(self): # Given stock = offers_factories.EducationalEventStockFactory( beginningDatetime=datetime.datetime(2021, 5, 15), offer__bookingEmail="*****@*****.**", ) educational_institution = educational_factories.EducationalInstitutionFactory( ) educational_factories.EducationalYearFactory( beginningDate=datetime.datetime(2020, 9, 1), expirationDate=datetime.datetime(2021, 8, 31)) educational_factories.EducationalYearFactory( beginningDate=datetime.datetime(2021, 9, 1), expirationDate=datetime.datetime(2022, 8, 31)) educational_redactor = educational_factories.EducationalRedactorFactory( email="*****@*****.**", firstName="Georges", lastName="Moustaki", ) redactor_informations = AuthenticatedInformation( email=educational_redactor.email, civility=educational_redactor.civility, firstname=educational_redactor.firstName, lastname=educational_redactor.lastName, uai=educational_institution.institutionId, ) # When educational_api.book_educational_offer( redactor_informations=redactor_informations, stock_id=stock.id, ) # Then assert len(mails_testing.outbox) == 1 sent_data = mails_testing.outbox[0].sent_data offer = stock.offer assert sent_data == { "FromEmail": "*****@*****.**", "MJ-TemplateID": 3174424, "MJ-TemplateLanguage": True, "To": "*****@*****.**", "Vars": { "departement": "75", "lien_offre_pcpro": f"http://*****:*****@example.com", "is_event": 1, }, }
def test_confirm_educational_booking_sends_email(self, db_session): # Given educational_redactor = educational_factories.EducationalRedactorFactory( email="*****@*****.**", firstName="Georges", lastName="Moustaki") educational_institution = educational_factories.EducationalInstitutionFactory( ) educational_year = educational_factories.EducationalYearFactory( adageId="1") educational_factories.EducationalDepositFactory( educationalInstitution=educational_institution, educationalYear=educational_year, amount=Decimal(1400.00), isFinal=True, ) booking = bookings_factories.EducationalBookingFactory( amount=Decimal(20.00), quantity=20, educationalBooking__educationalInstitution=educational_institution, educationalBooking__educationalYear=educational_year, educationalBooking__educationalRedactor=educational_redactor, status=BookingStatus.PENDING, stock__offer__bookingEmail="*****@*****.**", stock__beginningDatetime=datetime.datetime(2021, 5, 15), ) # When educational_api.confirm_educational_booking( booking.educationalBookingId) # Then assert len(mails_testing.outbox) == 1 sent_data = mails_testing.outbox[0].sent_data offer = booking.stock.offer assert sent_data == { "FromEmail": "*****@*****.**", "MJ-TemplateID": 3174413, "MJ-TemplateLanguage": True, "To": "*****@*****.**", "Vars": { "lien_offre_pcpro": f"http://*****:*****@example.com", "is_event": 1, }, }
def test_data(self): stock = offer_factories.EducationalEventStockFactory( beginningDatetime=stock_date) educational_institution = educational_factories.EducationalInstitutionFactory( ) educational_factories.EducationalYearFactory( beginningDate=educational_year_dates["start"], expirationDate=educational_year_dates["end"]) educational_redactor = educational_factories.EducationalRedactorFactory( email="*****@*****.**") return (stock, educational_institution, educational_redactor)
def test_when_user_has_rights_and_booking_is_educational_validated_by_principal(self, client): # Given redactor = educational_factories.EducationalRedactorFactory( civility="M.", firstName="Jean", lastName="Doudou", email="*****@*****.**", ) validated_eac_booking = bookings_factories.EducationalBookingFactory( dateCreated=datetime.utcnow() - timedelta(days=5), educationalBooking__educationalRedactor=redactor, educationalBooking__status=EducationalBookingStatus.USED_BY_INSTITUTE, ) pro_user = users_factories.ProFactory() offers_factories.UserOffererFactory(user=pro_user, offerer=validated_eac_booking.offerer) # When client = client.with_basic_auth(pro_user.email) response = client.get(f"/v2/bookings/token/{validated_eac_booking.token}") # Then assert response.headers["Content-type"] == "application/json" assert response.status_code == 200 assert response.json == { "bookingId": humanize(validated_eac_booking.id), "dateOfBirth": "", "datetime": format_into_utc_date(validated_eac_booking.stock.beginningDatetime), "ean13": None, "email": redactor.email, "formula": "PLACE", "isUsed": False, "offerId": validated_eac_booking.stock.offer.id, "offerName": validated_eac_booking.stock.offer.name, "offerType": "EVENEMENT", "phoneNumber": "", "price": float(validated_eac_booking.stock.price), "publicOfferId": humanize(validated_eac_booking.stock.offer.id), "quantity": validated_eac_booking.quantity, "theater": {}, "userName": f"{redactor.firstName} {redactor.lastName}", "venueAddress": validated_eac_booking.venue.address, "venueDepartmentCode": validated_eac_booking.venue.departementCode, "venueName": validated_eac_booking.venue.name, }
def test_should_create_educational_booking_on_requested_educational_offer( self): # Given stock = offers_factories.EducationalEventStockFactory( beginningDatetime=datetime.datetime(2021, 5, 15)) educational_institution = educational_factories.EducationalInstitutionFactory( ) educational_year = educational_factories.EducationalYearFactory( beginningDate=datetime.datetime(2020, 9, 1), expirationDate=datetime.datetime(2021, 8, 31)) educational_factories.EducationalYearFactory( beginningDate=datetime.datetime(2021, 9, 1), expirationDate=datetime.datetime(2022, 8, 31)) educational_redactor = educational_factories.EducationalRedactorFactory( email="*****@*****.**") redactor_informations = AuthenticatedInformation( email=educational_redactor.email, civility=educational_redactor.civility, firstname=educational_redactor.firstName, lastname=educational_redactor.lastName, uai=educational_institution.institutionId, ) # When returned_booking = educational_api.book_educational_offer( redactor_informations=redactor_informations, stock_id=stock.id, ) # Then saved_educational_booking = EducationalBooking.query.join( Booking).filter(Booking.stockId == stock.id).first() assert saved_educational_booking.booking.id == returned_booking.id assert saved_educational_booking.booking.stock.id == stock.id assert saved_educational_booking.booking.stock.dnBookedQuantity == 1 assert saved_educational_booking.confirmationLimitDate == stock.bookingLimitDatetime assert saved_educational_booking.educationalInstitution.institutionId == educational_institution.institutionId assert saved_educational_booking.educationalYear.adageId == educational_year.adageId assert saved_educational_booking.booking.status == BookingStatus.PENDING # Assert we do not create an extra educational redactor when exist assert EducationalRedactor.query.count() == 1
def test_post_educational_booking(self, app): # Given stock = offer_factories.EducationalEventStockFactory( beginningDatetime=stock_date) educational_institution = educational_factories.EducationalInstitutionFactory( ) educational_year = educational_factories.EducationalYearFactory( beginningDate=educational_year_dates["start"], expirationDate=educational_year_dates["end"]) educational_redactor = educational_factories.EducationalRedactorFactory( email="*****@*****.**") adage_jwt_fake_valid_token = _create_adage_valid_token_with_email( email=educational_redactor.email, uai=educational_institution.institutionId) test_client = TestClient(app.test_client()) test_client.auth_header = { "Authorization": f"Bearer {adage_jwt_fake_valid_token}" } # When response = test_client.post( "/adage-iframe/bookings", json={ "stockId": stock.id, }, ) # Then assert response.status_code == 200 booking = Booking.query.filter(Booking.stockId == stock.id).first() assert booking.educationalBookingId is not None assert booking.individualBookingId is None assert booking.stock.id == stock.id assert booking.educationalBooking.educationalInstitution.institutionId == educational_institution.institutionId assert booking.educationalBooking.educationalYear.adageId == educational_year.adageId assert response.json["bookingId"] == booking.id
def test_should_not_create_educational_booking_when_educational_year_not_found( self): # Given date_before_education_year_beginning = datetime.datetime(2018, 9, 20) stock = offers_factories.EducationalEventStockFactory( beginningDatetime=date_before_education_year_beginning) educational_institution = educational_factories.EducationalInstitutionFactory( ) educational_factories.EducationalYearFactory() educational_redactor = educational_factories.EducationalRedactorFactory( email="*****@*****.**") redactor_informations = AuthenticatedInformation( email=educational_redactor.email, civility=educational_redactor.civility, firstname=educational_redactor.firstName, lastname=educational_redactor.lastName, uai=educational_institution.institutionId, ) # When with pytest.raises(exceptions.EducationalYearNotFound) as error: educational_api.book_educational_offer( redactor_informations=redactor_informations, stock_id=stock.id, ) # Then assert error.value.errors == { "educationalYear": [ "Aucune année scolaire correspondant à la réservation demandée n'a été trouvée" ] } saved_bookings = EducationalBooking.query.join(Booking).filter( Booking.stockId == stock.id).all() assert len(saved_bookings) == 0
def create_industrial_educational_bookings() -> None: educational_current_year = educational_factories.EducationalYearFactory() educational_next_year = educational_factories.EducationalYearFactory() educational_institutions = [ educational_factories.EducationalInstitutionFactory( institutionId="0780032L"), educational_factories.EducationalInstitutionFactory( institutionId="0781839A"), educational_factories.EducationalInstitutionFactory( institutionId="0290047U"), educational_factories.EducationalInstitutionFactory( institutionId="0290198H"), educational_factories.EducationalInstitutionFactory( institutionId="0910620E"), educational_factories.EducationalInstitutionFactory( institutionId="0560071Y"), ] now = datetime.datetime.now(datetime.timezone.utc) stocks = [] venue = VenueFactory(name="Opéra Royal de Versailles", isPermanent=True) UserOffererFactory(validationToken=None, offerer=venue.managingOfferer) educational_redactor = educational_factories.EducationalRedactorFactory( email="*****@*****.**") user_offerer_reimbursements = UserOffererFactory( validationToken=None, user__email="*****@*****.**") venue_reimbursements = VenueFactory( name="Théâtre des potirons", isPermanent=True, managingOfferer=user_offerer_reimbursements.offerer) for stock_data in FAKE_STOCK_DATA: stocks.append( EducationalEventStockFactory( quantity=100, price=stock_data["price"], beginningDatetime=now + datetime.timedelta(days=stock_data["timedelta"]), offer__durationMinutes=60, offer__withdrawalDetails= "Récupération du ticket à l'adresse du lieu", offer__description= "Une description multi-lignes.\nOù il est notamment question du nombre d'élèves.\nNbr d'élèves max: 50", offer__name=stock_data["name"], offer__venue=venue, )) for stock in stocks: mediation = MediationFactory(offer=stock.offer, credit="Crédit photo") store_public_object_from_sandbox_assets("thumbs", mediation, mediation.offer.subcategoryId) next_year_stocks = [ EducationalEventStockFactory( quantity=100, price=1200, beginningDatetime=educational_next_year.beginningDate + datetime.timedelta(days=10), offer__durationMinutes=60, offer__withdrawalDetails= "Récupération du ticket à l'adresse du lieu", offer__description= "Une description multi-lignes.\nOù il est notamment question du nombre d'élèves.\nNbr d'élèves max: 50", offer__name= "Stage d'initiation à la photographie : prise en main de l'appareil-photo", offer__venue=venue, ), EducationalEventStockFactory( quantity=60, price=1400, beginningDatetime=educational_next_year.beginningDate + datetime.timedelta(days=15), offer__durationMinutes=60, offer__withdrawalDetails= "Récupération du ticket à l'adresse du lieu", offer__description= "Une description multi-lignes.\nOù il est notamment question du nombre d'élèves.\nNbr d'élèves max: 50", offer__name= "Explorer la nature au Parc Zoologique et Botanique de Mulhouse", offer__venue=venue, ), ] deposits = [] for educational_institution in educational_institutions: deposits.append( educational_factories.EducationalDepositFactory( educationalInstitution=educational_institution, educationalYear=educational_current_year, amount=20000, )) deposits.append( educational_factories.EducationalDepositFactory( educationalInstitution=educational_institution, educationalYear=educational_next_year, amount=25000, isFinal=False, )) for stock in stocks: for educational_institution in educational_institutions: EducationalBookingFactory( educationalBooking__educationalRedactor=educational_redactor, educationalBooking__educationalInstitution= educational_institution, educationalBooking__educationalYear=educational_current_year, educationalBooking__confirmationLimitDate=now + datetime.timedelta(days=10), cancellation_limit_date=now + datetime.timedelta(days=4), status=BookingStatus.PENDING, stock=stock, ) UsedEducationalBookingFactory( educationalBooking__educationalRedactor=educational_redactor, educationalBooking__educationalInstitution= educational_institution, educationalBooking__educationalYear=educational_current_year, educationalBooking__confirmationLimitDate=now - datetime.timedelta(days=20), cancellation_limit_date=now - datetime.timedelta(days=15), dateUsed=now - datetime.timedelta(8), status=BookingStatus.USED, stock=EducationalEventStockFactory( quantity=100, price=1200, beginningDatetime=now - datetime.timedelta(days=10), bookingLimitDatetime=now - datetime.timedelta(days=10), offer__venue=venue_reimbursements, ), ) for next_year_stock in next_year_stocks: for educational_institution in educational_institutions: EducationalBookingFactory( educationalBooking__educationalRedactor=educational_redactor, educationalBooking__educationalInstitution= educational_institution, educationalBooking__educationalYear=educational_next_year, educationalBooking__confirmationLimitDate=now + datetime.timedelta(days=30), status=BookingStatus.PENDING, stock=next_year_stock, )