def test_venue_with_draft_bank_information(self):
        offerer = offerers_factories.OffererFactory()
        offers_factories.VirtualVenueFactory(managingOfferer=offerer)
        venue = offers_factories.VenueFactory(managingOfferer=offerer)
        offers_factories.BankInformationFactory(venue=venue, status=BankInformationStatus.DRAFT)

        assert not has_physical_venue_without_draft_or_accepted_bank_information(offerer_id=offerer.id)
Beispiel #2
0
    def when_creating_new_thing_offer(self, app):
        # Given
        venue = offers_factories.VirtualVenueFactory()
        offerer = venue.managingOfferer
        offers_factories.UserOffererFactory(offerer=offerer, user__email="*****@*****.**")

        # When
        client = TestClient(app.test_client()).with_auth("*****@*****.**")
        data = {
            "venueId": humanize(venue.id),
            "bookingEmail": "*****@*****.**",
            "mediaUrls": ["http://example.com/media"],
            "name": "Les lièvres pas malins",
            "type": "ThingType.JEUX_VIDEO",
            "url": "http://example.com/offer",
        }
        response = client.post("/offers", json=data)

        # Then
        assert response.status_code == 201
        offer_id = dehumanize(response.json["id"])
        offer = Offer.query.get(offer_id)
        assert offer.bookingEmail == "*****@*****.**"
        assert offer.type == str(ThingType.JEUX_VIDEO)
        assert offer.venue == venue
        assert offer.product.name == "Les lièvres pas malins"
        assert offer.product.url == "http://example.com/offer"
        assert offer.url == "http://example.com/offer"
        assert offer.isDigital
        assert offer.isNational
        assert offer.product.isNational
        assert offer.product.owningOfferer == offerer
Beispiel #3
0
    def test_fail_when_offer_type_does_not_allow_virtual_offer_and_venue_is_virtuel(
            self, app):
        # Given
        venue = offers_factories.VirtualVenueFactory()
        offerer = venue.managingOfferer
        offers_factories.UserOffererFactory(offerer=offerer,
                                            user__email="*****@*****.**")

        # When
        data = {
            "type": "ThingType.JEUX",
            "name": "Le grand jeu",
            "url": "http://legrandj.eu",
            "mediaUrls": ["http://media.url"],
            "venueId": humanize(venue.id),
            "audioDisabilityCompliant": True,
            "mentalDisabilityCompliant": False,
            "motorDisabilityCompliant": False,
            "visualDisabilityCompliant": False,
        }
        client = TestClient(app.test_client()).with_auth("*****@*****.**")
        response = client.post("/offers", json=data)

        # Then
        assert response.status_code == 400
        assert response.json["url"] == [
            "Une offre de type Jeux (support physique) ne peut pas être numérique"
        ]
Beispiel #4
0
def get_existing_pro_validated_user_with_validated_offerer_validated_user_offerer_no_physical_venue():
    user_offerer = offers_factories.UserOffererFactory(
        validationToken=None,
        offerer__validationToken=None,
        user__validationToken=None,
    )
    offers_factories.VirtualVenueFactory(managingOfferer=user_offerer.offerer)
    return {"offerer": get_offerer_helper(user_offerer.offerer), "user": get_pro_helper(user_offerer.user)}
    def test_venues_with_missing_and_accepted_bank_information(self):
        offerer = offerers_factories.OffererFactory()
        offers_factories.VirtualVenueFactory(managingOfferer=offerer)
        offers_factories.VenueFactory(managingOfferer=offerer)
        venue_with_rejected_bank_information = offers_factories.VenueFactory(managingOfferer=offerer)
        offers_factories.BankInformationFactory(
            venue=venue_with_rejected_bank_information, status=BankInformationStatus.ACCEPTED
        )

        assert has_physical_venue_without_draft_or_accepted_bank_information(offerer_id=offerer.id)
Beispiel #6
0
    def test_success_if_digital_product_and_virtual_venue(self):
        venue = factories.VirtualVenueFactory()
        user_offerer = factories.UserOffererFactory(offerer=venue.managingOfferer)
        product = factories.DigitalProductFactory()

        data = offers_serialize.PostOfferBodyModel(
            venueId=humanize(venue.id),
            productId=humanize(product.id),
        )
        api.create_offer(data, user_offerer.user)  # should not fail
Beispiel #7
0
    def test_should_return_numerique_when_venue_is_virtual(
            self, mock_is_offer_active, mock_build_pc_pro_offer_link):
        # Given
        virtual_venue = offers_factories.VirtualVenueFactory()
        stock = offers_factories.ThingStockFactory(offer__venue=virtual_venue)
        booking1 = bookings_factories.CancelledIndividualBookingFactory(
            stock=stock, quantity=2)
        booking2 = bookings_factories.IndividualBookingFactory(stock=stock)

        # When
        mailjet_data = retrieve_offerer_booking_recap_email_data_after_user_cancellation(
            booking1)

        # Then
        assert mailjet_data == {
            "MJ-TemplateID": 780015,
            "MJ-TemplateLanguage": True,
            "Vars": {
                "departement":
                "numérique",
                "nom_offre":
                stock.offer.name,
                "lien_offre_pcpro":
                "http://pc_pro.com/offer_link",
                "nom_lieu":
                virtual_venue.name,
                "prix":
                f"{stock.price}",
                "is_event":
                0,
                "date":
                "",
                "heure":
                "",
                "quantite":
                booking1.quantity,
                "user_name":
                booking1.publicName,
                "user_email":
                booking1.email,
                "is_active":
                0,
                "nombre_resa":
                1,
                "users": [{
                    "contremarque": booking2.token,
                    "email": booking2.email,
                    "firstName": booking2.firstName,
                    "lastName": booking2.lastName,
                }],
            },
        }
Beispiel #8
0
    def test_fail_if_physical_product_and_virtual_venue(self):
        venue = factories.VirtualVenueFactory()
        user_offerer = factories.UserOffererFactory(offerer=venue.managingOfferer)
        product = factories.ProductFactory()

        data = offers_serialize.PostOfferBodyModel(
            venueId=humanize(venue.id),
            productId=humanize(product.id),
        )
        with pytest.raises(api_errors.ApiErrors) as error:
            api.create_offer(data, user_offerer.user)
        err = 'Une offre physique ne peut être associée au lieu "Offre numérique"'
        assert error.value.errors["venue"] == [err]
def get_existing_pro_validated_user_with_at_least_one_visible_activated_offer(
):
    user_offerer = offers_factories.UserOffererFactory(
        validationToken=None,
        offerer__validationToken=None,
        user__validationToken=None,
    )
    venue = offers_factories.VirtualVenueFactory(
        managingOfferer=user_offerer.offerer)
    offer = offers_factories.OfferFactory(venue=venue, isActive=True)

    return {
        "offer": get_offer_helper(offer),
        "user": get_pro_helper(user_offerer.user)
    }
Beispiel #10
0
    def test_with_virtual_offer(self):
        # Given
        author = users_factories.ProFactory()
        offer = offers_factories.EventOfferFactory(
            author=author,
            product=offers_factories.DigitalProductFactory(
                name="Les lièvres pas malins"),
            venue=offers_factories.VirtualVenueFactory(),
        )

        # When
        email = make_offer_creation_notification_email(offer)

        # Then
        assert email[
            "Subject"] == "[Création d’offre - numérique] Les lièvres pas malins"
Beispiel #11
0
    def when_user_is_not_attached_to_offerer(self, app):
        # Given
        users_factories.UserFactory(email="*****@*****.**")
        venue = offers_factories.VirtualVenueFactory()

        # When
        client = TestClient(app.test_client()).with_auth("*****@*****.**")
        data = {
            "venueId": humanize(venue.id),
        }
        response = client.post("/offers", json=data)

        # Then
        assert response.status_code == 403
        assert response.json["global"] == [
            "Vous n'avez pas les droits d'accès suffisant pour accéder à cette information."
        ]
def get_existing_pro_validated_user_with_validated_offerer_with_iban_validated_user_offerer_with_event_offer_with_no_stock(
):
    user_offerer = offers_factories.UserOffererFactory(
        validationToken=None,
        offerer__validationToken=None,
        user__validationToken=None,
    )
    offers_factories.BankInformationFactory(offerer=user_offerer.offerer)
    venue = offers_factories.VirtualVenueFactory(
        managingOfferer=user_offerer.offerer)
    offer = offers_factories.EventOfferFactory(venue=venue, isActive=True)

    return {
        "offer": get_offer_helper(offer),
        "offerer": get_offerer_helper(user_offerer.offerer),
        "user": get_pro_helper(user_offerer.user),
        "venue": get_venue_helper(venue),
    }
Beispiel #13
0
    def should_fail_when_externalTicketOfficeUrl_has_no_host(self, app):
        # Given
        venue = offers_factories.VirtualVenueFactory()
        offerer = venue.managingOfferer
        offers_factories.UserOffererFactory(offerer=offerer, user__email="*****@*****.**")

        # When
        client = TestClient(app.test_client()).with_session_auth("*****@*****.**")
        data = {
            "venueId": humanize(venue.id),
            "name": "Les lièvres pas malins",
            "subcategoryId": subcategories.JEU_EN_LIGNE.id,
            "externalTicketOfficeUrl": "https://missing",
        }
        response = client.post("/offers", json=data)

        # Then
        assert response.status_code == 400
        assert response.json["externalTicketOfficeUrl"] == ['L\'URL doit terminer par une extension (ex. ".fr")']
Beispiel #14
0
    def should_fail_when_url_has_no_scheme(self, app):
        # Given
        venue = offers_factories.VirtualVenueFactory()
        offerer = venue.managingOfferer
        offers_factories.UserOffererFactory(offerer=offerer, user__email="*****@*****.**")

        # When
        client = TestClient(app.test_client()).with_session_auth("*****@*****.**")
        data = {
            "venueId": humanize(venue.id),
            "name": "Les lièvres pas malins",
            "subcategoryId": subcategories.JEU_EN_LIGNE.id,
            "url": "missing.something",
        }
        response = client.post("/offers", json=data)

        # Then
        assert response.status_code == 400
        assert response.json["url"] == ['L\'URL doit commencer par "http://" ou "https://"']
Beispiel #15
0
    def when_creating_new_thing_offer(self, app):
        # Given
        venue = offers_factories.VirtualVenueFactory()
        offerer = venue.managingOfferer
        offers_factories.UserOffererFactory(offerer=offerer, user__email="*****@*****.**")

        # When
        client = TestClient(app.test_client()).with_session_auth("*****@*****.**")
        data = {
            "venueId": humanize(venue.id),
            "bookingEmail": "*****@*****.**",
            "mediaUrls": ["http://example.com/media"],
            "name": "Les lièvres pas malins",
            "subcategoryId": subcategories.JEU_EN_LIGNE.id,
            "url": "http://example.com/offer",
            "externalTicketOfficeUrl": "http://example.net",
            "audioDisabilityCompliant": True,
            "mentalDisabilityCompliant": False,
            "motorDisabilityCompliant": False,
            "visualDisabilityCompliant": False,
        }
        response = client.post("/offers", json=data)

        # Then
        assert response.status_code == 201
        offer_id = dehumanize(response.json["id"])
        offer = Offer.query.get(offer_id)
        assert offer.bookingEmail == "*****@*****.**"
        assert offer.subcategoryId == subcategories.JEU_EN_LIGNE.id
        assert offer.venue == venue
        assert offer.product.name == "Les lièvres pas malins"
        assert offer.product.url == "http://example.com/offer"
        assert offer.externalTicketOfficeUrl == "http://example.net"
        assert offer.url == "http://example.com/offer"
        assert offer.isDigital
        assert offer.isNational
        assert offer.product.isNational
        assert offer.product.owningOfferer == offerer
        assert offer.motorDisabilityCompliant == False
        assert offer.visualDisabilityCompliant == False
        assert offer.audioDisabilityCompliant == True
        assert offer.mentalDisabilityCompliant == False
Beispiel #16
0
    def test_fail_if_incoherent_input(self, app):
        # Given
        venue = offers_factories.VirtualVenueFactory()
        offerer = venue.managingOfferer
        offers_factories.UserOffererFactory(offerer=offerer, user__email="*****@*****.**")

        # When
        data = {
            "type": "ThingType.JEUX",
            "name": "Le grand jeu",
            "url": "http://legrandj.eu",
            "mediaUrls": ["http://media.url"],
            "venueId": humanize(venue.id),
        }
        client = TestClient(app.test_client()).with_auth("*****@*****.**")
        response = client.post("/offers", json=data)

        # Then
        assert response.status_code == 400
        assert response.json["url"] == ["Une offre de type Jeux (support physique) ne peut pas être numérique"]
Beispiel #17
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://"']
Beispiel #18
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")']
Beispiel #19
0
    def test_fail_when_offer_subcategory_is_offline_only_and_venue_is_virtuel(self, app):
        # Given
        venue = offers_factories.VirtualVenueFactory()
        offerer = venue.managingOfferer
        offers_factories.UserOffererFactory(offerer=offerer, user__email="*****@*****.**")

        # When
        data = {
            "subcategoryId": subcategories.ACHAT_INSTRUMENT.id,
            "name": "Le grand jeu",
            "url": "http://legrandj.eu",
            "mediaUrls": ["http://media.url"],
            "venueId": humanize(venue.id),
            "audioDisabilityCompliant": True,
            "mentalDisabilityCompliant": False,
            "motorDisabilityCompliant": False,
            "visualDisabilityCompliant": False,
        }
        client = TestClient(app.test_client()).with_session_auth("*****@*****.**")
        response = client.post("/offers", json=data)

        # Then
        assert response.status_code == 400
        assert response.json["url"] == ["Une offre de sous-catégorie Achat instrument ne peut pas être numérique"]
    def test_digital_venue_without_offer(self):
        offerer = offerers_factories.OffererFactory()
        offers_factories.VirtualVenueFactory(managingOfferer=offerer)

        assert not has_digital_venue_with_at_least_one_offer(offerer.id)
    def test_return_managing_offerer_timezone_when_venue_is_virtual(self):
        offers_factories.VirtualVenueFactory(managingOfferer__postalCode="97300")

        query_result = Venue.query.filter(Venue.timezone == "America/Cayenne").all()

        assert len(query_result) == 1
Beispiel #22
0
def test_generate_and_send_payments():
    # Comments below indicate what `generate_and_send_payments()` will
    # do, no what the setup does.
    cutoff = datetime.datetime.now()
    before_cutoff = cutoff - datetime.timedelta(days=1)

    # 1 new payment + 1 retried payment for venue 1
    venue1 = offers_factories.VenueFactory(name="venue1")
    offers_factories.BankInformationFactory(venue=venue1)
    booking11 = bookings_factories.UsedBookingFactory(
        dateUsed=before_cutoff, stock__offer__venue=venue1)
    booking12 = bookings_factories.UsedBookingFactory(
        dateUsed=before_cutoff, stock__offer__venue=venue1)
    payment12 = payments_factories.PaymentFactory(booking=booking12)
    payments_factories.PaymentStatusFactory(payment=payment12,
                                            status=TransactionStatus.ERROR)
    payment13 = payments_factories.PaymentFactory(
        booking__stock__offer__venue=venue1)
    payments_factories.PaymentStatusFactory(payment=payment13,
                                            status=TransactionStatus.SENT)
    bookings_factories.BookingFactory(stock__offer__venue=venue1)

    # 1 new payment for venue 2
    venue2 = offers_factories.VenueFactory(name="venue2")
    offers_factories.BankInformationFactory(offerer=venue2.managingOfferer)
    booking2 = bookings_factories.UsedBookingFactory(
        dateUsed=before_cutoff, stock__offer__venue=venue2)

    # 0 payment for venue 3 (existing booking has already been reimbursed)
    payment3 = payments_factories.PaymentFactory()
    payments_factories.PaymentStatusFactory(payment=payment3,
                                            status=TransactionStatus.SENT)

    # 1 new payment (not processable) for venue 4 (no IBAN nor BIC)
    venue4 = offers_factories.VenueFactory()
    booking4 = bookings_factories.UsedBookingFactory(
        dateUsed=before_cutoff, stock__offer__venue=venue4)

    # 0 payment for venue 5 (booking is not used)
    venue5 = offers_factories.VenueFactory()
    bookings_factories.BookingFactory(stock__offer__venue=venue5)

    # 0 payment for venue 6 (booking has been used after cutoff)
    venue6 = offers_factories.VenueFactory(name="venue2")
    offers_factories.BankInformationFactory(offerer=venue6.managingOfferer)
    bookings_factories.UsedBookingFactory(dateUsed=cutoff,
                                          stock__offer__venue=venue2)

    # 1 new payment for digital venue
    virtual_venue = offers_factories.VirtualVenueFactory()
    offers_factories.BankInformationFactory(
        offerer=virtual_venue.managingOfferer)
    digital_reimbursable_offer = offers_factories.DigitalOfferFactory(
        venue=virtual_venue,
        subcategoryId=subcategories.CINE_VENTE_DISTANCE.id)
    digital_booking = bookings_factories.UsedBookingFactory(
        dateUsed=before_cutoff, stock__offer=digital_reimbursable_offer)

    last_payment_id = Payment.query.with_entities(func.max(
        Payment.id)).scalar()
    last_status_id = PaymentStatus.query.with_entities(
        func.max(PaymentStatus.id)).scalar()

    generate_and_send_payments(cutoff)

    # Check new payments and statuses
    new_payments = Payment.query.filter(Payment.id > last_payment_id).all()
    assert set(p.booking for p in new_payments) == {
        booking11, booking2, booking4, digital_booking
    }

    new_statuses = (PaymentStatus.query.filter(
        PaymentStatus.id > last_status_id).join(
            PaymentStatus.payment).order_by(Payment.bookingId))
    assert set((s.payment.booking, s.status) for s in new_statuses) == {
        (booking11, TransactionStatus.PENDING),
        (booking11, TransactionStatus.UNDER_REVIEW),
        (booking12, TransactionStatus.UNDER_REVIEW),
        (booking2, TransactionStatus.PENDING),
        (booking2, TransactionStatus.UNDER_REVIEW),
        (booking4, TransactionStatus.NOT_PROCESSABLE),
        (digital_booking, TransactionStatus.PENDING),
        (digital_booking, TransactionStatus.UNDER_REVIEW),
    }

    # Check "transaction" e-mail
    email = mails_testing.outbox[0]
    subject = email.sent_data["Subject"].split("-")[0].strip()  # ignore date
    assert subject == "Virements XML pass Culture Pro"
    xml = base64.b64decode(
        email.sent_data["Attachments"][0]["Content"]).decode("utf-8")
    assert "<NbOfTxs>4</NbOfTxs>" in xml
    assert "<CtrlSum>40.00</CtrlSum>" in xml
    assert xml.count("<EndToEndId>") == 4

    # Check "report" e-mail
    email = mails_testing.outbox[1]
    subject = email.sent_data["Subject"].split("-")[0].strip()  # ignore date
    assert subject == "Récapitulatif des paiements pass Culture Pro"
    html = email.sent_data["Html-part"]
    assert "Nombre total de paiements : 5" in html
    assert "NOT_PROCESSABLE : 1" in html
    assert "UNDER_REVIEW : 4" in html

    # Check "details" e-mail
    email = mails_testing.outbox[2]
    subject = email.sent_data["Subject"].split("-")[0].strip()  # ignore date
    assert subject == "Détails des paiements pass Culture Pro"
    zip_data = base64.b64decode(email.sent_data["Attachments"][0]["Content"])
    with zipfile.ZipFile(io.BytesIO(zip_data)) as zf:
        csv = zf.open(zf.namelist()[0]).read().decode("utf-8")
    rows = csv.splitlines()
    assert len(rows) == 5  # header + 4 payments

    # Check "wallet balance" e-mail
    email = mails_testing.outbox[3]
    subject = email.sent_data["Subject"].split("-")[0].strip()  # ignore date
    assert subject == "Soldes des utilisateurs pass Culture"
    zip_data = base64.b64decode(email.sent_data["Attachments"][0]["Content"])
    with zipfile.ZipFile(io.BytesIO(zip_data)) as zf:
        csv = zf.open(zf.namelist()[0]).read().decode("utf-8")
    rows = csv.splitlines()
    assert len(rows) == users_models.User.query.count() + 1  # + header
    def test_return_managing_offerer_timezone_when_venue_is_virtual(self):
        venue = offers_factories.VirtualVenueFactory(managingOfferer__postalCode="97300")

        assert venue.timezone == "America/Cayenne"