def test_send_payments_report_sends_two_csv_attachments_if_some_payments_are_not_processable_and_in_error( app): # given iban = "CF13QSDFGH456789" bic = "QSDFGH8Z555" payment1 = payments_factories.PaymentFactory(iban=iban, bic=bic, statuses=[]) payments_factories.PaymentStatusFactory(payment=payment1, status=TransactionStatus.SENT) payment2 = payments_factories.PaymentFactory(iban=iban, bic=bic, statuses=[]) payments_factories.PaymentStatusFactory(payment=payment2, status=TransactionStatus.ERROR) payment3 = payments_factories.PaymentFactory(iban=iban, bic=bic, statuses=[]) payments_factories.PaymentStatusFactory( payment=payment3, status=TransactionStatus.NOT_PROCESSABLE) payments = [payment1, payment2, payment3] # when send_payments_report(payments, ["*****@*****.**"]) # then assert len(mails_testing.outbox) == 1 assert len(mails_testing.outbox[0].sent_data["Attachments"]) == 2 assert mails_testing.outbox[0].sent_data["Attachments"][0][ "ContentType"] == "text/csv" assert mails_testing.outbox[0].sent_data["Attachments"][1][ "ContentType"] == "text/csv"
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_send_payments_report_sends_two_csv_attachments_if_no_payments_are_in_error_or_sent( app): # given iban = "CF13QSDFGH456789" bic = "QSDFGH8Z555" payment1 = payments_factories.PaymentFactory(iban=iban, bic=bic, statuses=[]) payment2 = payments_factories.PaymentFactory(iban=iban, bic=bic, statuses=[]) for payment in (payment1, payment2): payments_factories.PaymentStatusFactory(payment=payment, status=TransactionStatus.SENT) payments = [payment1, payment2] # when send_payments_report(payments, ["*****@*****.**"]) # then assert len(mails_testing.outbox) == 1 assert len(mails_testing.outbox[0].sent_data["Attachments"]) == 2 assert mails_testing.outbox[0].sent_data["Attachments"][0][ "ContentType"] == "text/csv" assert mails_testing.outbox[0].sent_data["Attachments"][1][ "ContentType"] == "text/csv"
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_without_batch_date(self): p1 = factories.PaymentFactory() p2 = factories.PaymentFactory() query = payment_queries.get_payments_by_status([TransactionStatus.PENDING]) assert set(query.all()) == {p1, p2} factories.PaymentStatusFactory(status=TransactionStatus.NOT_PROCESSABLE, payment=p2) query = payment_queries.get_payments_by_status([TransactionStatus.PENDING]) assert query.all() == [p1] query = payment_queries.get_payments_by_status([TransactionStatus.NOT_PROCESSABLE]) assert query.all() == [p2]
def test_without_detail(self): p1 = payments_factories.PaymentFactory(statuses=[]) p2 = payments_factories.PaymentFactory(statuses=[]) _ignored = payments_factories.PaymentFactory(statuses=[]) query = Payment.query.filter(Payment.id.in_((p1.id, p2.id))) api.bulk_create_payment_statuses(query, TransactionStatus.PENDING) statuses = PaymentStatus.query.all() assert len(statuses) == 2 assert {s.payment for s in statuses} == {p1, p2} assert {s.status for s in statuses} == {TransactionStatus.PENDING} assert {s.detail for s in statuses} == {None}
def test_send_transactions_should_send_an_email_with_xml_attachment(app): # given iban = "CF13QSDFGH456789" bic = "AZERTY9Q666" payment1 = payments_factories.PaymentFactory(iban=iban, bic=bic) payment2 = payments_factories.PaymentFactory(iban=iban, bic=bic) payment3 = payments_factories.PaymentFactory(iban=iban, bic=bic) payments = [payment1, payment2, payment3] # when send_transactions(payments, iban, bic, "0000", ["*****@*****.**"]) # then assert len(mails_testing.outbox) == 1 assert len(mails_testing.outbox[0].sent_data["Attachments"]) == 1
def test_send_transactions_should_send_an_email_with_xml_and_csv_attachments(): # given iban = "CF13QSDFGH456789" bic = "AZERTY9Q666" batch_date = datetime.datetime.now() payments_factories.PaymentFactory(iban=iban, bic=bic, batchDate=batch_date) payments_factories.PaymentFactory(iban=iban, bic=bic, batchDate=batch_date) payments_factories.PaymentFactory(iban=iban, bic=bic, batchDate=batch_date) # when send_transactions(Payment.query, batch_date, iban, bic, "0000", ["*****@*****.**"]) # then assert len(mails_testing.outbox) == 1 assert len(mails_testing.outbox[0].sent_data["Attachments"]) == 2
def test_send_transactions_should_not_send_an_email_if_pass_culture_id_is_missing(): # given iban = "CF13QSDFGH456789" bic = "AZERTY9Q666" batch_date = datetime.datetime.now() payments_factories.PaymentFactory(iban=iban, bic=bic) payments_factories.PaymentFactory(iban=iban, bic=bic) payments_factories.PaymentFactory(iban=iban, bic=bic) # when with pytest.raises(Exception): send_transactions(Payment.query, batch_date, iban, bic, None, ["*****@*****.**"]) # then assert not mails_testing.outbox
def test_send_transactions_creates_a_new_payment_transaction_if_email_was_sent_properly(): # given iban = "CF13QSDFGH456789" bic = "AZERTY9Q666" batch_date = datetime.datetime.now() payments_factories.PaymentFactory(iban=iban, bic=bic, batchDate=batch_date) payments_factories.PaymentFactory(iban=iban, bic=bic, batchDate=batch_date) payments_factories.PaymentFactory(iban=iban, bic=bic, batchDate=batch_date) # when send_transactions(Payment.query, batch_date, "BD12AZERTY123456", "AZERTY9Q666", "0000", ["*****@*****.**"]) # then payment_messages = {p.paymentMessage for p in Payment.query.all()} assert len(payment_messages) == 1 assert payment_messages != {None}
def test_send_transactions_should_not_send_an_email_if_pass_culture_bic_is_missing( app): # given iban = "CF13QSDFGH456789" bic = "AZERTY9Q666" payment1 = payments_factories.PaymentFactory(iban=iban, bic=bic) payment2 = payments_factories.PaymentFactory(iban=iban, bic=bic) payment3 = payments_factories.PaymentFactory(iban=iban, bic=bic) payments = [payment1, payment2, payment3] # when with pytest.raises(Exception): send_transactions(payments, iban, None, "0000", ["*****@*****.**"]) # then assert not mails_testing.outbox
def test_should_return_one_payment_info_with_sent_status_when_offer_educational( self, app): # Given now = datetime.utcnow() educational_booking = bookings_factories.UsedEducationalBookingFactory( educationalBooking__educationalRedactor__firstName="Dominique", educationalBooking__educationalRedactor__lastName="Leprof", dateUsed=now, token="ABCDEF", quantity=5, amount=50, stock__price=10, ) payment = payments_factories.PaymentFactory( amount=50, reimbursementRate=1, booking=educational_booking, iban="CF13QSDFGH456789", transactionLabel= "pass Culture Pro - remboursement 1ère quinzaine 07-2019", ) payments_factories.PaymentStatusFactory(payment=payment, status=TransactionStatus.ERROR, detail="Iban non fourni") payments_factories.PaymentStatusFactory(payment=payment, status=TransactionStatus.RETRY, detail="All good") payments_factories.PaymentStatusFactory(payment=payment, status=TransactionStatus.SENT, detail="All good") # When payments = find_all_offerer_payments( educational_booking.stock.offer.venue.managingOfferer.id, reimbursement_period) # Then assert len(payments) == 1 assert payments[0] == ( None, None, "Dominique", "Leprof", "ABCDEF", now, educational_booking.quantity, educational_booking.amount, educational_booking.stock.offer.name, educational_booking.stock.offer.venue.managingOfferer.address, educational_booking.stock.offer.venue.name, educational_booking.stock.offer.venue.siret, educational_booking.stock.offer.venue.address, Decimal("50.00"), Decimal("1.00"), "CF13QSDFGH456789", "pass Culture Pro - remboursement 1ère quinzaine 07-2019", TransactionStatus.SENT, "All good", )
def test_with_user_linked_to_offerers(app): offerer1 = offers_factories.OffererFactory() offerer2 = offers_factories.OffererFactory(siren="123456788") venue1 = offers_factories.VenueFactory(managingOfferer=offerer1) venue2 = offers_factories.VenueFactory(managingOfferer=offerer1) venue3 = offers_factories.VenueFactory(managingOfferer=offerer1) venue4 = offers_factories.VenueFactory(managingOfferer=offerer2) for venue in (venue1, venue2, venue3, venue4): payments_factories.PaymentFactory( booking__stock__offer__venue=venue, transactionLabel= "pass Culture Pro - remboursement 1ère quinzaine 06-21") pro = users_factories.ProFactory(offerers=[offerer1, offerer2]) # When client = TestClient(app.test_client()).with_session_auth(pro.email) response = client.get("/reimbursements/csv") # 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" rows = response.data.decode("utf-8").splitlines() assert len(rows) == 1 + 4 # header + payments
def test_send_transactions_set_status_to_under_review_even_on_email_error(): # given iban = "CF13QSDFGH456789" bic = "AZERTY9Q666" batch_date = datetime.datetime.now() payments_factories.PaymentFactory(iban=iban, bic=bic, batchDate=batch_date) payments_factories.PaymentFactory(iban=iban, bic=bic, batchDate=batch_date) # when send_transactions(Payment.query, batch_date, iban, bic, "0000", ["*****@*****.**"]) # then payments = Payment.query.all() for payment in payments: assert len(payment.statuses) == 2 assert payment.currentStatus.status == TransactionStatus.UNDER_REVIEW
def test_should_raises_resource_gone_error_if_payement_exists(self, app): booking = payments_factories.PaymentFactory().booking with pytest.raises(api_errors.ResourceGoneError) as exc: validation.check_can_be_mark_as_unused(booking) assert exc.value.errors["payment"] == [ "Le remboursement est en cours de traitement" ]
def test_raise_if_has_payment(self): booking = booking_factories.UsedIndividualBookingFactory() payments_factories.PaymentFactory(booking=booking) with pytest.raises(api_errors.ResourceGoneError): api.mark_as_unused(booking) assert booking.isUsed # unchanged assert booking.status is BookingStatus.USED
def should_raises_forbidden_error_if_payement_exists(self, app): booking = factories.UsedIndividualBookingFactory() payments_factories.PaymentFactory(booking=booking) with pytest.raises(api_errors.ForbiddenError) as exc: validation.check_is_usable(booking) assert exc.value.errors["payment"] == [ "Cette réservation a été remboursée" ]
def test_send_transactions_set_status_to_sent_if_email_was_sent_properly(app): # given iban = "CF13QSDFGH456789" bic = "AZERTY9Q666" payment1 = payments_factories.PaymentFactory(iban=iban, bic=bic) payment2 = payments_factories.PaymentFactory(iban=iban, bic=bic) payment3 = payments_factories.PaymentFactory(iban=iban, bic=bic) payments = [payment1, payment2, payment3] # when send_transactions(payments, iban, bic, "0000", ["*****@*****.**"]) # then updated_payments = Payment.query.all() for payment in updated_payments: assert len(payment.statuses) == 2 assert payment.currentStatus.status == TransactionStatus.SENT
def should_return_ko_if_at_least_one_booking_has_payments(self): # Given booking = payment_factories.PaymentFactory().booking # When soft_delete_stock(booking.stock.id) # Then assert not booking.stock.isSoftDeleted
def test_send_transactions_set_status_to_error_with_details_if_email_was_not_sent_properly( app): # given iban = "CF13QSDFGH456789" bic = "AZERTY9Q666" payment1 = payments_factories.PaymentFactory(iban=iban, bic=bic) payment2 = payments_factories.PaymentFactory(iban=iban, bic=bic) payments = [payment1, payment2] # when send_transactions(payments, iban, bic, "0000", ["*****@*****.**"]) # then updated_payments = Payment.query.all() for payment in updated_payments: assert len(payment.statuses) == 2 assert payment.currentStatus.status == TransactionStatus.ERROR assert payment.currentStatus.detail == "Erreur d'envoi à MailJet"
def test_send_transactions_creates_a_new_payment_transaction_if_email_was_sent_properly( app): # given iban = "CF13QSDFGH456789" bic = "AZERTY9Q666" payment1 = payments_factories.PaymentFactory(iban=iban, bic=bic) payment2 = payments_factories.PaymentFactory(iban=iban, bic=bic) payment3 = payments_factories.PaymentFactory(iban=iban, bic=bic) payments = [payment1, payment2, payment3] # when send_transactions(payments, "BD12AZERTY123456", "AZERTY9Q666", "0000", ["*****@*****.**"]) # then payment_messages = {p.paymentMessage for p in Payment.query.all()} assert len(payment_messages) == 1 assert payment_messages != {None}
def should_return_ko_if_at_least_one_booking_has_payments(self, app): # Given booking = bookings_factories.BookingFactory(isUsed=True) payment = payment_factories.PaymentFactory(booking=booking) # When soft_delete_stock(payment.booking.stock.id) # Then assert not booking.stock.isSoftDeleted
def test_group_by_venue(): venue1 = offers_factories.VenueFactory( name="Venue 1", siret="siret1", managingOfferer__name="Offerer 1", managingOfferer__siren="siren1", ) factories.PaymentFactory( booking__stock__offer__venue=venue1, author="", iban="iban1", bic="bic1", amount=10, ) venue2 = offers_factories.VenueFactory( name="Venue 2", siret="siret2", managingOfferer__name="Offerer 2", managingOfferer__siren="siren2", ) factories.PaymentFactory( booking__stock__offer__venue=venue2, author="", iban="iban2", bic="bic2", amount=20, ) factories.PaymentFactory( booking__stock__offer__venue=venue2, author="", iban="iban2", bic="bic2", amount=40, ) factories.PaymentFactory(author="ignored", iban="ignored", bic="ignored") query = Payment.query.filter_by(author="") pairs = payment_queries.group_by_venue(query) assert pairs == [ (venue1.id, "Venue 1", "siret1", "Offerer 1", "siren1", "iban1", "bic1", 10), (venue2.id, "Venue 2", "siret2", "Offerer 2", "siren2", "iban2", "bic2", 60), ]
def test_with_specific_batch_date(self): batch_date = datetime.datetime.utcnow() query = payment_queries.get_payments_by_status([TransactionStatus.NOT_PROCESSABLE], batch_date) factories.PaymentFactory() # not the same batch date assert query.count() == 0 ps = factories.PaymentStatusFactory(status=TransactionStatus.PENDING, payment__batchDate=batch_date) assert query.count() == 0 factories.PaymentStatusFactory(status=TransactionStatus.NOT_PROCESSABLE, payment=ps.payment) assert query.all() == [ps.payment]
def test_when_booking_is_refunded(self, client): # Given booking = payments_factories.PaymentFactory().booking pro_user = offers_factories.UserOffererFactory(offerer=booking.offerer).user # When url = f"/v2/bookings/token/{booking.token}" response = client.with_basic_auth(pro_user.email).get(url) # Then assert response.status_code == 403 assert response.json["payment"] == ["Cette réservation a été remboursée"]
def test_mark_payments_as_sent(self, app, db_session): # Given payment1 = payment_factories.PaymentFactory(statuses=[], transactionLabel="transaction_label") payment2 = payment_factories.PaymentFactory(statuses=[], transactionLabel="transaction_label") payment3 = payment_factories.PaymentFactory(statuses=[], transactionLabel="transaction_label") payment4 = payment_factories.PaymentFactory(statuses=[], transactionLabel="transaction_label") no_status_under_review_payment = payment_factories.PaymentFactory( statuses=[], transactionLabel="transaction_label" ) wrong_transaction_label_payment = payment_factories.PaymentFactory( statuses=[], transactionLabel="wrong_transaction_label" ) expected_payments_to_be_marked_as_sent = [payment1, payment2, payment3, payment4] expected_payments_not_to_be_marked_as_sent = [no_status_under_review_payment, wrong_transaction_label_payment] payment_factories.PaymentStatusFactory(payment=payment1, status=TransactionStatus.UNDER_REVIEW) payment_factories.PaymentStatusFactory(payment=payment1, status=TransactionStatus.PENDING) payment_factories.PaymentStatusFactory(payment=payment2, status=TransactionStatus.UNDER_REVIEW) payment_factories.PaymentStatusFactory(payment=payment3, status=TransactionStatus.UNDER_REVIEW) payment_factories.PaymentStatusFactory(payment=payment4, status=TransactionStatus.UNDER_REVIEW) payment_factories.PaymentStatusFactory(payment=no_status_under_review_payment, status=TransactionStatus.PENDING) # When mark_payments_as_sent("transaction_label", 2) # Then assert PaymentStatus.query.count() == 6 + 4 payments_statuses_sent = PaymentStatus.query.filter(PaymentStatus.status == TransactionStatus.SENT).all() assert len(payments_statuses_sent) == 4 assert set(status.payment for status in payments_statuses_sent) == set(expected_payments_to_be_marked_as_sent) for payment in expected_payments_to_be_marked_as_sent: assert payment.booking.status == BookingStatus.REIMBURSED assert payment.booking.reimbursementDate == payment.currentStatus.date for payment in expected_payments_not_to_be_marked_as_sent: assert payment.booking.status != BookingStatus.REIMBURSED assert payment.booking.reimbursementDate is None
def test_send_transactions_with_malformed_iban(): # given batch_date = datetime.datetime.now() payments_factories.PaymentFactory(iban="CF 13QSDFGH45 qbc //", batchDate=batch_date) # when with pytest.raises(DocumentInvalid) as exc: send_transactions(Payment.query, batch_date, "BD12AZERTY123456", "AZERTY9Q666", "0000", ["*****@*****.**"]) assert str(exc.value) == ( "Element '{urn:iso:std:iso:20022:tech:xsd:pain.001.001.03}IBAN': " "[facet 'pattern'] The value 'CF 13QSDFGH45 qbc //' is not accepted " "by the pattern '[A-Z]{2,2}[0-9]{2,2}[a-zA-Z0-9]{1,30}'., line 76" )
def test_send_payments_details_sends_a_csv_attachment(): # given iban = "CF13QSDFGH456789" bic = "AZERTY9Q666" payments_factories.PaymentFactory(iban=iban, bic=bic) # when send_payments_details(Payment.query, ["*****@*****.**"]) # then assert len(mails_testing.outbox) == 1 assert len(mails_testing.outbox[0].sent_data["Attachments"]) == 1 assert mails_testing.outbox[0].sent_data["Attachments"][0]["ContentType"] == "application/zip"
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_return_payments_filtered_by_venue(self, app): # Given offerer = OffererFactory() venue_1 = VenueFactory(managingOfferer=offerer) venue_2 = VenueFactory(managingOfferer=offerer) payment_1 = payments_factories.PaymentFactory( booking__stock__offer__venue=venue_1) payments_factories.PaymentStatusFactory(payment=payment_1, status=TransactionStatus.SENT) payment_2 = payments_factories.PaymentFactory( booking__stock__offer__venue=venue_2) payments_factories.PaymentStatusFactory(payment=payment_2, status=TransactionStatus.SENT) # When payments = find_all_offerer_payments(offerer.id, reimbursement_period, venue_1.id) # Then assert len(payments) == 1 assert payment_1.booking.token in payments[0] assert venue_1.name in payments[0]