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
def create_industrial_payments():
    logger.info("create_industrial_payments")

    cutoff_date = datetime.datetime.utcnow()
    batch_date = cutoff_date
    generate_new_payments(cutoff_date, batch_date)

    logger.info("created payments")
    def test_records_new_payment_lines_in_database(self):
        # Given
        cutoff = datetime.datetime.now()
        before_cutoff = cutoff - datetime.timedelta(days=1)

        beneficiary = users_factories.BeneficiaryGrant18Factory(
            email="*****@*****.**")
        offerer = offers_factories.OffererFactory()
        offer = offers_factories.ThingOfferFactory(
            venue__managingOfferer=offerer)
        paying_stock = offers_factories.ThingStockFactory(offer=offer)
        free_stock = offers_factories.ThingStockFactory(offer=offer, price=0)
        bookings_factories.UsedBookingFactory(user=beneficiary,
                                              stock=paying_stock,
                                              dateUsed=before_cutoff)
        bookings_factories.UsedBookingFactory(user=beneficiary,
                                              stock=paying_stock,
                                              dateUsed=before_cutoff)
        bookings_factories.UsedBookingFactory(user=beneficiary,
                                              stock=free_stock,
                                              dateUsed=before_cutoff)
        bookings_factories.UsedBookingFactory(user=beneficiary,
                                              stock=free_stock,
                                              dateUsed=before_cutoff)
        bookings_factories.UsedBookingFactory(user=beneficiary,
                                              stock=paying_stock,
                                              dateUsed=cutoff)

        payment_message = payments_factories.PaymentMessageFactory(
            name="ABCD123")
        payments_factories.PaymentFactory(paymentMessage=payment_message)

        initial_payment_count = Payment.query.count()

        # When
        n_queries = 1  # get_venue_ids_to_reimburse()
        n_queries += 1  # fetch custom reimbursement rules
        n_queries += 1  # find_bookings_eligible_for_payment_for_venue()
        n_queries += 1  # insert payments
        n_queries += 1  # release savepoint (commit)
        n_queries += 1  # insert PENDING payment statuses
        n_queries += 1  # release savepoint (commit)
        n_queries += 1  # insert NOT_PROCESSABLE payment statuses
        n_queries += 1  # release savepoint (commit)
        with assert_num_queries(n_queries):
            generate_new_payments(cutoff, batch_date=datetime.datetime.now())

        # Then
        assert Payment.query.count() - initial_payment_count == 2
Пример #4
0
def generate_payments(cutoff_date: datetime.datetime, batch_date: datetime.datetime):
    logger.info("[BATCH][PAYMENTS] STEP 1 : generate payments")
    generate_new_payments(cutoff_date, batch_date)

    logger.info("[BATCH][PAYMENTS] STEP 2 : set NOT_PROCESSABLE payments to RETRY")
    set_not_processable_payments_with_bank_information_to_retry(batch_date)

    logger.info("[BATCH][PAYMENTS] STEP 2 Bis : include payments in ERROR and RETRY statuses")
    include_error_and_retry_payments_in_batch(batch_date)

    by_status = payment_queries.get_payment_count_by_status(batch_date)
    total = sum(count for count in by_status.values())
    logger.info("[BATCH][PAYMENTS] %i payments in status ERROR to send", by_status.get("ERROR", 0))
    logger.info("[BATCH][PAYMENTS] %i payments in status RETRY to send", by_status.get("RETRY", 0))
    logger.info("[BATCH][PAYMENTS] %i payments in total to send", total)
    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")
Пример #6
0
def create_industrial_payments():
    logger.info("create_industrial_payments")

    pending_payments, not_processable_payments = generate_new_payments()

    logger.info("created %d payments",
                len(pending_payments + not_processable_payments))
Пример #7
0
        def when_user_has_an_offerer_attached(self, app):
            # Given
            user = create_user(email="*****@*****.**")
            deposit = create_deposit(user, amount=500, source="public")
            offerer1 = create_offerer()
            offerer2 = create_offerer(siren="123456788")
            user_offerer1 = create_user_offerer(user, offerer1, validation_token=None)
            user_offerer2 = create_user_offerer(user, offerer2, validation_token=None)
            venue1 = create_venue(offerer1)
            venue2 = create_venue(offerer1, siret="12345678912346")
            venue3 = create_venue(offerer2, siret="12345678912347")
            bank_information1 = create_bank_information(application_id=1, venue=venue1)
            bank_information2 = create_bank_information(application_id=7, venue=venue2)
            stock1 = create_stock_with_thing_offer(offerer=offerer1, venue=venue1, price=10)
            stock2 = create_stock_with_thing_offer(offerer=offerer1, venue=venue2, price=11)
            stock3 = create_stock_with_thing_offer(offerer=offerer2, venue=venue3, price=12)
            stock4 = create_stock_with_thing_offer(offerer=offerer2, venue=venue3, price=13)
            booking1 = create_booking(user=user, stock=stock1, is_used=True, token="ABCDEF", venue=venue1)
            booking2 = create_booking(user=user, stock=stock1, token="ABCDEG", venue=venue1)
            booking3 = create_booking(user=user, stock=stock2, is_used=True, token="ABCDEH", venue=venue2)
            booking4 = create_booking(user=user, stock=stock3, is_used=True, token="ABCDEI", venue=venue3)
            booking5 = create_booking(user=user, stock=stock4, is_used=True, token="ABCDEJ", venue=venue3)
            booking6 = create_booking(user=user, stock=stock4, is_used=True, token="ABCDEK", venue=venue3)
            repository.save(
                deposit,
                booking1,
                booking2,
                booking3,
                booking4,
                booking5,
                booking6,
                user_offerer1,
                user_offerer2,
                bank_information1,
                bank_information2,
            )
            generate_new_payments()

            # When
            response = TestClient(app.test_client()).with_auth(user.email).get("/reimbursements/csv")
            response_lines = response.data.decode("utf-8").split("\n")

            # Then
            assert response.status_code == 200
            assert response.headers["Content-type"] == "text/csv; charset=utf-8;"
            assert response.headers["Content-Disposition"] == "attachment; filename=remboursements_pass_culture.csv"
            assert len(response_lines) == 7
    def test_find_all_offerer_reimbursement_details(self, app):
        # Given
        user = users_factories.UserFactory(email="*****@*****.**")
        offerer1 = create_offerer(siren="123456789")
        user_offerer1 = create_user_offerer(user,
                                            offerer1,
                                            validation_token=None)
        venue1 = create_venue(offerer1)
        venue2 = create_venue(offerer1, siret="12345678912346")
        bank_information1 = create_bank_information(application_id=1,
                                                    venue=venue1)
        bank_information2 = create_bank_information(application_id=2,
                                                    venue=venue2)
        create_offer_with_thing_product(
            venue1,
            url="https://host/path/{token}?offerId={offerId}&email={email}")
        create_offer_with_thing_product(venue2)
        stock1 = create_stock_with_thing_offer(offerer=offerer1,
                                               venue=venue1,
                                               price=10)
        stock2 = create_stock_with_thing_offer(offerer=offerer1,
                                               venue=venue2,
                                               price=11)
        booking1 = create_booking(user=user,
                                  stock=stock1,
                                  is_used=True,
                                  token="ABCDEF",
                                  venue=venue1)
        booking2 = create_booking(user=user,
                                  stock=stock1,
                                  token="ABCDEG",
                                  venue=venue1)
        booking3 = create_booking(user=user,
                                  stock=stock2,
                                  is_used=True,
                                  token="ABCDEH",
                                  venue=venue2)
        repository.save(booking1, booking2, booking3, user_offerer1,
                        bank_information1, bank_information2)
        generate_new_payments()

        # When
        reimbursement_details = find_all_offerer_reimbursement_details(
            offerer1.id)

        # Then
        assert len(reimbursement_details) == 2
    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
Пример #11
0
        def test_records_new_payment_lines_in_database(self, app):
            # Given
            offerer = create_offerer()
            venue = create_venue(offerer)
            offer = create_offer_with_thing_product(venue)
            paying_stock = create_stock_from_offer(offer)
            free_stock = create_stock_from_offer(offer, price=0)
            user = create_user()
            deposit = create_deposit(user, amount=500)
            booking1 = create_booking(user=user,
                                      stock=paying_stock,
                                      venue=venue,
                                      is_used=True)
            booking2 = create_booking(user=user,
                                      stock=paying_stock,
                                      venue=venue,
                                      is_used=True)
            booking3 = create_booking(user=user,
                                      stock=paying_stock,
                                      venue=venue,
                                      is_used=True)
            booking4 = create_booking(user=user,
                                      stock=free_stock,
                                      venue=venue,
                                      is_used=True)
            payment1 = create_payment(booking2,
                                      offerer,
                                      10,
                                      payment_message_name="ABCD123")

            repository.save(payment1)
            repository.save(deposit, booking1, booking3, booking4)

            initial_payment_count = Payment.query.count()

            # When
            generate_new_payments()

            # Then
            assert Payment.query.count() - initial_payment_count == 2
    def test_generate_payment_details_csv_with_right_values(self, app):
        # given
        user = users_factories.UserFactory(firstName="John", lastName="Doe")
        offerer1 = create_offerer(siren="123456789",
                                  address="123 rue de Paris")
        user_offerer1 = create_user_offerer(user,
                                            offerer1,
                                            validation_token=None)
        venue1 = create_venue(offerer1)
        bank_information1 = create_bank_information(venue=venue1)
        stock1 = create_stock_with_thing_offer(offerer=offerer1,
                                               venue=venue1,
                                               price=10)
        booking1 = create_booking(user=user,
                                  stock=stock1,
                                  is_used=True,
                                  token="ABCDEF",
                                  venue=venue1)
        booking2 = create_booking(user=user,
                                  stock=stock1,
                                  token="ABCDEG",
                                  venue=venue1)

        repository.save(booking1, booking2, user_offerer1, bank_information1)

        generate_new_payments()

        reimbursement_details = find_all_offerer_reimbursement_details(
            offerer1.id)

        # when
        csv = generate_reimbursement_details_csv(reimbursement_details)

        # then
        assert _count_non_empty_lines(csv) == 2
        assert (
            _get_header(csv, 1) ==
            "2019;Juillet : remboursement 1ère quinzaine;La petite librairie;12345678912345;123 rue de Paris;FR7630006000011234567890189;La petite librairie;Test Book;Doe;John;ABCDEF;;10.00;Remboursement initié"
        )
Пример #13
0
        def test_reimburses_95_percent_for_book_product_when_bookings_exceed_100000_euros(
                self, app):
            # Given
            offerer1 = create_offerer(siren="123456789")
            repository.save(offerer1)
            bank_information = create_bank_information(
                bic="BDFEFR2LCCB",
                iban="FR7630006000011234567890189",
                offerer=offerer1)
            venue1 = create_venue(offerer1, siret="12345678912345")
            venue2 = create_venue(offerer1, siret="98765432154321")
            venue3 = create_venue(offerer1, siret="98123432154321")
            offer1 = create_offer_with_thing_product(
                venue1, thing_type=ThingType.LIVRE_EDITION, url=None)
            offer2 = create_offer_with_thing_product(
                venue2, thing_type=ThingType.LIVRE_EDITION, url=None)
            offer3 = create_offer_with_thing_product(
                venue3, thing_type=ThingType.LIVRE_EDITION, url=None)
            paying_stock1 = create_stock_from_offer(offer1, price=10000)
            paying_stock2 = create_stock_from_offer(offer2, price=10000)
            paying_stock3 = create_stock_from_offer(offer3, price=100000)
            user = create_user()
            deposit = create_deposit(user, amount=120000)
            booking1 = create_booking(user=user,
                                      stock=paying_stock1,
                                      venue=venue1,
                                      is_used=True,
                                      quantity=1)
            booking2 = create_booking(user=user,
                                      stock=paying_stock2,
                                      venue=venue2,
                                      is_used=True,
                                      quantity=1)
            booking3 = create_booking(user=user,
                                      stock=paying_stock3,
                                      venue=venue3,
                                      is_used=True,
                                      quantity=1)
            repository.save(deposit, booking1, booking2, booking3,
                            bank_information)

            # When
            pending, not_processable = generate_new_payments()

            # Then
            assert len(pending) == 3
            assert len(not_processable) == 0
            assert sum(p.amount for p in pending) == 115000
Пример #14
0
        def test_reimburses_offerer_if_he_has_more_than_20000_euros_in_bookings_on_several_venues(
                self, app):
            # Given
            offerer1 = create_offerer(siren="123456789")
            repository.save(offerer1)
            bank_information = create_bank_information(
                bic="BDFEFR2LCCB",
                iban="FR7630006000011234567890189",
                offerer=offerer1)
            venue1 = create_venue(offerer1, siret="12345678912345")
            venue2 = create_venue(offerer1, siret="98765432154321")
            venue3 = create_venue(offerer1, siret="98123432154321")
            offer1 = create_offer_with_thing_product(venue1)
            offer2 = create_offer_with_thing_product(venue2)
            offer3 = create_offer_with_thing_product(venue3)
            paying_stock1 = create_stock_from_offer(offer1, price=10000)
            paying_stock2 = create_stock_from_offer(offer2, price=10000)
            paying_stock3 = create_stock_from_offer(offer3, price=10000)
            user = create_user()
            deposit = create_deposit(user, amount=50000)
            booking1 = create_booking(user=user,
                                      stock=paying_stock1,
                                      venue=venue1,
                                      is_used=True,
                                      quantity=1)
            booking2 = create_booking(user=user,
                                      stock=paying_stock2,
                                      venue=venue2,
                                      is_used=True,
                                      quantity=1)
            booking3 = create_booking(user=user,
                                      stock=paying_stock3,
                                      venue=venue3,
                                      is_used=True,
                                      quantity=1)
            repository.save(deposit, booking1, booking2, booking3,
                            bank_information)

            # When
            pending, not_processable = generate_new_payments()

            # Then
            assert len(pending) == 3
            assert len(not_processable) == 0
            assert sum(p.amount for p in pending) == 30000
Пример #15
0
        def test_returns_a_tuple_of_pending_and_not_processable_payments(
                self, app):
            # Given
            offerer1 = create_offerer(siren="123456789")
            offerer2 = create_offerer(siren="987654321")
            repository.save(offerer1)
            bank_information = create_bank_information(
                bic="BDFEFR2LCCB",
                iban="FR7630006000011234567890189",
                offerer=offerer1)
            venue1 = create_venue(offerer1, siret="12345678912345")
            venue2 = create_venue(offerer2, siret="98765432154321")
            offer1 = create_offer_with_thing_product(venue1)
            offer2 = create_offer_with_thing_product(venue2)
            paying_stock1 = create_stock_from_offer(offer1)
            paying_stock2 = create_stock_from_offer(offer2)
            free_stock1 = create_stock_from_offer(offer1, price=0)
            user = create_user()
            deposit = create_deposit(user, amount=500)
            booking1 = create_booking(user=user,
                                      stock=paying_stock1,
                                      venue=venue1,
                                      is_used=True)
            booking2 = create_booking(user=user,
                                      stock=paying_stock1,
                                      venue=venue1,
                                      is_used=True)
            booking3 = create_booking(user=user,
                                      stock=paying_stock2,
                                      venue=venue2,
                                      is_used=True)
            booking4 = create_booking(user=user,
                                      stock=free_stock1,
                                      venue=venue1,
                                      is_used=True)
            repository.save(deposit, booking1, booking2, booking3, booking4,
                            bank_information)

            # When
            pending, not_processable = generate_new_payments()

            # Then
            assert len(pending) == 2
            assert len(not_processable) == 1
Пример #16
0
def generate_or_collect_payments(
        payment_message_id: str = None) -> Tuple[List[Payment], List[Payment]]:
    if payment_message_id is None:
        logger.info("[BATCH][PAYMENTS] STEP 1 : generate payments")
        pending_payments, not_processable_payments = generate_new_payments()

        logger.info(
            "[BATCH][PAYMENTS] STEP 2 : set NOT_PROCESSABLE payments to RETRY")
        set_not_processable_payments_with_bank_information_to_retry()

        logger.info(
            "[BATCH][PAYMENTS] STEP 2 Bis : collect payments in ERROR and RETRY statuses"
        )
        payments_to_send = concatenate_payments_with_errors_and_retries(
            pending_payments)
    else:
        logger.info(
            "[BATCH][PAYMENTS] STEP 1 Bis : collect payments corresponding to payment_message_id"
        )
        not_processable_payments = []
        payments_to_send = get_payments_by_message_id(payment_message_id)
    return not_processable_payments, payments_to_send
    def test_full_reimburses_book_product_when_bookings_are_below_20000_euros(
            self, app):
        # Given
        offerer1 = create_offerer(siren="123456789")
        repository.save(offerer1)
        bank_information = create_bank_information(
            bic="BDFEFR2LCCB",
            iban="FR7630006000011234567890189",
            offerer=offerer1)
        venue1 = create_venue(offerer1, siret="12345678912345")
        venue2 = create_venue(offerer1, siret="98765432154321")
        offer1 = create_offer_with_thing_product(
            venue1, thing_type=ThingType.LIVRE_EDITION, url=None)
        offer2 = create_offer_with_thing_product(
            venue2, thing_type=ThingType.LIVRE_EDITION, url=None)
        paying_stock1 = create_stock_from_offer(offer1, price=10000)
        paying_stock2 = create_stock_from_offer(offer2, price=19990)
        user = users_factories.UserFactory()
        user.deposit.amount = 50000
        repository.save(user.deposit)
        booking1 = create_booking(user=user,
                                  stock=paying_stock1,
                                  venue=venue1,
                                  is_used=True,
                                  quantity=1)
        booking2 = create_booking(user=user,
                                  stock=paying_stock2,
                                  venue=venue2,
                                  is_used=True,
                                  quantity=1)
        repository.save(booking1, booking2, bank_information)

        # When
        pending, not_processable = generate_new_payments()

        # Then
        assert len(pending) == 2
        assert len(not_processable) == 0
        assert sum(p.amount for p in pending) == 29990