def test_delete_cascade_venue_should_remove_bank_informations_of_venue():
    # Given
    venue_to_delete = offers_factories.VenueFactory()
    offers_factories.BankInformationFactory(venue=venue_to_delete)
    offers_factories.BankInformationFactory()

    # When
    delete_cascade_venue_by_id(venue_to_delete.id)

    # Then
    assert Venue.query.count() == 0
    assert Offerer.query.count() == 1
    assert BankInformation.query.count() == 1
    def test_venues_with_rejected_and_accepted_bank_information(self):
        offerer = offerers_factories.OffererFactory()
        offers_factories.VirtualVenueFactory(managingOfferer=offerer)
        venue_with_rejected_bank_information = offers_factories.VenueFactory(managingOfferer=offerer)
        offers_factories.BankInformationFactory(
            venue=venue_with_rejected_bank_information, status=BankInformationStatus.REJECTED
        )
        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)
示例#3
0
    def test_should_not_set_not_processable_payments_to_retry_when_bank_information_status_is_not_accepted(self):
        # Given
        offerer = offers_factories.OffererFactory(name="first offerer")
        stock = offers_factories.ThingStockFactory(offer__venue__managingOfferer=offerer)
        booking = bookings_factories.UsedBookingFactory(stock=stock)
        offers_factories.BankInformationFactory(
            offerer=offerer, iban=None, bic=None, status=BankInformationStatus.DRAFT
        )
        not_processable_payment = payments_factories.PaymentFactory(booking=booking, amount=10, iban=None, bic=None)
        payments_factories.PaymentStatusFactory(
            payment=not_processable_payment, status=TransactionStatus.NOT_PROCESSABLE
        )

        sent_payment = payments_factories.PaymentFactory(booking=booking, amount=10)
        payments_factories.PaymentStatusFactory(payment=sent_payment, status=TransactionStatus.SENT)

        new_batch_date = datetime.datetime.now()

        # When

        set_not_processable_payments_with_bank_information_to_retry(new_batch_date)

        # Then
        queried_not_processable_payment = Payment.query.filter_by(id=not_processable_payment.id).one()
        queried_sent_payment = Payment.query.filter_by(id=sent_payment.id).one()
        assert queried_not_processable_payment.iban == None
        assert queried_not_processable_payment.bic == None
        assert queried_not_processable_payment.batchDate != new_batch_date
        assert queried_not_processable_payment.currentStatus.status == TransactionStatus.NOT_PROCESSABLE
        assert queried_sent_payment.currentStatus.status == TransactionStatus.SENT
    def test_reimburses_95_percent_for_book_product_when_bookings_exceed_100000_euros(
            self):
        # Given
        cutoff = datetime.datetime.now()
        before_cutoff = cutoff - datetime.timedelta(days=1)

        beneficiary = users_factories.BeneficiaryGrant18Factory(
            email="*****@*****.**")
        offerer1 = offers_factories.OffererFactory(siren="123456789")
        offers_factories.BankInformationFactory(
            bic="BDFEFR2LCCB",
            iban="FR7630006000011234567890189",
            offerer=offerer1)
        venue1 = offers_factories.VenueFactory(managingOfferer=offerer1,
                                               siret="12345678912345")
        venue2 = offers_factories.VenueFactory(managingOfferer=offerer1,
                                               siret="98765432154321")
        venue3 = offers_factories.VenueFactory(managingOfferer=offerer1,
                                               siret="98123432154321")
        product = offers_factories.ThingProductFactory(
            subcategoryId=subcategories.LIVRE_PAPIER.id)
        offer1 = offers_factories.ThingOfferFactory(venue=venue1,
                                                    product=product)
        offer2 = offers_factories.ThingOfferFactory(venue=venue2,
                                                    product=product)
        offer3 = offers_factories.ThingOfferFactory(venue=venue3,
                                                    product=product)

        paying_stock1 = offers_factories.ThingStockFactory(offer=offer1,
                                                           price=10000)
        paying_stock2 = offers_factories.ThingStockFactory(offer=offer2,
                                                           price=10000)
        paying_stock3 = offers_factories.ThingStockFactory(offer=offer3,
                                                           price=100000)
        offers_factories.ThingStockFactory(offer=offer1, price=0)

        beneficiary.deposit.amount = 120000
        repository.save(beneficiary.deposit)

        bookings_factories.UsedBookingFactory(user=beneficiary,
                                              stock=paying_stock1,
                                              dateUsed=before_cutoff,
                                              quantity=1)
        bookings_factories.UsedBookingFactory(user=beneficiary,
                                              stock=paying_stock2,
                                              dateUsed=before_cutoff,
                                              quantity=1)
        bookings_factories.UsedBookingFactory(user=beneficiary,
                                              stock=paying_stock3,
                                              dateUsed=before_cutoff,
                                              quantity=1)

        # When
        generate_new_payments(cutoff, batch_date=datetime.datetime.now())

        # Then
        pending = get_pending_payments()
        assert pending.count() == 3
        assert total_amount(pending) == 115000
        assert get_not_processable_payments().count() == 0
示例#5
0
    def test_should_set_not_processable_payments_to_retry_and_update_payments_bic_and_iban_using_venue_information(
        self,
    ):
        # Given
        offerer = offers_factories.OffererFactory(name="first offerer")
        stock = offers_factories.ThingStockFactory(offer__venue__managingOfferer=offerer)
        booking = bookings_factories.UsedBookingFactory(stock=stock)
        offers_factories.BankInformationFactory(offerer=offerer, iban="FR7611808009101234567890147", bic="CCBPFRPPVER")
        not_processable_payment = payments_factories.PaymentFactory(booking=booking, amount=10, iban=None, bic=None)
        payments_factories.PaymentStatusFactory(
            payment=not_processable_payment, status=TransactionStatus.NOT_PROCESSABLE
        )

        sent_payment = payments_factories.PaymentFactory(
            booking=booking, amount=10, iban="FR7630007000111234567890144", bic="BDFEFR2LCCB"
        )
        payments_factories.PaymentStatusFactory(payment=sent_payment, status=TransactionStatus.SENT)

        new_batch_date = datetime.datetime.now()

        # When
        set_not_processable_payments_with_bank_information_to_retry(new_batch_date)

        # Then
        queried_not_processable_payment = Payment.query.filter_by(id=not_processable_payment.id).one()
        assert queried_not_processable_payment.iban == "FR7611808009101234567890147"
        assert queried_not_processable_payment.bic == "CCBPFRPPVER"
        assert queried_not_processable_payment.batchDate == new_batch_date
    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)
示例#7
0
    def test_use_iban_and_bic_from_venue(self):
        booking = bookings_factories.IndividualBookingFactory()
        offers_factories.BankInformationFactory(venue=booking.venue,
                                                iban="iban1",
                                                bic="bic1")
        offers_factories.BankInformationFactory(offerer=booking.offerer,
                                                iban="iban2",
                                                bic="bic2")
        reimbursement = BookingReimbursement(booking,
                                             PhysicalOffersReimbursement(),
                                             Decimal(10))
        batch_date = datetime.utcnow()

        payment = create_payment_for_booking(reimbursement, batch_date)

        assert payment.iban == "IBAN1"
        assert payment.bic == "BIC1"
    def test_use_custom_reimbursement_rule_with_rate(self):
        booking = bookings_factories.UsedBookingFactory(amount=10, quantity=2)
        offerer = booking.offerer
        rule = payments_factories.CustomReimbursementRuleFactory(
            offerer=booking.offerer, rate=0.8)
        offers_factories.BankInformationFactory(offerer=offerer,
                                                iban="iban1",
                                                bic="bic1")

        cutoff = batch_date = datetime.datetime.now()
        generate_new_payments(cutoff, batch_date)

        payment = Payment.query.one()
        assert payment.amount == 16  # 2 (quantity) * 0.8 (rate) * 10 (amount)
        assert payment.customReimbursementRule == rule
        assert payment.reimbursementRate == Decimal("0.8")
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),
    }
    def test_use_custom_reimbursement_rule_with_amount(self):
        offer = offers_factories.DigitalOfferFactory()
        offers_factories.BankInformationFactory(venue=offer.venue,
                                                iban="iban1",
                                                bic="bic1")
        bookings_factories.UsedBookingFactory(amount=10,
                                              quantity=2,
                                              stock__offer=offer)
        rule = payments_factories.CustomReimbursementRuleFactory(offer=offer,
                                                                 amount=7)

        cutoff = batch_date = datetime.datetime.now()
        generate_new_payments(cutoff, batch_date)

        payment = Payment.query.one()
        assert payment.amount == 14  # 2 (booking.quantity) * 7 (Rule.amount)
        assert payment.customReimbursementRule == rule
        assert payment.reimbursementRate is None
    def test_creates_pending_and_not_processable_payments(self):
        # Given
        cutoff = datetime.datetime.now()
        before_cutoff = cutoff - datetime.timedelta(days=1)

        beneficiary = users_factories.BeneficiaryGrant18Factory(
            email="*****@*****.**")
        offerer1 = offers_factories.OffererFactory(siren="123456789")
        offerer2 = offers_factories.OffererFactory(siren="987654321")
        offers_factories.BankInformationFactory(
            bic="BDFEFR2LCCB",
            iban="FR7630006000011234567890189",
            offerer=offerer1)
        venue1 = offers_factories.VenueFactory(managingOfferer=offerer1,
                                               siret="12345678912345")
        venue2 = offers_factories.VenueFactory(managingOfferer=offerer2,
                                               siret="98765432154321")
        offer1 = offers_factories.ThingOfferFactory(venue=venue1)
        offer2 = offers_factories.ThingOfferFactory(venue=venue2)

        paying_stock1 = offers_factories.ThingStockFactory(offer=offer1)
        paying_stock2 = offers_factories.ThingStockFactory(offer=offer2)
        free_stock1 = offers_factories.ThingStockFactory(offer=offer1, price=0)
        bookings_factories.UsedBookingFactory(user=beneficiary,
                                              stock=paying_stock1,
                                              dateUsed=before_cutoff)
        bookings_factories.UsedBookingFactory(user=beneficiary,
                                              stock=paying_stock1,
                                              dateUsed=before_cutoff)
        bookings_factories.UsedBookingFactory(user=beneficiary,
                                              stock=paying_stock2,
                                              dateUsed=before_cutoff)
        bookings_factories.UsedBookingFactory(user=beneficiary,
                                              stock=free_stock1,
                                              dateUsed=before_cutoff)

        # When
        generate_new_payments(cutoff, batch_date=datetime.datetime.now())

        # Then
        assert get_pending_payments().count() == 2
        assert get_not_processable_payments().count() == 1
    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
示例#13
0
    def test_should_set_not_processable_payments_to_retry_and_update_payments_bic_and_iban_using_offerer_information(
        self, make_transaction_label_stub
    ):
        # Given
        offerer = offers_factories.OffererFactory(name="first offerer")
        stock = offers_factories.ThingStockFactory(offer__venue__managingOfferer=offerer)
        booking = bookings_factories.UsedBookingFactory(stock=stock)
        offers_factories.BankInformationFactory(offerer=offerer, iban="FR7611808009101234567890147", bic="CCBPFRPPVER")
        not_processable_payment = payments_factories.PaymentFactory(
            amount=10,
            booking=booking,
            bic="QSDFGH8Z555",
            iban="CF13QSDFGH456789",
            transactionLabel="My old transaction label",
        )
        payments_factories.PaymentStatusFactory(
            payment=not_processable_payment, status=TransactionStatus.NOT_PROCESSABLE
        )

        sent_payment = payments_factories.PaymentFactory(booking=booking, amount=10)
        payments_factories.PaymentStatusFactory(payment=sent_payment, status=TransactionStatus.SENT)

        new_batch_date = datetime.datetime.now()
        new_transaction_label = "My new transaction label"
        make_transaction_label_stub.return_value = new_transaction_label

        # When
        set_not_processable_payments_with_bank_information_to_retry(new_batch_date)

        # Then
        queried_not_processable_payment = Payment.query.filter_by(id=not_processable_payment.id).one()
        queried_sent_payment = Payment.query.filter_by(id=sent_payment.id).one()
        assert queried_not_processable_payment.iban == "FR7611808009101234567890147"
        assert queried_not_processable_payment.bic == "CCBPFRPPVER"
        assert queried_not_processable_payment.batchDate == new_batch_date
        assert queried_not_processable_payment.transactionLabel == new_transaction_label
        assert queried_not_processable_payment.currentStatus.status == TransactionStatus.RETRY
        assert queried_sent_payment.currentStatus.status == TransactionStatus.SENT
    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 == []
示例#15
0
    def when_user_has_rights_on_managing_offerer(self, app):
        # given
        user_offerer = offers_factories.UserOffererFactory(
            user__email="*****@*****.**")
        venue = offers_factories.VenueFactory(
            name="L'encre et la plume", managingOfferer=user_offerer.offerer)
        bank_information = offers_factories.BankInformationFactory(venue=venue)

        expected_serialized_venue = {
            "address":
            venue.address,
            "audioDisabilityCompliant":
            venue.audioDisabilityCompliant,
            "bic":
            bank_information.bic,
            "bookingEmail":
            venue.bookingEmail,
            "city":
            venue.city,
            "contact": {
                "email": venue.contact.email,
                "website": venue.contact.website,
                "phoneNumber": venue.contact.phone_number,
                "socialMedias": venue.contact.social_medias,
            },
            "comment":
            venue.comment,
            "dateCreated":
            format_into_utc_date(venue.dateCreated),
            "dateModifiedAtLastProvider":
            format_into_utc_date(venue.dateModifiedAtLastProvider),
            "demarchesSimplifieesApplicationId":
            str(venue.demarchesSimplifieesApplicationId),
            "departementCode":
            venue.departementCode,
            "description":
            venue.description,
            "fieldsUpdated":
            venue.fieldsUpdated,
            "iban":
            bank_information.iban,
            "id":
            humanize(venue.id),
            "idAtProviders":
            venue.idAtProviders,
            "isValidated":
            venue.isValidated,
            "isVirtual":
            venue.isVirtual,
            "latitude":
            float(venue.latitude),
            "lastProviderId":
            venue.lastProviderId,
            "longitude":
            float(venue.longitude),
            "managingOfferer": {
                "address":
                venue.managingOfferer.address,
                "bic":
                venue.managingOfferer.bic,
                "city":
                venue.managingOfferer.city,
                "dateCreated":
                format_into_utc_date(venue.managingOfferer.dateCreated),
                "dateModifiedAtLastProvider":
                format_into_utc_date(
                    venue.managingOfferer.dateModifiedAtLastProvider),
                "demarchesSimplifieesApplicationId":
                venue.managingOfferer.demarchesSimplifieesApplicationId,
                "fieldsUpdated":
                venue.managingOfferer.fieldsUpdated,
                "iban":
                venue.managingOfferer.iban,
                "id":
                humanize(venue.managingOfferer.id),
                "idAtProviders":
                venue.managingOfferer.idAtProviders,
                "isValidated":
                venue.managingOfferer.isValidated,
                "lastProviderId":
                venue.managingOfferer.lastProviderId,
                "name":
                venue.managingOfferer.name,
                "postalCode":
                venue.managingOfferer.postalCode,
                "siren":
                venue.managingOfferer.siren,
            },
            "managingOffererId":
            humanize(venue.managingOffererId),
            "mentalDisabilityCompliant":
            venue.mentalDisabilityCompliant,
            "motorDisabilityCompliant":
            venue.motorDisabilityCompliant,
            "name":
            venue.name,
            "postalCode":
            venue.postalCode,
            "publicName":
            venue.publicName,
            "siret":
            venue.siret,
            "venueLabelId":
            humanize(venue.venueLabelId),
            "venueTypeId":
            humanize(venue.venueTypeId),
            "visualDisabilityCompliant":
            venue.visualDisabilityCompliant,
            "withdrawalDetails":
            None,
        }

        # when
        auth_request = TestClient(
            app.test_client()).with_session_auth(email=user_offerer.user.email)
        response = auth_request.get("/venues/%s" % humanize(venue.id))

        # then
        assert response.status_code == 200
        assert response.json == expected_serialized_venue
示例#16
0
    def test_returns_an_event_stock(self, app):
        # Given
        now = datetime.utcnow()
        beneficiary = users_factories.BeneficiaryGrant18Factory()
        stock = offers_factories.EventStockFactory(
            dateCreated=now,
            dateModified=now,
            dateModifiedAtLastProvider=now,
            beginningDatetime=now + timedelta(hours=1),
            bookingLimitDatetime=now + timedelta(hours=1),
            offer__dateCreated=now,
            offer__dateModifiedAtLastProvider=now,
            offer__bookingEmail="*****@*****.**",
            offer__name="Derrick",
            offer__description="Tatort, but slower",
            offer__durationMinutes=60,
            offer__mentalDisabilityCompliant=True,
            offer__externalTicketOfficeUrl="http://example.net",
            offer__product__name="Derrick",
            offer__product__description="Tatort, but slower",
            offer__product__durationMinutes=60,
            offer__product__dateModifiedAtLastProvider=now,
            offer__venue__siret="12345678912345",
            offer__venue__name="La petite librairie",
            offer__venue__dateCreated=now,
            offer__venue__dateModifiedAtLastProvider=now,
            offer__venue__bookingEmail="*****@*****.**",
            offer__venue__managingOfferer__dateCreated=now,
            offer__venue__managingOfferer__dateModifiedAtLastProvider=now,
            offer__venue__managingOfferer__siren="123456789",
            offer__venue__managingOfferer__name="Test Offerer",
        )
        offer = stock.offer
        venue = offer.venue
        offerer = venue.managingOfferer
        offers_factories.BankInformationFactory(venue=venue)

        # 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
        assert response.json == {
            "activeMediation":
            None,
            "ageMax":
            None,
            "ageMin":
            None,
            "bookingEmail":
            "*****@*****.**",
            "conditions":
            None,
            "dateCreated":
            "2020-10-15T00:00:00Z",
            "dateModifiedAtLastProvider":
            "2020-10-15T00:00:00Z",
            "dateRange": ["2020-10-15T01:00:00Z", "2020-10-15T01:00:00Z"],
            "description":
            "Tatort, but slower",
            "durationMinutes":
            60,
            "extraData":
            None,
            "externalTicketOfficeUrl":
            "http://example.net",
            "fieldsUpdated": [],
            "hasBookingLimitDatetimesPassed":
            False,
            "id":
            humanize(stock.offer.id),
            "idAtProviders":
            None,
            "isActive":
            True,
            "audioDisabilityCompliant":
            False,
            "mentalDisabilityCompliant":
            True,
            "motorDisabilityCompliant":
            False,
            "visualDisabilityCompliant":
            False,
            "isBookable":
            True,
            "isDigital":
            False,
            "isDuo":
            False,
            "isEducational":
            False,
            "isEditable":
            True,
            "isEvent":
            True,
            "isNational":
            False,
            "isThing":
            False,
            "lastProvider":
            None,
            "lastProviderId":
            None,
            "mediaUrls": [],
            "mediations": [],
            "name":
            "Derrick",
            "nonHumanizedId":
            stock.offer.id,
            "product": {
                "ageMax": None,
                "ageMin": None,
                "conditions": None,
                "dateModifiedAtLastProvider": "2020-10-15T00:00:00Z",
                "description": "Tatort, but slower",
                "durationMinutes": 60,
                "extraData": None,
                "fieldsUpdated": [],
                "id": humanize(stock.offer.product.id),
                "idAtProviders": None,
                "isGcuCompatible": True,
                "isNational": False,
                "lastProviderId": None,
                "mediaUrls": [],
                "name": "Derrick",
                "owningOffererId": None,
                "thumbCount": 0,
                "url": None,
            },
            "productId":
            humanize(stock.offer.product.id),
            "status":
            "ACTIVE",
            "stocks": [{
                "beginningDatetime": "2020-10-15T01:00:00Z",
                "bookingLimitDatetime": "2020-10-15T01:00:00Z",
                "bookingsQuantity": 0,
                "cancellationLimitDate": "2020-10-15T00:00:00Z",
                "dateCreated": "2020-10-15T00:00:00Z",
                "dateModified": "2020-10-15T00:00:00Z",
                "dateModifiedAtLastProvider": "2020-10-15T00:00:00Z",
                "fieldsUpdated": [],
                "hasActivationCode": False,
                "id": humanize(stock.id),
                "idAtProviders": None,
                "isBookable": True,
                "isEventDeletable": True,
                "isEventExpired": False,
                "isSoftDeleted": False,
                "lastProviderId": None,
                "offerId": humanize(stock.offer.id),
                "price": 10.0,
                "quantity": 1000,
                "remainingQuantity": 1000,
            }],
            "subcategoryId":
            "SEANCE_CINE",
            "thumbUrl":
            None,
            "url":
            None,
            "venue": {
                "address": "1 boulevard Poissonnière",
                "audioDisabilityCompliant": False,
                "bookingEmail": "*****@*****.**",
                "city": "Paris",
                "comment": None,
                "dateCreated": "2020-10-15T00:00:00Z",
                "dateModifiedAtLastProvider": "2020-10-15T00:00:00Z",
                "departementCode": "75",
                "fieldsUpdated": [],
                "id": humanize(venue.id),
                "idAtProviders": None,
                "isValidated": True,
                "isVirtual": False,
                "lastProviderId": None,
                "latitude": 48.87004,
                "longitude": 2.37850,
                "managingOfferer": {
                    "address": "1 boulevard Poissonnière",
                    "city": "Paris",
                    "dateCreated": "2020-10-15T00:00:00Z",
                    "dateModifiedAtLastProvider": "2020-10-15T00:00:00Z",
                    "fieldsUpdated": [],
                    "id": humanize(offerer.id),
                    "idAtProviders": None,
                    "isActive": True,
                    "isValidated": True,
                    "lastProviderId": None,
                    "name": "Test Offerer",
                    "postalCode": "75000",
                    "siren": "123456789",
                    "thumbCount": 0,
                },
                "managingOffererId": humanize(offerer.id),
                "mentalDisabilityCompliant": False,
                "motorDisabilityCompliant": False,
                "name": "La petite librairie",
                "postalCode": "75000",
                "publicName": "La petite librairie",
                "siret": "12345678912345",
                "thumbCount": 0,
                "venueLabelId": None,
                "venueTypeId": None,
                "visualDisabilityCompliant": False,
            },
            "venueId":
            humanize(venue.id),
            "withdrawalDetails":
            None,
        }
示例#17
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
示例#18
0
    def test_when_user_has_rights_on_offerer(self, app):
        pro = users_factories.ProFactory()
        offerer = offers_factories.OffererFactory()
        offers_factories.UserOffererFactory(user=pro, offerer=offerer)
        venue_1 = offers_factories.VenueFactory(
            managingOfferer=offerer,
            withdrawalDetails="Venue withdrawal details")
        offers_factories.OfferFactory(venue=venue_1)
        venue_2 = offers_factories.VenueFactory(
            managingOfferer=offerer,
            withdrawalDetails="Other venue withdrawal details")
        offers_factories.VenueFactory(
            managingOfferer=offerer,
            withdrawalDetails="More venue withdrawal details")
        ApiKeyFactory(offerer=offerer, prefix="testenv_prefix")
        ApiKeyFactory(offerer=offerer, prefix="testenv_prefix2")
        offers_factories.BankInformationFactory(venue=venue_1,
                                                applicationId=2,
                                                status="REJECTED")
        offers_factories.BankInformationFactory(venue=venue_1, applicationId=3)
        offers_factories.BankInformationFactory(venue=venue_2, applicationId=4)

        client = TestClient(app.test_client()).with_session_auth(pro.email)
        n_queries = (
            testing.AUTHENTICATION_QUERIES +
            1  # check_user_has_access_to_offerer
            + 1  # Offerer api_key prefix
            + 1  # Offerer hasDigitalVenueAtLeastOneOffer
            + 1  # Offerer BankInformation
            + 1  # Offerer hasMissingBankInformation
        )
        with testing.assert_num_queries(n_queries):
            response = client.get(f"/offerers/{humanize(offerer.id)}")

        expected_serialized_offerer = {
            "address":
            offerer.address,
            "apiKey": {
                "maxAllowed": 5,
                "prefixes": ["testenv_prefix", "testenv_prefix2"]
            },
            "bic":
            None,
            "iban":
            None,
            "city":
            offerer.city,
            "dateCreated":
            format_into_utc_date(offerer.dateCreated),
            "dateModifiedAtLastProvider":
            format_into_utc_date(offerer.dateModifiedAtLastProvider),
            "demarchesSimplifieesApplicationId":
            None,
            "hasDigitalVenueAtLeastOneOffer":
            False,
            "fieldsUpdated":
            offerer.fieldsUpdated,
            "hasMissingBankInformation":
            True,
            "id":
            humanize(offerer.id),
            "idAtProviders":
            offerer.idAtProviders,
            "isValidated":
            offerer.isValidated,
            "lastProviderId":
            offerer.lastProviderId,
            "managedVenues": [{
                "audioDisabilityCompliant":
                False,
                "address":
                offererVenue.address,
                "bookingEmail":
                offererVenue.bookingEmail,
                "city":
                offererVenue.city,
                "comment":
                offererVenue.comment,
                "departementCode":
                offererVenue.departementCode,
                "id":
                humanize(offererVenue.id),
                "isValidated":
                offererVenue.isValidated,
                "isVirtual":
                offererVenue.isVirtual,
                "managingOffererId":
                humanize(offererVenue.managingOffererId),
                "mentalDisabilityCompliant":
                False,
                "motorDisabilityCompliant":
                False,
                "name":
                offererVenue.name,
                "postalCode":
                offererVenue.postalCode,
                "publicName":
                offererVenue.publicName,
                "venueLabelId":
                humanize(offererVenue.venueLabelId),
                "venueTypeId":
                humanize(offererVenue.venueTypeId),
                "visualDisabilityCompliant":
                False,
                "withdrawalDetails":
                offererVenue.withdrawalDetails,
            } for offererVenue in offerer.managedVenues],
            "name":
            offerer.name,
            "postalCode":
            offerer.postalCode,
            "siren":
            offerer.siren,
        }
        assert response.status_code == 200
        assert response.json == expected_serialized_offerer