Exemple #1
0
    def test_balance(self):
        # given
        user = users_factories.BeneficiaryGrant18Factory(deposit__version=1)
        bookings_factories.UsedIndividualBookingFactory(
            individualBooking__user=user, quantity=1, amount=10)
        bookings_factories.UsedIndividualBookingFactory(
            individualBooking__user=user, quantity=2, amount=20)
        bookings_factories.IndividualBookingFactory(
            individualBooking__user=user, quantity=3, amount=30)
        bookings_factories.CancelledIndividualBookingFactory(
            individualBooking__user=user, quantity=4, amount=40)

        # then
        assert user.wallet_balance == 500 - (10 + 2 * 20 + 3 * 30)
        assert user.real_wallet_balance == 500 - (10 + 2 * 20)
    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
Exemple #3
0
 def test_raise_if_already_used(self):
     booking = factories.UsedIndividualBookingFactory()
     with pytest.raises(api_errors.ForbiddenError) as exc:
         validation.check_booking_can_be_cancelled(booking)
     assert exc.value.errors["global"] == [
         "Impossible d'annuler une réservation consommée"
     ]
Exemple #4
0
 def should_raise_if_used(self):
     booking = factories.UsedIndividualBookingFactory()
     with pytest.raises(api_errors.ResourceGoneError) as exc:
         validation.check_is_usable(booking)
     assert exc.value.errors["booking"] == [
         "Cette réservation a déjà été validée"
     ]
    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_raise_if_has_payment(self):
     booking = booking_factories.UsedIndividualBookingFactory()
     payments_factories.PaymentFactory(booking=booking)
     with pytest.raises(api_errors.ResourceGoneError):
         api.mark_as_unused(booking)
     assert booking.isUsed  # unchanged
     assert booking.status is BookingStatus.USED
    def test_no_need_when_booking_is_autovalidated(self):
        # Given
        offer = offers_factories.OfferFactory(
            venue__name="Lieu de l'offreur",
            venue__managingOfferer__name="Théâtre du coin",
            product=offers_factories.DigitalProductFactory(
                name="Super événement", url="http://example.com"),
        )
        digital_stock = offers_factories.StockWithActivationCodesFactory()
        first_activation_code = digital_stock.activationCodes[0]
        booking = bookings_factories.UsedIndividualBookingFactory(
            individualBooking__user__email="*****@*****.**",
            individualBooking__user__firstName="John",
            individualBooking__user__lastName="Doe",
            stock__offer=offer,
            activationCode=first_activation_code,
            dateCreated=datetime(2018, 1, 1),
        )

        # When
        email_data = retrieve_data_for_offerer_booking_recap_email(
            booking.individualBooking)

        # Then
        expected = get_expected_base_email_data(
            booking,
            date="",
            heure="",
            is_event=0,
            is_booking_autovalidated=1,
            must_use_token_for_payment=0,
            offer_type="VOD",
            contremarque=booking.token,
        )
        assert email_data == expected
Exemple #8
0
 def should_raises_forbidden_error_if_payement_exists(self, app):
     booking = factories.UsedIndividualBookingFactory()
     payments_factories.PaymentFactory(booking=booking)
     with pytest.raises(api_errors.ForbiddenError) as exc:
         validation.check_is_usable(booking)
     assert exc.value.errors["payment"] == [
         "Cette réservation a été remboursée"
     ]
    def test_raise_if_already_used(self):
        booking = booking_factories.UsedIndividualBookingFactory()
        with pytest.raises(api_errors.ForbiddenError):
            api.cancel_booking_by_offerer(booking)
        assert booking.isUsed
        assert not booking.isCancelled
        assert booking.status is BookingStatus.USED
        assert not booking.cancellationReason

        assert push_testing.requests == []
    def test_does_not_update_booking_if_already_used(self):
        event_date = datetime.now() - timedelta(days=3)
        booking = booking_factories.UsedIndividualBookingFactory(stock__beginningDatetime=event_date)
        initial_date_used = booking.dateUsed

        api.auto_mark_as_used_after_event()

        booking = Booking.query.first()
        assert booking.isUsed
        assert booking.dateUsed == initial_date_used
 def test_raise_if_booking_was_automatically_used_for_digital_offer_with_activation_code(self):
     offer = offers_factories.OfferFactory(product=offers_factories.DigitalProductFactory())
     digital_stock = offers_factories.StockWithActivationCodesFactory()
     first_activation_code = digital_stock.activationCodes[0]
     booking = booking_factories.UsedIndividualBookingFactory(
         stock__offer=offer, activationCode=first_activation_code
     )
     with pytest.raises(api_errors.ForbiddenError):
         api.mark_as_unused(booking)
     assert booking.isUsed
     assert booking.status is BookingStatus.USED
Exemple #12
0
    def test_balance_should_not_be_negative(self):
        # given
        user = users_factories.BeneficiaryGrant18Factory(deposit__version=1)
        bookings_factories.UsedIndividualBookingFactory(
            individualBooking__user=user, quantity=1, amount=10)
        deposit = user.deposit
        deposit.expirationDate = datetime(2000, 1, 1)

        # then
        assert user.wallet_balance == 0
        assert user.real_wallet_balance == 0
        def test_when_user_is_logged_in_and_regular_offer(self, client):
            booking = bookings_factories.UsedIndividualBookingFactory()
            pro_user = offers_factories.UserOffererFactory(
                offerer=booking.offerer).user

            url = f"/v2/bookings/keep/token/{booking.token}"
            response = client.with_session_auth(pro_user.email).patch(url)

            assert response.status_code == 204
            booking = Booking.query.one()
            assert not booking.isUsed
            assert booking.status is not BookingStatus.USED
            assert booking.dateUsed is None
        def test_ignore_activation_that_is_already_used_for_booking(self):
            # Given
            beneficiary = users_factories.BeneficiaryGrant18Factory()
            booking = booking_factories.UsedIndividualBookingFactory(token="ABCDEF")
            stock = offers_factories.StockWithActivationCodesFactory(
                activationCodes=["code-vgya451afvyux", "code-bha45k15fuz"]
            )
            stock.activationCodes[0].booking = booking

            # When
            booking = api.book_offer(beneficiary=beneficiary, stock_id=stock.id, quantity=1)

            # Then
            assert booking.activationCode.code == "code-bha45k15fuz"
Exemple #15
0
    def test_integration_toggle_visibility(self, app):
        user = users_factories.BeneficiaryGrant18Factory(email=self.identifier)
        access_token = create_access_token(identity=self.identifier)

        stock = StockWithActivationCodesFactory()
        activation_code = stock.activationCodes[0]
        booking = booking_factories.UsedIndividualBookingFactory(
            individualBooking__user=user,
            displayAsEnded=None,
            dateUsed=datetime.now(),
            stock=stock,
            activationCode=activation_code,
        )

        test_client = TestClient(app.test_client())
        test_client.auth_header = {"Authorization": f"Bearer {access_token}"}

        response = test_client.get("/native/v1/bookings")
        assert response.status_code == 200

        assert [b["id"]
                for b in response.json["ongoing_bookings"]] == [booking.id]
        assert [b["id"] for b in response.json["ended_bookings"]] == []

        response = test_client.post(
            f"/native/v1/bookings/{booking.id}/toggle_display",
            json={"ended": True})

        assert response.status_code == 204

        response = test_client.get("/native/v1/bookings")
        assert response.status_code == 200

        assert [b["id"] for b in response.json["ongoing_bookings"]] == []
        assert [b["id"]
                for b in response.json["ended_bookings"]] == [booking.id]

        response = test_client.post(
            f"/native/v1/bookings/{booking.id}/toggle_display",
            json={"ended": False})

        assert response.status_code == 204

        response = test_client.get("/native/v1/bookings")
        assert response.status_code == 200

        assert [b["id"]
                for b in response.json["ongoing_bookings"]] == [booking.id]
        assert [b["id"] for b in response.json["ended_bookings"]] == []
    def test_suspend_users_by_ids_does_not_cancel_bookings_when_not_cancellable(
            self):
        fraudulent_user_ids = [15]
        admin_user = AdminFactory()
        fraudulent_user = BeneficiaryGrant18Factory(id=15)
        uncancellable_booking = booking_factories.UsedIndividualBookingFactory(
            individualBooking__user=fraudulent_user, stock__price=1)

        suspend_fraudulent_beneficiary_users_by_ids(fraudulent_user_ids,
                                                    admin_user,
                                                    dry_run=False)

        assert not fraudulent_user.isActive
        assert not uncancellable_booking.isCancelled
        assert uncancellable_booking.status is not BookingStatus.CANCELLED
        def test_when_there_is_no_remaining_quantity_after_validating(
                self, client):
            booking = bookings_factories.UsedIndividualBookingFactory(
                stock__quantity=1)
            pro_user = offers_factories.UserOffererFactory(
                offerer=booking.offerer).user

            url = f"/v2/bookings/keep/token/{booking.token.lower()}"
            response = client.with_session_auth(pro_user.email).patch(url)

            assert response.status_code == 204
            booking = Booking.query.one()
            assert not booking.isUsed
            assert booking.status is not BookingStatus.USED
            assert booking.dateUsed is None
    def test_should_not_return_payments_to_retry_if_no_bank_information(self, app):
        # Given
        product = offers_factories.ThingProductFactory(name="Lire un livre", isNational=True)
        venue = offers_factories.VenueFactory(postalCode="34000", departementCode="34")
        offer = offers_factories.ThingOfferFactory(product=product, venue=venue)
        stock = offers_factories.ThingStockFactory(offer=offer, price=0, quantity=2)
        booking = bookings_factories.UsedIndividualBookingFactory(stock=stock, quantity=2)
        payment = factories.PaymentFactory(booking=booking, amount=10)
        factories.PaymentStatusFactory(payment=payment, status=TransactionStatus.NOT_PROCESSABLE)

        # When
        payments_to_retry = payment_queries.find_not_processable_with_bank_information()

        # Then
        assert payments_to_retry == []
        def test_raise_when_no_activation_code_available(self):
            # Given
            beneficiary = users_factories.BeneficiaryGrant18Factory()
            booking = booking_factories.UsedIndividualBookingFactory(token="ABCDEF")
            stock = offers_factories.StockWithActivationCodesFactory(activationCodes=["code-vgya451afvyux"])
            stock.activationCodes[0].booking = booking

            # When
            with pytest.raises(exceptions.NoActivationCodeAvailable) as error:
                api.book_offer(beneficiary=beneficiary, stock_id=stock.id, quantity=1)

            # Then
            assert Booking.query.count() == 1
            assert error.value.errors == {
                "noActivationCodeAvailable": ["Ce stock ne contient plus de code d'activation disponible."]
            }
    def when_the_booking_cannot_be_cancelled(self, app):
        # Given
        booking = bookings_factories.UsedIndividualBookingFactory()

        # 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 == 400
        assert response.json["booking"] == [
            "Impossible d'annuler une réservation consommée"
        ]
        assert not booking.isCancelled
        assert booking.status is BookingStatus.USED
    def test_cancel_all_bookings_from_stock(self, app):
        stock = offers_factories.StockFactory(dnBookedQuantity=1)
        booking_factories.IndividualBookingFactory(stock=stock)
        booking_factories.IndividualBookingFactory(stock=stock)
        booking_factories.UsedIndividualBookingFactory(stock=stock)
        booking_factories.CancelledIndividualBookingFactory(stock=stock)

        # 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=stock.id)

            with pytest.raises(sqlalchemy.exc.OperationalError):
                api.cancel_bookings_when_offerer_deletes_stock(stock)

        assert models.Booking.query.filter().count() == 4
        assert models.Booking.query.filter(models.Booking.isCancelled == True).count() == 1
    def test_does_not_cancel_booking_when_not_cancellable(self):
        # Given
        fraudulent_emails_providers = ["example.com"]
        admin_user = AdminFactory()
        fraudulent_user = BeneficiaryGrant18Factory(
            email="*****@*****.**")
        uncancellable_booking = booking_factories.UsedIndividualBookingFactory(
            individualBooking__user=fraudulent_user, stock__price=1)

        # When
        suspend_fraudulent_beneficiary_users_by_email_providers(
            fraudulent_emails_providers, admin_user, dry_run=False)

        # Then
        assert not fraudulent_user.isActive
        assert not uncancellable_booking.isCancelled
        assert uncancellable_booking.status is not BookingStatus.CANCELLED
        def test_when_api_key_provided_is_related_to_regular_offer_with_rights(
                self, client):
            booking = bookings_factories.UsedIndividualBookingFactory()
            ApiKeyFactory(offerer=booking.offerer)

            url = f"/v2/bookings/keep/token/{booking.token}"
            response = client.patch(
                url,
                headers={
                    "Authorization": f"Bearer {DEFAULT_CLEAR_API_KEY}",
                },
            )

            assert response.status_code == 204
            booking = Booking.query.one()
            assert not booking.isUsed
            assert booking.status is not BookingStatus.USED
            assert booking.dateUsed is None
Exemple #24
0
    def test_hide_cancellation_policy_on_bookings_with_activation_code(self):
        offer = offers_factories.OfferFactory(
            venue__name="Lieu de l'offreur",
            venue__managingOfferer__name="Théâtre du coin",
            product=offers_factories.DigitalProductFactory(name="Super offre numérique", url="http://example.com"),
        )
        digital_stock = offers_factories.StockWithActivationCodesFactory()
        first_activation_code = digital_stock.activationCodes[0]
        booking = bookings_factories.UsedIndividualBookingFactory(
            stock__offer=offer,
            activationCode=first_activation_code,
            dateCreated=datetime(2018, 1, 1),
        )

        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="10.00 €",
            offer_token=booking.activationCode.code,
            can_expire=0,
            is_digital_booking_with_activation_code_and_no_expiration_date=1,
            has_offer_url=1,
            digital_offer_url="http://example.com",
            user_first_name="Jeanne",
            venue_address="1 boulevard Poissonnière",
            venue_city="Paris",
            venue_postal_code="75000",
            booking_date="1 janvier 2018",
            booking_hour="01h00",
            expiration_delay="",
        )

        assert email_data == expected
    def test_can_not_cancel_refunded_booking(self, app):
        users_factories.UserFactory(email="*****@*****.**", isAdmin=True)
        booking = bookings_factories.UsedIndividualBookingFactory()
        payments_factories.PaymentFactory(booking=booking)

        client = TestClient(
            app.test_client()).with_session_auth("*****@*****.**")
        route = f"/pc/back-office/bookings/cancel/{booking.id}"
        response = client.post(route, form={})

        assert response.status_code == 302
        assert response.location == f"http://localhost/pc/back-office/bookings/?id={booking.id}"

        response = client.get(response.location)
        content = response.data.decode(response.charset)
        assert "L'opération a échoué : la réservation a déjà été remboursée" in content

        booking = Booking.query.get(booking.id)
        assert not booking.isCancelled
Exemple #26
0
    def test_should_return_beneficiary_bookings_with_expected_information(self, app):
        # Given
        beneficiary = BeneficiaryGrant18Factory()
        offer = ThingOfferFactory(isActive=True, url="http://url.com", product__thumbCount=1)
        stock = ThingStockFactory(offer=offer, price=0, quantity=10)
        booking = booking_factories.UsedIndividualBookingFactory(
            individualBooking__user=beneficiary,
            stock=stock,
            token="ABCDEF",
            dateCreated=datetime(2020, 4, 22, 0, 0),
            dateUsed=datetime(2020, 5, 5, 0, 0),
            quantity=2,
        )

        # When
        result = BeneficiaryBookingsSQLRepository().get_beneficiary_bookings(beneficiary_id=beneficiary.id)

        # Then
        assert isinstance(result, BeneficiaryBookingsWithStocks)
        assert len(result.bookings) == 1
        expected_booking = result.bookings[0]
        assert expected_booking.amount == 0.0
        assert expected_booking.cancellationDate is None
        assert expected_booking.dateCreated == datetime(2020, 4, 22, 0, 0)
        assert expected_booking.dateUsed == datetime(2020, 5, 5, 0, 0)
        assert expected_booking.id == booking.id
        assert expected_booking.isCancelled is False
        assert expected_booking.isUsed is True
        assert expected_booking.quantity == 2
        assert expected_booking.stockId == stock.id
        assert expected_booking.token == booking.token
        assert expected_booking.userId == beneficiary.id
        assert expected_booking.offerId == stock.offer.id
        assert expected_booking.name == stock.offer.name
        assert expected_booking.url == stock.offer.url
        assert expected_booking.email == beneficiary.email
        assert expected_booking.beginningDatetime == stock.beginningDatetime
        assert expected_booking.venueId == stock.offer.venue.id
        assert expected_booking.departementCode == stock.offer.venue.departementCode
        assert (
            expected_booking.thumb_url == f"http://localhost/storage/thumbs/products/{humanize(stock.offer.productId)}"
        )
    def test_should_return_one_payment_info_with_error_status(self, app):
        # Given
        stock = offers_factories.ThingStockFactory(price=10)
        now = datetime.utcnow()
        booking = bookings_factories.UsedIndividualBookingFactory(
            stock=stock, dateUsed=now, token="ABCDEF")
        payment = payments_factories.PaymentFactory(
            booking=booking,
            transactionLabel=
            "pass Culture Pro - remboursement 1ère quinzaine 07-2019")
        payments_factories.PaymentStatusFactory(payment=payment,
                                                status=TransactionStatus.ERROR,
                                                detail="Iban non fourni")

        # When
        payments = legacy_find_all_offerer_payments(
            stock.offer.venue.managingOfferer.id)

        # Then
        assert len(payments) == 1
        assert payments[0] == (
            "Doux",
            "Jeanne",
            None,
            None,
            "ABCDEF",
            now,
            1,
            Decimal("10.00"),
            stock.offer.name,
            "1 boulevard Poissonnière",
            stock.offer.venue.name,
            stock.offer.venue.siret,
            "1 boulevard Poissonnière",
            Decimal("10.00"),
            Decimal("1.00"),
            "CF13QSDFGH456789",
            "pass Culture Pro - remboursement 1ère quinzaine 07-2019",
            TransactionStatus.ERROR,
            "Iban non fourni",
        )
    def test_should_return_payment_to_retry_if_bank_information_linked_to_offerer_and_current_status_is_not_processable(
        self, app
    ):
        # Given
        user_offerer = offers_factories.UserOffererFactory()
        product = offers_factories.ThingProductFactory(name="Lire un livre", isNational=True)
        venue = offers_factories.VenueFactory(
            managingOfferer=user_offerer.offerer, postalCode="34000", departementCode="34"
        )
        offer = offers_factories.ThingOfferFactory(product=product, venue=venue)
        stock = offers_factories.ThingStockFactory(offer=offer, price=0)
        booking = bookings_factories.UsedIndividualBookingFactory(stock=stock)
        not_processable_payment = factories.PaymentFactory(booking=booking, amount=10)
        factories.PaymentStatusFactory(payment=not_processable_payment, status=TransactionStatus.NOT_PROCESSABLE)
        offers_factories.BankInformationFactory(offerer=user_offerer.offerer)

        # When
        payments_to_retry = payment_queries.find_not_processable_with_bank_information()

        # Then
        assert not_processable_payment in payments_to_retry
Exemple #29
0
    def test_returns_both_current_and_real_balances(self):
        # given
        offer = offers_factories.OfferFactory()
        stock1 = offers_factories.StockFactory(offer=offer, price=20)
        stock2 = offers_factories.StockFactory(offer=offer, price=30)
        stock3 = offers_factories.StockFactory(offer=offer, price=40)
        user = users_factories.BeneficiaryGrant18Factory(deposit__version=1)

        bookings_factories.IndividualBookingFactory(
            individualBooking__user=user, stock=stock1)
        bookings_factories.CancelledIndividualBookingFactory(
            individualBooking__user=user, stock=stock2)
        bookings_factories.UsedIndividualBookingFactory(
            individualBooking__user=user, stock=stock3, quantity=2)

        # when
        balances = get_all_users_wallet_balances()

        # then
        balance = balances[0]
        assert balance.current_balance == 500 - (20 + 40 * 2)
        assert balance.real_balance == 500 - (40 * 2)
    def test_should_not_return_payment_to_retry_if_bank_information_status_is_not_accepted(self, app):
        # Given
        user_offerer = offers_factories.UserOffererFactory()
        product = offers_factories.ThingProductFactory(name="Lire un livre", isNational=True)
        venue = offers_factories.VenueFactory(
            managingOfferer=user_offerer.offerer, postalCode="34000", departementCode="34"
        )
        offer = offers_factories.ThingOfferFactory(product=product, venue=venue)
        stock = offers_factories.ThingStockFactory(offer=offer, price=0)
        booking = bookings_factories.UsedIndividualBookingFactory(stock=stock)
        not_processable_payment = factories.PaymentFactory(
            booking=booking, amount=10, iban="CF13QSDFGH456789", bic="QSDFGH8Z555"
        )
        factories.PaymentStatusFactory(payment=not_processable_payment, status=TransactionStatus.NOT_PROCESSABLE)
        offers_factories.BankInformationFactory(
            offerer=user_offerer.offerer, iban=None, bic=None, status=BankInformationStatus.DRAFT
        )

        # When
        payments_to_retry = payment_queries.find_not_processable_with_bank_information()

        # Then
        assert payments_to_retry == []