Exemple #1
0
    def should_fail_when_url_has_no_scheme(self, app):
        # Given
        virtual_venue = offers_factories.VirtualVenueFactory()
        offer = offers_factories.OfferFactory(venue=virtual_venue)
        offers_factories.UserOffererFactory(
            user__email="*****@*****.**",
            offerer=offer.venue.managingOfferer,
        )

        # When
        data = {
            "name": "Les lièvres pas malins",
            "url": "missing.something",
        }
        client = TestClient(app.test_client()).with_auth("*****@*****.**")
        response = client.patch(f"offers/{humanize(offer.id)}", json=data)

        # Then
        assert response.status_code == 400
        assert response.json["url"] == ['L\'URL doit commencer par "http://" ou "https://"']
Exemple #2
0
    def test_digital_limit(self):
        beneficiary = self._get_beneficiary()
        product = offers_factories.DigitalProductFactory(
            subcategoryId=subcategories.VOD.id)
        offer = offers_factories.OfferFactory(product=product)
        factories.IndividualBookingFactory(
            individualBooking__user=beneficiary,
            stock__price=90,
            stock__offer=offer,
        )

        validation.check_expenses_limits(beneficiary, 10,
                                         offer)  # should not raise

        with pytest.raises(
                exceptions.DigitalExpenseLimitHasBeenReached) as error:
            validation.check_expenses_limits(beneficiary, 11, offer)
        assert error.value.errors["global"] == [
            "Le plafond de 100 € pour les offres numériques ne vous permet pas de réserver cette offre."
        ]
Exemple #3
0
    def should_fail_when_externalTicketOfficeUrl_has_no_host(self, app):
        # Given
        virtual_venue = offers_factories.VirtualVenueFactory()
        offer = offers_factories.OfferFactory(venue=virtual_venue)
        offers_factories.UserOffererFactory(
            user__email="*****@*****.**",
            offerer=offer.venue.managingOfferer,
        )

        # When
        data = {
            "name": "Les lièvres pas malins",
            "externalTicketOfficeUrl": "https://missing",
        }
        client = TestClient(app.test_client()).with_auth("*****@*****.**")
        response = client.patch(f"offers/{humanize(offer.id)}", json=data)

        # Then
        assert response.status_code == 400
        assert response.json["externalTicketOfficeUrl"] == ['L\'URL doit terminer par une extension (ex. ".fr")']
Exemple #4
0
    def test_digital_limit(self):
        beneficiary = users_factories.UserFactory(deposit__version=1)
        product = offers_factories.DigitalProductFactory(
            type=str(ThingType.AUDIOVISUEL))
        offer = offers_factories.OfferFactory(product=product)
        factories.BookingFactory(
            user=beneficiary,
            stock__price=190,
            stock__offer=offer,
        )

        validation.check_expenses_limits(beneficiary, 10,
                                         offer)  # should not raise

        with pytest.raises(
                exceptions.DigitalExpenseLimitHasBeenReached) as error:
            validation.check_expenses_limits(beneficiary, 11, offer)
        assert error.value.errors["global"] == [
            "Le plafond de 200 € pour les offres numériques ne vous permet pas de réserver cette offre."
        ]
Exemple #5
0
    def when_stock_is_on_an_offer_from_titelive_provider(
            self, app, db_session):
        # given
        provider = offerers_factories.ProviderFactory(
            localClass="TiteLiveThings")
        offer = offers_factories.OfferFactory(lastProvider=provider,
                                              idAtProviders="1")
        stock = offers_factories.StockFactory(offer=offer)

        user = users_factories.UserFactory(isAdmin=True)

        # when
        client = TestClient(app.test_client()).with_auth(user.email)
        response = client.delete(f"/stocks/{humanize(stock.id)}")

        # then
        assert response.status_code == 400
        assert response.json["global"] == [
            "Les offres importées ne sont pas modifiables"
        ]
Exemple #6
0
    def test_approve_offer_and_send_mail_to_administration(
        self,
        mocked_send_offer_validation_notification_to_administration,
        mocked_get_offerer_legal_category,
        mocked_validate_csrf_token,
        app,
    ):
        # Given
        config_yaml = """
                    minimum_score: 0.6
                    rules:
                       - name: "check offer name"
                         factor: 0
                         conditions:
                           - model: "Offer"
                             attribute: "name"
                             condition:
                                operator: "not in"
                                comparated: "REJECTED"
                    """
        import_offer_validation_config(config_yaml)
        users_factories.AdminFactory(email="*****@*****.**")
        offer = offers_factories.OfferFactory(validation=OfferValidationStatus.PENDING, isActive=True)
        mocked_get_offerer_legal_category.return_value = {
            "legal_category_code": 5202,
            "legal_category_label": "Société en nom collectif",
        }
        data = dict(validation=OfferValidationStatus.APPROVED.value, action="save")
        client = TestClient(app.test_client()).with_session_auth("*****@*****.**")

        # When
        response = client.post(f"/pc/back-office/validation/edit?id={offer.id}", form=data)

        # Then
        assert response.status_code == 302
        assert response.headers["location"] == "http://localhost/pc/back-office/validation/"
        assert offer.validation == OfferValidationStatus.APPROVED
        mocked_send_offer_validation_notification_to_administration.assert_called_once_with(
            OfferValidationStatus.APPROVED, offer
        )
        assert offer.lastValidationDate == datetime.datetime(2020, 11, 17, 15)
    def when_trying_to_patch_forbidden_attributes(self, app, client):
        # Given
        offer = offers_factories.OfferFactory()
        offers_factories.UserOffererFactory(
            user__email="*****@*****.**",
            offerer=offer.venue.managingOfferer,
        )

        # When
        data = {
            "dateCreated": serialize(datetime(2019, 1, 1)),
            "dateModifiedAtLastProvider": serialize(datetime(2019, 1, 1)),
            "id": 1,
            "idAtProviders": 1,
            "lastProviderId": 1,
            "owningOffererId": "AA",
            "thumbCount": 2,
            "subcategoryId": subcategories.LIVRE_PAPIER,
            "type": subcategories.LIVRE_PAPIER.matching_type,
        }
        response = client.with_session_auth("*****@*****.**").patch(
            f"offers/{humanize(offer.id)}", json=data)

        # Then
        assert response.status_code == 400
        assert response.json["owningOffererId"] == [
            "Vous ne pouvez pas changer cette information"
        ]
        forbidden_keys = {
            "dateCreated",
            "dateModifiedAtLastProvider",
            "id",
            "idAtProviders",
            "lastProviderId",
            "owningOffererId",
            "thumbCount",
            "subcategoryId",
            "type",
        }
        for key in forbidden_keys:
            assert key in response.json
Exemple #8
0
    def test_returns_a_thing_with_activation_code_stock(self, app):
        # Given
        beneficiary = users_factories.BeneficiaryGrant18Factory()
        offer = offers_factories.OfferFactory(
            stocks=[offers_factories.StockWithActivationCodesFactory()],
            subcategoryId=subcategories.ABO_PLATEFORME_MUSIQUE.id,
            url="fake-url",
        )

        # When
        client = TestClient(
            app.test_client()).with_session_auth(email=beneficiary.email)

        response = client.get(f"/offers/{humanize(offer.id)}")

        # Then
        assert response.status_code == 200
        data = response.json
        assert data["stocks"][0]["cancellationLimitDate"] is None
        assert data["subcategoryId"] == "ABO_PLATEFORME_MUSIQUE"
        assert data["stocks"][0]["hasActivationCode"] is True
Exemple #9
0
    def should_ignore_soft_deleted_stocks(self, app):
        offer = offers_factories.OfferFactory()
        offers_factories.StockFactory(
            offer=offer,
            bookingLimitDatetime=datetime(2019, 12, 31),  # within range
        )
        offers_factories.StockFactory(
            offer=offer,
            bookingLimitDatetime=datetime(2020, 1, 31),  # in the future
            isSoftDeleted=True,
        )

        expired_offer_ids = get_paginated_offer_ids_given_booking_limit_datetime_interval(
            limit=1,
            page=0,
            from_date=datetime(2019, 12, 30, 10, 0, 0),
            to_date=datetime(2019, 12, 31, 10, 0, 0))

        # Then
        expired_offer_ids = from_tuple_to_int(expired_offer_ids)
        assert expired_offer_ids == [offer.id]
    def test_forbidden_on_imported_offer_on_other_fields(self):
        provider = offerers_factories.ProviderFactory()
        offer = factories.OfferFactory(lastProvider=provider,
                                       name="Old name",
                                       isDuo=False,
                                       audioDisabilityCompliant=True)

        with pytest.raises(models.ApiErrors) as error:
            api.update_offer(offer,
                             name="New name",
                             isDuo=True,
                             audioDisabilityCompliant=False)

        assert error.value.errors == {
            "name": ["Vous ne pouvez pas modifier ce champ"],
            "isDuo": ["Vous ne pouvez pas modifier ce champ"],
        }
        offer = models.Offer.query.one()
        assert offer.name == "Old name"
        assert offer.isDuo == False
        assert offer.audioDisabilityCompliant == True
    def test_a_digital_booking_with_activation_code_is_automatically_used(
            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 offre numérique", 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="",
            prix="10.00 €",
            is_event=0,
            nom_offre="Super offre numérique",
            offer_type="VOD",
            quantity=1,
            can_expire=0,
            is_booking_autovalidated=1,
            must_use_token_for_payment=0,
            contremarque=booking.token,
        )
        assert email_data == expected
Exemple #12
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_accepts_request(app):
    ProviderFactory(name="Pass Culture API Stocks", localClass="PCAPIStocks")
    offerer = offers_factories.OffererFactory(siren=123456789)
    venue = offers_factories.VenueFactory(managingOfferer=offerer, id=3)
    offer_to_update = offers_factories.OfferFactory(
        product__idAtProviders="123456789",
        product__subcategoryId="LIVRE_PAPIER",
        idAtProviders=f"123456789@{venue.id}",
        venue=venue,
    )
    ApiKeyFactory(offerer=offerer)

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

    response = test_client.post(
        f"/v2/venue/{venue.id}/stocks",
        json={
            "stocks": [
                {
                    "ref": "123456789",
                    "available": 4,
                    "price": 30
                },
                {
                    "ref": "1234567890",
                    "available": 0,
                    "price": 10
                },
            ]
        },
    )

    assert response.status_code == 204
    assert len(offer_to_update.stocks) == 1
    assert offer_to_update.stocks[0].quantity == 4
    assert offer_to_update.stocks[0].price == 30
Exemple #14
0
    def test_rejection_email(self):
        # Given
        offer = offer_factories.OfferFactory(name="Ma petite offre",
                                             venue__name="Mon stade")

        # When
        new_offer_validation_email = retrieve_data_for_offer_rejection_email(
            offer)

        # Then
        assert new_offer_validation_email == {
            "MJ-TemplateID": 2613942,
            "FromEmail": "*****@*****.**",
            "MJ-TemplateLanguage": True,
            "Vars": {
                "offer_name":
                "Ma petite offre",
                "venue_name":
                "Mon stade",
                "pc_pro_offer_link":
                f"{settings.PRO_URL}/offres/{humanize(offer.id)}/edition",
            },
        }
Exemple #15
0
    def test_approve_rejected_offer(
        self,
        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.REJECTED, isActive=True)
            frozen_time.move_to("2020-12-20 15:00:00")
            data = dict(validation=OfferValidationStatus.APPROVED.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.APPROVED
        assert offer.lastValidationDate == datetime.datetime(2020, 12, 20, 15)

        mocked_send_offer_validation_notification_to_administration.assert_called_once_with(
            OfferValidationStatus.APPROVED, offer
        )
        assert mocked_send_offer_validation_status_update_email.call_count == 1
Exemple #16
0
    def test_patch_non_approved_offer_fails(self, app):
        pending_validation_offer = offers_factories.OfferFactory(
            validation=OfferValidationStatus.PENDING)
        stock = offers_factories.StockFactory(offer=pending_validation_offer)
        offers_factories.UserOffererFactory(
            user__email="*****@*****.**",
            offerer=pending_validation_offer.venue.managingOfferer,
        )
        stock_data = {
            "offerId": humanize(pending_validation_offer.id),
            "stocks": [{
                "id": humanize(stock.id),
                "price": 20
            }],
        }

        response = (TestClient(
            app.test_client()).with_session_auth("*****@*****.**").post(
                "/stocks/bulk/", json=stock_data))

        assert response.status_code == 400
        assert response.json["global"] == [
            "Les offres refusées ou en attente de validation ne sont pas modifiables"
        ]
    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.UserFactory(deposit__version=1)

        bookings_factories.BookingFactory(user=user, stock=stock1)
        bookings_factories.BookingFactory(user=user,
                                          stock=stock2,
                                          isCancelled=True)
        bookings_factories.BookingFactory(user=user,
                                          stock=stock3,
                                          isUsed=True,
                                          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)
Exemple #18
0
 def test_use_product(self):
     product = factories.ProductFactory(thumbCount=1)
     offer = factories.OfferFactory(product=product)
     assert offer.thumbUrl.startswith("http")
     assert offer.thumbUrl == product.thumbUrl
 def test_mark_as_unused_digital_offer(self):
     offer = offers_factories.OfferFactory(product=offers_factories.DigitalProductFactory())
     booking = booking_factories.UsedIndividualBookingFactory(stock__offer=offer)
     api.mark_as_unused(booking)
     assert not booking.isUsed
     assert booking.status is not BookingStatus.USED
Exemple #20
0
 def test_editable_if_from_allocine(self):
     provider = providers_factories.ProviderFactory(localClass="AllocineStocks")
     offer = factories.OfferFactory(lastProvider=provider)
     assert offer.isEditable
Exemple #21
0
 def test_not_editabe_if_from_another_provider(self):
     provider = providers_factories.ProviderFactory(localClass="TiteLiveStocks")
     offer = factories.OfferFactory(lastProvider=provider)
     assert not offer.isEditable
Exemple #22
0
    def test_stock_with_positive_remaining_quantity(self):
        offer = factories.OfferFactory()
        stock = factories.StockFactory(offer=offer, quantity=5)

        assert stock.remainingQuantity == 5
        assert Offer.query.filter(Stock.remainingQuantity == 5).one() == offer
Exemple #23
0
 def test_editable_if_not_from_provider(self):
     offer = factories.OfferFactory()
     assert offer.isEditable
Exemple #24
0
    def test_bookings_quantity_without_bookings(self):
        offer = factories.OfferFactory()
        stock = factories.StockFactory(offer=offer, quantity=None)

        assert Stock.query.filter(Stock.dnBookedQuantity == 0).one() == stock
Exemple #25
0
    def test_offer_without_stocks(self):
        offer = factories.OfferFactory()

        assert offer.isSoldOut
        assert Offer.query.filter(Offer.isSoldOut.is_(True)).one() == offer
        assert Offer.query.filter(Offer.isSoldOut.is_(False)).count() == 0
Exemple #26
0
    def test_pending(self):
        pending_offer = factories.OfferFactory(
            validation=OfferValidationStatus.PENDING)

        assert pending_offer.status == OfferStatus.PENDING
Exemple #27
0
    def test_rejected(self):
        rejected_offer = factories.OfferFactory(
            validation=OfferValidationStatus.REJECTED, isActive=False)

        assert rejected_offer.status == OfferStatus.REJECTED
Exemple #28
0
 def test_factory_object_defaults_to_approved(self):
     offer = factories.OfferFactory()
     assert offer.validation == OfferValidationStatus.APPROVED
Exemple #29
0
    def test_does_not_raise_error_when_offer_type_is_editable(self):
        offer = factories.OfferFactory(lastProviderId=None)

        validation.check_offer_is_editable(offer)  # should not raise
Exemple #30
0
 def should_not_raise_an_error_when_offer_is_not_from_provider(self):
     offer = factories.OfferFactory(lastProvider=None)
     validation.check_stocks_are_editable_for_offer(
         offer)  # should not raise