def test_returns_85_reimbursement_rate_between_40000_and_150000_when_cumulative_value_is_150000( self): # given booking1 = create_booking_for_event(amount=19000, quantity=1) booking2 = create_booking_for_thing(url="http://truc", amount=50, quantity=3) booking3 = create_booking_for_thing(amount=19000, quantity=4) booking4 = create_booking_for_thing(amount=5000, quantity=1) bookings = [booking1, booking2, booking3, booking4] cumulative_value_for_bookings_1_and_3_and_4 = ( booking1.amount * booking1.quantity + booking3.amount * booking3.quantity + booking4.amount * booking4.quantity) # when booking_reimbursements = find_all_booking_reimbursements( bookings, NEW_RULES) # then assert_total_reimbursement(booking_reimbursements[0], booking1) assert_no_reimbursement_for_digital(booking_reimbursements[1], booking2) assert_degressive_reimbursement( booking_reimbursements[2], booking3, cumulative_value_for_bookings_1_and_3_and_4) assert_degressive_reimbursement( booking_reimbursements[3], booking4, cumulative_value_for_bookings_1_and_3_and_4)
def generate_new_payments() -> Tuple[List[Payment], List[Payment]]: offerers = Offerer.query.all() all_payments = [] for offerer in offerers: booking_reimbursements = [] for venue in offerer.managedVenues: final_bookings = booking_repository.find_bookings_eligible_for_payment_for_venue( venue.id) booking_reimbursements += find_all_booking_reimbursements( final_bookings, RULES) booking_reimbursements_to_pay = filter_out_already_paid_for_bookings( filter_out_bookings_without_cost(booking_reimbursements)) with db.session.no_autoflush: payments = list( map(create_payment_for_booking, booking_reimbursements_to_pay)) if payments: repository.save(*payments) all_payments.extend(payments) logger.info("[BATCH][PAYMENTS] Saved %i payments for offerer : %s", len(payments), offerer.name) logger.info( "[BATCH][PAYMENTS] Generated %i payments for %i offerers in total", len(all_payments), len(offerers)) pending_payments = keep_only_pending_payments(all_payments) not_processable_payments = keep_only_not_processable_payments(all_payments) logger.info("[BATCH][PAYMENTS] %s Payments in status PENDING to send", len(pending_payments)) return pending_payments, not_processable_payments
def test_returns_85_reimbursement_rate_between_20000_and_40000_euros_for_this_civil_year( self): # given booking1 = create_booking_for_event(amount=20000, quantity=1, date_created=datetime( 2018, 1, 1)) booking2 = create_booking_for_thing(amount=25000, quantity=1, date_created=datetime( 2019, 1, 1)) booking3 = create_booking_for_thing(amount=2000, quantity=1, date_created=datetime( 2019, 1, 1)) bookings = [booking1, booking2, booking3] # when booking_reimbursements = find_all_booking_reimbursements( bookings, NEW_RULES) # then assert_total_reimbursement(booking_reimbursements[0], booking1) assert_degressive_reimbursement(booking_reimbursements[1], booking2, 25000) assert_degressive_reimbursement(booking_reimbursements[2], booking3, 27000)
def test_degressive_reimbursement_above_150000(self): user = create_rich_user(150000) event1 = create_event_booking(user=user, price=150000) event2 = create_event_booking(price=100) thing = create_non_digital_thing_booking(price=100) digital = create_digital_booking(price=100) book = create_book_booking(price=100) educational = bookings_factories.UsedEducationalBookingFactory() bookings = [event1, event2, thing, digital, book, educational] reimbursements = reimbursement.find_all_booking_reimbursements( bookings, reimbursement.CustomRuleFinder()) assert_partial_reimbursement( reimbursements[0], event1, reimbursement.ReimbursementRateByVenueBetween40000And150000, 0.92 * 150000) assert_partial_reimbursement( reimbursements[1], event2, reimbursement.ReimbursementRateByVenueAbove150000, 90) assert_partial_reimbursement( reimbursements[2], thing, reimbursement.ReimbursementRateByVenueAbove150000, 90) assert_no_reimbursement_for_digital(reimbursements[3], digital) assert_partial_reimbursement( reimbursements[4], book, reimbursement.ReimbursementRateForBookAbove20000, 95) assert_total_reimbursement( reimbursements[5], reimbursement.EducationalOffersReimbursement, educational)
def test_returns_full_reimbursement_for_all_bookings_for_new_civil_year( self): # given booking1 = create_booking_for_event(amount=10000, quantity=1, date_created=datetime( 2018, 1, 1)) booking2 = create_booking_for_thing(amount=10000, quantity=1, date_created=datetime( 2018, 1, 1)) booking3 = create_booking_for_event(amount=200, quantity=2, date_created=datetime( 2019, 1, 1)) bookings = [booking1, booking2, booking3] # when booking_reimbursements = find_all_booking_reimbursements( bookings, NEW_RULES) # then assert_total_reimbursement(booking_reimbursements[0], booking1) assert_total_reimbursement(booking_reimbursements[1], booking2) assert_total_reimbursement(booking_reimbursements[2], booking3)
def test_returns_full_reimbursement_for_all_bookings_above_20000_if_rule_is_not_valid_anymore( self): # given now = datetime.utcnow() booking1 = create_booking_for_event(amount=50, quantity=1, date_created=now) booking2 = create_booking_for_thing(url="http://truc", amount=50, quantity=3, date_created=now) booking3 = create_booking_for_thing(amount=1995, quantity=10, date_created=now) bookings = [booking1, booking2, booking3] ReimbursementRules.MAX_REIMBURSEMENT.value.valid_from = now - timedelta( weeks=5) ReimbursementRules.MAX_REIMBURSEMENT.value.valid_until = now + timedelta( weeks=5) # when booking_reimbursements = find_all_booking_reimbursements( bookings, CURRENT_RULES) # then assert_total_reimbursement(booking_reimbursements[0], booking1) assert_no_reimbursement_for_digital(booking_reimbursements[1], booking2) assert_total_reimbursement(booking_reimbursements[2], booking3) # tear down ReimbursementRules.MAX_REIMBURSEMENT.value.valid_from = None ReimbursementRules.MAX_REIMBURSEMENT.value.valid_until = None
def test_returns_85_reimbursement_rate_between_40000_and_150000_when_cumulative_value_is_150000(self): # given user = create_rich_user(150000) booking1 = create_event_booking(user=user, price=19000) booking2 = create_digital_booking(price=50, quantity=3) booking3 = create_non_digital_thing_booking(user=user, price=19000, quantity=4) booking4 = create_non_digital_thing_booking(user=user, price=5000) bookings = [booking1, booking2, booking3, booking4] cumulative_value_for_bookings_1_and_3_and_4 = ( booking1.amount * booking1.quantity + booking3.amount * booking3.quantity + booking4.amount * booking4.quantity ) # when booking_reimbursements = find_all_booking_reimbursements(bookings, RULES) # then assert_total_reimbursement(booking_reimbursements[0], booking1) assert_no_reimbursement_for_digital(booking_reimbursements[1], booking2) assert_degressive_reimbursement( booking_reimbursements[2], booking3, cumulative_value_for_bookings_1_and_3_and_4 ) assert_degressive_reimbursement( booking_reimbursements[3], booking4, cumulative_value_for_bookings_1_and_3_and_4 )
def test_pre_september_2021_degressive_reimbursement_around_20000(self): user = create_rich_user(20000) event1 = create_event_booking(user=user, price=20000) event2 = create_event_booking(price=100) thing = create_non_digital_thing_booking(price=100) digital = create_digital_booking(price=100) book = create_book_booking(price=100) educational = bookings_factories.UsedEducationalBookingFactory() bookings = [event1, event2, thing, digital, book, educational] reimbursements = reimbursement.find_all_booking_reimbursements( bookings, reimbursement.CustomRuleFinder()) assert_total_reimbursement(reimbursements[0], reimbursement.PhysicalOffersReimbursement, event1) rule = reimbursement.LegacyPreSeptember2021ReimbursementRateByVenueBetween20000And40000 assert_partial_reimbursement(reimbursements[1], event2, rule, Decimal(95)) assert_partial_reimbursement(reimbursements[2], thing, rule, 95) assert_no_reimbursement_for_digital(reimbursements[3], digital) assert_partial_reimbursement( reimbursements[4], book, reimbursement.ReimbursementRateForBookAbove20000, 95) assert_total_reimbursement( reimbursements[5], reimbursement.EducationalOffersReimbursement, educational)
def test_returns_a_different_reimbursement_for_digital_booking(self): # given booking1 = create_event_booking() booking2 = create_digital_booking() booking3 = create_event_booking() bookings = [booking1, booking2, booking3] # when booking_reimbursements = find_all_booking_reimbursements(bookings, RULES) # then assert_total_reimbursement(booking_reimbursements[0], booking1) assert_no_reimbursement_for_digital(booking_reimbursements[1], booking2) assert_total_reimbursement(booking_reimbursements[2], booking3)
def test_returns_full_reimbursement_when_cumulative_value_is_20000(self): # given booking1 = create_event_booking() booking2 = create_digital_booking() booking3 = create_non_digital_thing_booking() bookings = [booking1, booking2, booking3] # when booking_reimbursements = find_all_booking_reimbursements(bookings, RULES) # then assert_total_reimbursement(booking_reimbursements[0], booking1) assert_total_reimbursement(booking_reimbursements[2], booking3) assert_no_reimbursement_for_digital(booking_reimbursements[1], booking2)
def test_returns_65_reimbursement_rate_above_150000_euros_for_last_booking(self): # given user = create_rich_user(300000) booking1 = create_event_booking(user=user, price=19000) booking2 = create_digital_booking(price=50, quantity=3) booking3 = create_non_digital_thing_booking(user=user, price=2000, quantity=120) bookings = [booking1, booking2, booking3] # when booking_reimbursements = find_all_booking_reimbursements(bookings, RULES) # then assert_total_reimbursement(booking_reimbursements[0], booking1) assert_degressive_reimbursement(booking_reimbursements[2], booking3, 430000) assert_no_reimbursement_for_digital(booking_reimbursements[1], booking2)
def test_returns_full_reimbursement_for_all_bookings(self): # given booking1 = create_booking_for_event(amount=50, quantity=1) booking2 = create_booking_for_thing(amount=40, quantity=3) booking3 = create_booking_for_event(amount=100, quantity=2) bookings = [booking1, booking2, booking3] # when booking_reimbursements = find_all_booking_reimbursements( bookings, NEW_RULES) # then assert_total_reimbursement(booking_reimbursements[0], booking1) assert_total_reimbursement(booking_reimbursements[1], booking2) assert_total_reimbursement(booking_reimbursements[2], booking3)
def test_returns_full_reimbursement_for_all_bookings_for_new_civil_year(self): # given user = create_rich_user(30000) booking1 = create_event_booking(user=user, price=10000, date_created=datetime(2018, 1, 1)) booking2 = create_non_digital_thing_booking(user=user, price=10000, date_created=datetime(2018, 1, 1)) booking3 = create_event_booking(user=user, price=200, quantity=2, date_created=datetime(2019, 1, 1)) bookings = [booking1, booking2, booking3] # when booking_reimbursements = find_all_booking_reimbursements(bookings, RULES) # then assert_total_reimbursement(booking_reimbursements[0], booking1) assert_total_reimbursement(booking_reimbursements[1], booking2) assert_total_reimbursement(booking_reimbursements[2], booking3)
def test_returns_85_reimbursement_rate_between_20000_and_40000_euros_for_this_civil_year(self): # given user = create_rich_user(50000) booking1 = create_event_booking(user=user, price=20000, date_created=datetime(2018, 1, 1)) booking2 = create_non_digital_thing_booking(user=user, price=25000, date_created=datetime(2019, 1, 1)) booking3 = create_non_digital_thing_booking(user=user, price=2000, date_created=datetime(2019, 1, 1)) bookings = [booking1, booking2, booking3] # when booking_reimbursements = find_all_booking_reimbursements(bookings, RULES) # then assert_total_reimbursement(booking_reimbursements[0], booking1) assert_degressive_reimbursement(booking_reimbursements[1], booking2, 25000) assert_degressive_reimbursement(booking_reimbursements[2], booking3, 27000)
def test_returns_95_reimbursement_rate_between_20000_and_40000_euros_for_most_recent_booking(self): # given user = create_rich_user(20000) booking1 = create_event_booking(user=user, price=19990) booking2 = create_digital_booking() booking3 = create_non_digital_thing_booking(price=20) bookings = [booking1, booking2, booking3] cumulative_value_for_bookings_1_and_3 = ( booking1.amount * booking1.quantity + booking3.amount * booking3.quantity ) # when booking_reimbursements = find_all_booking_reimbursements(bookings, RULES) # then assert_total_reimbursement(booking_reimbursements[0], booking1) assert_degressive_reimbursement(booking_reimbursements[2], booking3, cumulative_value_for_bookings_1_and_3) assert_no_reimbursement_for_digital(booking_reimbursements[1], booking2)
def test_returns_a_different_reimbursement_for_digital_booking(self): # given booking1 = create_booking_for_event(amount=50, quantity=1) booking2 = create_booking_for_thing(url="http://truc", amount=40, quantity=3) booking3 = create_booking_for_event(amount=100, quantity=2) bookings = [booking1, booking2, booking3] # when booking_reimbursements = find_all_booking_reimbursements( bookings, NEW_RULES) # then assert_total_reimbursement(booking_reimbursements[2], booking3) assert_total_reimbursement(booking_reimbursements[0], booking1) assert_no_reimbursement_for_digital(booking_reimbursements[1], booking2)
def test_returns_full_reimbursement_when_cumulative_value_is_20000( self): # given booking1 = create_booking_for_event(amount=19990, quantity=1) booking2 = create_booking_for_thing(url="http://truc", amount=50, quantity=3) booking3 = create_booking_for_thing(amount=10, quantity=1) bookings = [booking1, booking2, booking3] # when booking_reimbursements = find_all_booking_reimbursements( bookings, NEW_RULES) # then assert_total_reimbursement(booking_reimbursements[0], booking1) assert_total_reimbursement(booking_reimbursements[2], booking3) assert_no_reimbursement_for_digital(booking_reimbursements[1], booking2)
def test_returns_no_reimbursement_above_20000_euros_for_last_booking( self): # given booking1 = create_booking_for_event(amount=60, quantity=1) booking2 = create_booking_for_thing(url="http://truc", amount=50, quantity=3) booking3 = create_booking_for_thing(amount=1995, quantity=10) bookings = [booking1, booking2, booking3] # when booking_reimbursements = find_all_booking_reimbursements( bookings, CURRENT_RULES) # then assert_total_reimbursement(booking_reimbursements[0], booking1) assert_no_reimbursement_for_digital(booking_reimbursements[1], booking2) assert_no_reimbursement_beyond_max(booking_reimbursements[2], booking3)
def test_returns_65_reimbursement_rate_above_150000_euros_for_last_booking( self): # given booking1 = create_booking_for_event(amount=19000, quantity=1) booking2 = create_booking_for_thing(url="http://truc", amount=50, quantity=3) booking3 = create_booking_for_thing(amount=2000, quantity=120) bookings = [booking1, booking2, booking3] # when booking_reimbursements = find_all_booking_reimbursements( bookings, NEW_RULES) # then assert_total_reimbursement(booking_reimbursements[0], booking1) assert_degressive_reimbursement(booking_reimbursements[2], booking3, 430000) assert_no_reimbursement_for_digital(booking_reimbursements[1], booking2)
def test_degressive_reimbursement_around_20000(self): user = create_rich_user(20000) reimbursed_digital1 = create_digital_booking( product_subcategory_id=subcategories.MUSEE_VENTE_DISTANCE.id, user=user, price=20000, ) reimbursed_digital2 = create_digital_booking( product_subcategory_id=subcategories.MUSEE_VENTE_DISTANCE.id, price=100, ) thing = create_non_digital_thing_booking(price=100) digital = create_digital_booking(price=100) book = create_book_booking(price=100) educational = bookings_factories.UsedEducationalBookingFactory() bookings = [ reimbursed_digital1, reimbursed_digital2, thing, digital, book, educational ] reimbursements = reimbursement.find_all_booking_reimbursements( bookings, reimbursement.CustomRuleFinder()) assert_total_reimbursement( reimbursements[0], reimbursement.PhysicalOffersReimbursement, reimbursed_digital1, ) rule = reimbursement.ReimbursementRateByVenueBetween20000And40000 assert_partial_reimbursement(reimbursements[1], reimbursed_digital2, rule, 95) assert_partial_reimbursement(reimbursements[2], thing, rule, 95) assert_no_reimbursement_for_digital(reimbursements[3], digital) assert_partial_reimbursement( reimbursements[4], book, reimbursement.ReimbursementRateForBookAbove20000, 95) assert_total_reimbursement( reimbursements[5], reimbursement.EducationalOffersReimbursement, educational)
def test_select_custom_reimbursement_rule_if_applicable(self): offer1 = offers_factories.DigitalOfferFactory() booking1 = bookings_factories.UsedBookingFactory(stock__offer=offer1) offer2 = offers_factories.DigitalOfferFactory() booking2 = bookings_factories.UsedBookingFactory(stock__offer=offer2) rule1 = payments_factories.CustomReimbursementRuleFactory(offer=offer1, amount=5) payments_factories.CustomReimbursementRuleFactory( offer=offer2, timespan=[booking2.dateCreated + timedelta(days=2), None]) educational = bookings_factories.UsedEducationalBookingFactory() bookings = [booking1, booking2, educational] reimbursements = reimbursement.find_all_booking_reimbursements( bookings, reimbursement.CustomRuleFinder()) assert reimbursements[0].booking == booking1 assert reimbursements[0].rule == rule1 assert reimbursements[0].reimbursed_amount == 5 assert_no_reimbursement_for_digital(reimbursements[1], booking2) assert_total_reimbursement( reimbursements[2], reimbursement.EducationalOffersReimbursement, educational)
def test_full_reimbursement_for_all_bookings_for_new_civil_year(self): user = create_rich_user(30000) booking1 = create_event_booking(user=user, price=20000, date_used=datetime(2018, 1, 1)) booking2 = create_event_booking(user=user, price=100, date_used=datetime(2019, 1, 1)) educational = bookings_factories.UsedEducationalBookingFactory() bookings = [booking1, booking2, educational] reimbursements = reimbursement.find_all_booking_reimbursements( bookings, reimbursement.CustomRuleFinder()) assert_total_reimbursement(reimbursements[0], reimbursement.PhysicalOffersReimbursement, booking1) assert_total_reimbursement(reimbursements[1], reimbursement.PhysicalOffersReimbursement, booking2) assert_total_reimbursement( reimbursements[2], reimbursement.EducationalOffersReimbursement, educational)
def test_returns_95_reimbursement_rate_between_20000_and_40000_euros_for_most_recent_booking( self): # given booking1 = create_booking_for_event(amount=19990, quantity=1) booking2 = create_booking_for_thing(url="http://truc", amount=50, quantity=3) booking3 = create_booking_for_thing(amount=20, quantity=1) bookings = [booking1, booking2, booking3] cumulative_value_for_bookings_1_and_3 = ( booking1.amount * booking1.quantity + booking3.amount * booking3.quantity) # when booking_reimbursements = find_all_booking_reimbursements( bookings, NEW_RULES) # then assert_total_reimbursement(booking_reimbursements[0], booking1) assert_degressive_reimbursement( booking_reimbursements[2], booking3, cumulative_value_for_bookings_1_and_3) assert_no_reimbursement_for_digital(booking_reimbursements[1], booking2)
def test_reimbursement_under_20000(self): event = create_event_booking() thing = create_non_digital_thing_booking() digital = create_digital_booking() book = create_book_booking() educational = bookings_factories.UsedEducationalBookingFactory() bookings = [event, thing, digital, book, educational] reimbursements = reimbursement.find_all_booking_reimbursements( bookings, reimbursement.CustomRuleFinder()) assert_total_reimbursement(reimbursements[0], reimbursement.PhysicalOffersReimbursement, event) assert_total_reimbursement(reimbursements[1], reimbursement.PhysicalOffersReimbursement, thing) assert_no_reimbursement_for_digital(reimbursements[2], digital) assert_total_reimbursement( reimbursements[3], reimbursement.ReimbursementRateForBookBelow20000, book) assert_total_reimbursement( reimbursements[4], reimbursement.EducationalOffersReimbursement, educational)
def generate_new_payments(cutoff_date: datetime, batch_date: datetime) -> None: n_payments = 0 logger.info("Fetching venues to reimburse") venues_to_reimburse = get_venues_to_reimburse(cutoff_date) logger.info("Found %d venues to reimburse", len(venues_to_reimburse)) custom_rule_finder = CustomRuleFinder() n_payments = 0 for venue_id, venue_name in venues_to_reimburse: logger.info("[BATCH][PAYMENTS] Fetching bookings for venue: %s", venue_name, extra={"venue": venue_id}) bookings = booking_repository.find_bookings_eligible_for_payment_for_venue( venue_id, cutoff_date) logger.info( "[BATCH][PAYMENTS] Calculating reimbursements for venue: %s", venue_name, extra={"venue": venue_id}) reimbursements = find_all_booking_reimbursements( bookings, custom_rule_finder) to_pay = filter_out_already_paid_for_bookings( filter_out_bookings_without_cost(reimbursements)) if not to_pay: logger.info( "[BATCH][PAYMENTS] No payments generated for venue: %s", venue_name, extra={"venue": venue_id}) continue n_payments += len(to_pay) logger.info( "[BATCH][PAYMENTS] Creating Payment objects for venue: %s", venue_name, extra={ "venue": venue_id, "payments": len(to_pay) }, ) payments = [ create_payment_for_booking(reimbursement, batch_date) for reimbursement in to_pay ] logger.info( "[BATCH][PAYMENTS] Inserting Payment objects for venue: %s", venue_name, extra={ "venue": venue_id, "payments": len(to_pay) }, ) db.session.bulk_save_objects(payments) db.session.commit() logger.info( "[BATCH][PAYMENTS] Saved %i payments for venue: %s", len(payments), venue_name, extra={ "venue": venue_id, "payments": len(payments) }, ) # Create all payment statuses. We get payments created above by # looking at their batch date. if n_payments: base_payment_query = Payment.query.filter_by(batchDate=batch_date) payments_api.bulk_create_payment_statuses( base_payment_query.filter(Payment.iban.isnot(None)), status=TransactionStatus.PENDING, ) payments_api.bulk_create_payment_statuses( base_payment_query.filter(Payment.iban.is_(None)), status=TransactionStatus.NOT_PROCESSABLE, detail="IBAN et BIC manquants sur l'offreur", ) db.session.commit() logger.info( "[BATCH][PAYMENTS] Generated %i payments for %i venues", n_payments, len(venues_to_reimburse), )