예제 #1
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_relevancy_depending_on_revenue(self):
        booking = create_event_booking()

        assert not self.rule.is_relevant(booking, 150000)
        assert self.rule.is_relevant(booking, 150001)
        assert not self.rule.is_relevant(
            bookings_factories.EducationalBookingFactory(), 15001)
        def test_when_user_is_logged_in_and_offer_is_educational_but_has_been_refused_by_institution(
                self, client):
            # Given
            booking = bookings_factories.EducationalBookingFactory(
                token="ABCDEF",
                dateCreated=datetime.datetime.utcnow() -
                datetime.timedelta(days=3),
                educationalBooking__status=EducationalBookingStatus.REFUSED,
            )
            pro_user = users_factories.ProFactory(email="*****@*****.**")
            offers_factories.UserOffererFactory(user=pro_user,
                                                offerer=booking.offerer)

            # When
            url = f"/v2/bookings/use/token/{booking.token}"
            response = client.with_session_auth("*****@*****.**").patch(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"
            )
            booking = Booking.query.get(booking.id)
            assert booking.isUsed is False
            assert booking.status is not BookingStatus.USED
예제 #4
0
    def test_should_return_redactor_first_name_when_booking_is_educational(
            self):
        # Given
        stock = offers_factories.EventStockFactory(beginningDatetime=datetime(
            2019, 7, 20, 12, 0, 0, tzinfo=timezone.utc))
        booking = bookings_factories.EducationalBookingFactory(
            stock=stock,
            educationalBooking__educationalRedactor__firstName="Georgio",
            educationalBooking__educationalRedactor__lastName="Di georgio",
        )

        # When
        mailjet_data = retrieve_data_to_warn_user_after_pro_booking_cancellation(
            booking)

        # Then
        assert mailjet_data == {
            "MJ-TemplateID": 3192295,
            "MJ-TemplateLanguage": True,
            "Vars": {
                "event_date": "samedi 20 juillet 2019",
                "event_hour": "14h",
                "is_event": 1,
                "is_free_offer": 0,
                "is_online": 0,
                "is_thing": 0,
                "offer_name": booking.stock.offer.name,
                "offer_price": "10.00",
                "offerer_name": booking.offerer.name,
                "user_first_name": "Georgio",
                "user_last_name": "Di georgio",
                "venue_name": booking.venue.name,
            },
        }
예제 #5
0
    def test_confirm_when_confirmation_limit_date_has_not_passed(self) -> None:
        booking: Booking = factories.EducationalBookingFactory(
            educationalBooking__confirmationLimitDate=datetime(2021, 8, 5, 16))

        booking.mark_as_confirmed()
        db.session.flush()

        assert booking.status == BookingStatus.CONFIRMED
 def test_relevancy_depending_on_offer_type(self):
     revenue = 150001
     assert self.rule.is_relevant(create_non_digital_thing_booking(),
                                  revenue)
     assert self.rule.is_relevant(create_event_booking(), revenue)
     assert not self.rule.is_relevant(create_digital_booking(), revenue)
     assert not self.rule.is_relevant(
         bookings_factories.EducationalBookingFactory(), revenue)
예제 #7
0
    def test_raises_booking_is_cancelled(self, db_session) -> None:
        # Given
        booking = bookings_factories.EducationalBookingFactory(
            status=BookingStatus.CANCELLED)

        # Then
        with pytest.raises(exceptions.BookingIsCancelled):
            educational_api.confirm_educational_booking(
                booking.educationalBookingId)
 def test_relevancy_depending_on_revenue(self):
     assert not self.rule.is_relevant(self.book_booking, 20000)
     assert self.rule.is_relevant(self.book_booking, 20001)
     assert not self.rule.is_relevant(
         bookings_factories.EducationalBookingFactory(
             stock__offer__product__subcategoryId=subcategories.
             LIVRE_PAPIER.id),
         20001,
     )
예제 #9
0
    def test_confirm_educational_booking_lock(self, app):
        educational_institution = educational_factories.EducationalInstitutionFactory(
        )
        educational_year = educational_factories.EducationalYearFactory(
            adageId="1")
        deposit = educational_factories.EducationalDepositFactory(
            educationalInstitution=educational_institution,
            educationalYear=educational_year,
            amount=Decimal(1400.00),
            isFinal=True,
        )
        bookings_factories.EducationalBookingFactory(
            amount=Decimal(20.00),
            quantity=20,
            educationalBooking__educationalInstitution=educational_institution,
            educationalBooking__educationalYear=educational_year,
            status=BookingStatus.CONFIRMED,
        )

        booking = bookings_factories.EducationalBookingFactory(
            amount=Decimal(20.00),
            quantity=20,
            educationalBooking__educationalInstitution=educational_institution,
            educationalBooking__educationalYear=educational_year,
            status=BookingStatus.PENDING,
        )

        # open a second connection on purpose and lock the deposit
        engine = create_engine(app.config["SQLALCHEMY_DATABASE_URI"])
        with engine.connect() as connection:
            connection.execute(
                text(
                    """SELECT * FROM educational_deposit WHERE id = :educational_deposit_id FOR UPDATE"""
                ),
                educational_deposit_id=deposit.id,
            )

            with pytest.raises(sqlalchemy.exc.OperationalError):
                educational_api.confirm_educational_booking(
                    booking.educationalBookingId)

        refreshed_booking = Booking.query.filter(
            Booking.id == booking.id).one()
        assert refreshed_booking.status == BookingStatus.PENDING
예제 #10
0
    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,
            },
        }
예제 #11
0
    def test_confirm_when_has_confirmation_limit_date_passed(self) -> None:
        booking: Booking = factories.EducationalBookingFactory(
            educationalBooking__confirmationLimitDate=datetime(2021, 8, 5, 14),
            status=models.BookingStatus.PENDING,
        )

        with pytest.raises(exceptions.ConfirmationLimitDateHasPassed):
            booking.mark_as_confirmed()

        assert booking.status == BookingStatus.PENDING
예제 #12
0
    def test_raises_educational_booking_is_refused(self, db_session) -> None:
        # Given
        booking = bookings_factories.EducationalBookingFactory(
            educationalBooking__status=EducationalBookingStatus.REFUSED,
            status=BookingStatus.CANCELLED,
        )

        # Then
        with pytest.raises(exceptions.EducationalBookingIsRefused):
            educational_api.confirm_educational_booking(
                booking.educationalBookingId)
예제 #13
0
    def test_update_educational_booking_if_not_used_and_not_validated_by_principal_yet(self):
        event_date = datetime.now() - timedelta(days=3)
        booking_factories.EducationalBookingFactory(
            stock__beginningDatetime=event_date,
            educationalBooking__status=None,
        )

        api.auto_mark_as_used_after_event()

        non_validated_by_ce_educational_booking = Booking.query.first()
        assert non_validated_by_ce_educational_booking.isUsed
        assert non_validated_by_ce_educational_booking.status is BookingStatus.USED
예제 #14
0
def get_existing_pro_validated_user_with_validated_offerer_with_validated_user_offerer_with_eac_offer_with_stock_with_not_used_booking_validated_by_principal(
):
    user_offerer = offers_factories.UserOffererFactory()
    booking = bookings_factories.EducationalBookingFactory(
        dateCreated=datetime.datetime.utcnow() - datetime.timedelta(days=5),
        stock__offer__venue__managingOfferer=user_offerer.offerer,
        educationalBooking__status=EducationalBookingStatus.USED_BY_INSTITUTE,
    )

    return {
        "booking": get_booking_helper(booking),
        "user": get_pro_helper(user_offerer.user),
    }
 def test_relevancy_depending_on_offer_type(self):
     revenue = 20001
     assert self.rule.is_relevant(self.book_booking, revenue)
     assert not self.rule.is_relevant(create_non_digital_thing_booking(),
                                      revenue)
     assert not self.rule.is_relevant(create_event_booking(), revenue)
     assert not self.rule.is_relevant(create_digital_booking(), revenue)
     assert self.rule.is_relevant(
         create_digital_booking(
             product_subcategory_id=subcategories.LIVRE_NUMERIQUE.id),
         revenue)
     assert not self.rule.is_relevant(
         bookings_factories.EducationalBookingFactory(), revenue)
예제 #16
0
    def test_raises_confirmation_limit_date_has_passed(self,
                                                       db_session) -> None:
        # Given
        booking: Booking = bookings_factories.EducationalBookingFactory(
            educationalBooking__confirmationLimitDate=datetime.datetime(
                2021, 8, 5, 14),
            status=BookingStatus.PENDING,
        )

        # Then
        with pytest.raises(bookings_exceptions.ConfirmationLimitDateHasPassed):
            educational_api.confirm_educational_booking(
                booking.educationalBookingId)
    def test_should_not_cancel_confirmed_dated_educational_booking_when_confirmation_limit_date_has_passed(
            self, app) -> None:
        # Given
        now = datetime.utcnow()
        yesterday = now - timedelta(days=1)
        confirmed_educational_booking: Booking = booking_factories.EducationalBookingFactory(
            educationalBooking__confirmationLimitDate=yesterday)

        # When
        handle_expired_bookings.cancel_expired_educational_bookings()

        # Then
        assert confirmed_educational_booking.status == BookingStatus.CONFIRMED
예제 #18
0
    def test_no_op_when_educational_booking_already_refused(self, db_session):
        stock = offers_factories.EducationalEventStockFactory(
            dnBookedQuantity=20)
        booking = bookings_factories.EducationalBookingFactory(
            educationalBooking__status=EducationalBookingStatus.REFUSED,
            quantity=1,
            stock=stock,
        )

        educational_api.refuse_educational_booking(
            booking.educationalBookingId)

        assert stock.dnBookedQuantity == 21
    def test_relevancy(self):
        rule = reimbursement.PhysicalOffersReimbursement()

        assert rule.is_relevant(create_non_digital_thing_booking())
        assert rule.is_relevant(create_event_booking())
        assert not rule.is_relevant(create_digital_booking())
        digital_book_booking = create_digital_booking(
            product_subcategory_id=subcategories.LIVRE_NUMERIQUE.id)
        assert not rule.is_relevant(digital_book_booking)
        cinema_card_booking = create_digital_booking(
            product_subcategory_id=subcategories.CINE_VENTE_DISTANCE.id)
        assert rule.is_relevant(cinema_card_booking)
        assert not rule.is_relevant(
            bookings_factories.EducationalBookingFactory())
예제 #20
0
    def test_refuse_educational_booking(self, db_session):
        stock = offers_factories.EducationalEventStockFactory(
            quantity=200, dnBookedQuantity=0)
        booking = bookings_factories.EducationalBookingFactory(
            status=BookingStatus.CONFIRMED,
            stock=stock,
            quantity=20,
        )

        educational_api.refuse_educational_booking(
            booking.educationalBookingId)

        assert stock.dnBookedQuantity == 0
        assert booking.status == BookingStatus.CANCELLED
        assert booking.cancellationReason == BookingCancellationReasons.REFUSED_BY_INSTITUTE
    def test_relevancy(self):
        rule = reimbursement.DigitalThingsReimbursement()

        assert rule.is_relevant(create_digital_booking())
        digital_book_booking = create_digital_booking(
            product_subcategory_id=subcategories.LIVRE_PAPIER.id)
        assert not rule.is_relevant(digital_book_booking)
        cinema_card_booking = create_digital_booking(
            product_subcategory_id=subcategories.CINE_VENTE_DISTANCE.id)
        assert not rule.is_relevant(cinema_card_booking)
        assert not rule.is_relevant(create_non_digital_thing_booking())
        assert not rule.is_relevant(create_event_booking())
        assert not rule.is_relevant(
            bookings_factories.EducationalBookingFactory(
                stock__offer__product=offers_factories.DigitalProductFactory())
        )
예제 #22
0
    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_not_notify_of_todays_expired_educational_bookings(
            self, mocked_send_email_recap, app) -> None:
        # Given
        now = datetime.utcnow()
        long_ago = now - timedelta(days=31)
        dvd = ProductFactory(
            subcategoryId=subcategories.SUPPORT_PHYSIQUE_FILM.id)
        booking_factories.EducationalBookingFactory(
            stock__offer__product=dvd,
            dateCreated=long_ago,
            isCancelled=True,
            status=BookingStatus.CANCELLED,
            cancellationReason=BookingCancellationReasons.EXPIRED,
        )

        # When
        handle_expired_bookings.notify_users_of_expired_individual_bookings()

        # Then
        assert not mocked_send_email_recap.called
예제 #24
0
    def test_refuse_educational_booking_stock_lock(self, app):
        booking = bookings_factories.EducationalBookingFactory(
            status=BookingStatus.CONFIRMED, )
        educational_booking = booking.educationalBooking

        # open a second connection on purpose and lock the deposit
        engine = create_engine(app.config["SQLALCHEMY_DATABASE_URI"])
        with engine.connect() as connection:
            connection.execute(
                text(
                    """SELECT * FROM stock WHERE id = :stock_id FOR UPDATE"""),
                stock_id=booking.stock.id,
            )

            with pytest.raises(sqlalchemy.exc.OperationalError):
                educational_api.refuse_educational_booking(
                    educational_booking.id)

        refreshed_booking = Booking.query.filter(
            Booking.id == booking.id).one()
        assert refreshed_booking.status == BookingStatus.CONFIRMED
    def when_booking_is_educational(self, app):
        admin = users_factories.AdminFactory()
        user_offerer = offers_factories.UserOffererFactory()
        bookings_factories.EducationalBookingFactory(
            dateCreated=datetime(2020, 8, 11, 12, 0, 0),
            stock__offer__venue__managingOfferer=user_offerer.offerer,
            educationalBooking__educationalRedactor__firstName="Georges",
            educationalBooking__educationalRedactor__lastName="Moustaki",
            educationalBooking__educationalRedactor__email="*****@*****.**",
        )

        client = TestClient(app.test_client()).with_session_auth(admin.email)
        response = client.get(f"/bookings/pro?{BOOKING_PERIOD_PARAMS}")

        assert response.status_code == 200
        assert response.json["bookings_recap"][0]["stock"]["offer_is_educational"] is True
        assert response.json["bookings_recap"][0]["beneficiary"] == {
            "email": "*****@*****.**",
            "firstname": "Georges",
            "lastname": "Moustaki",
            "phonenumber": None,
        }
예제 #26
0
    def test_confirm_educational_booking(self, db_session):
        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,
            status=BookingStatus.PENDING,
        )
        educational_api.confirm_educational_booking(
            booking.educationalBookingId)

        assert booking.status == BookingStatus.CONFIRMED
        def test_when_user_is_logged_in_and_offer_is_educational_validated_by_institution(
                self, client):
            # Given
            booking = bookings_factories.EducationalBookingFactory(
                token="ABCDEF",
                dateCreated=datetime.datetime.utcnow() -
                datetime.timedelta(days=3),
                educationalBooking__status=EducationalBookingStatus.
                USED_BY_INSTITUTE,
            )
            pro_user = users_factories.ProFactory(email="*****@*****.**")
            offers_factories.UserOffererFactory(user=pro_user,
                                                offerer=booking.offerer)

            # When
            url = f"/v2/bookings/use/token/{booking.token}"
            response = client.with_session_auth("*****@*****.**").patch(url)

            # Then
            assert response.status_code == 204
            booking = Booking.query.one()
            assert booking.isUsed
            assert booking.status == BookingStatus.USED
예제 #28
0
    def test_raises_insufficient_temporary_fund(self, db_session) -> None:
        # When
        educational_year = educational_factories.EducationalYearFactory(
            adageId="1")
        educational_institution = educational_factories.EducationalInstitutionFactory(
        )
        educational_factories.EducationalDepositFactory(
            educationalYear=educational_year,
            educationalInstitution=educational_institution,
            amount=Decimal(1000.00),
            isFinal=False,
        )
        booking = bookings_factories.EducationalBookingFactory(
            educationalBooking__educationalYear=educational_year,
            educationalBooking__educationalInstitution=educational_institution,
            amount=Decimal(900.00),
            quantity=1,
            status=BookingStatus.PENDING,
        )

        # Then
        with pytest.raises(exceptions.InsufficientTemporaryFund):
            educational_api.confirm_educational_booking(
                booking.educationalBookingId)
예제 #29
0
 def test_raises_if_no_educational_deposit(self, db_session):
     booking = bookings_factories.EducationalBookingFactory(
         status=BookingStatus.PENDING)
     with pytest.raises(exceptions.EducationalDepositNotFound):
         educational_api.confirm_educational_booking(
             booking.educationalBookingId)
    def test_relevancy(self):
        rule = reimbursement.EducationalOffersReimbursement()

        assert rule.is_relevant(bookings_factories.EducationalBookingFactory())
        assert not rule.is_relevant(bookings_factories.BookingFactory())