def test_late_manual_payment_switched_to_automatic_is_scheduled_a_week_away(self): # Set up a manual donation alice = self.make_participant('alice', email='*****@*****.**') bob = self.make_participant('bob') alice.set_tip_to(bob, EUR('0.23'), renewal_mode=1) alice_sdd = self.upsert_route(alice, 'stripe-sdd') payin, pt = self.make_payin_and_transfer(alice_sdd, bob, EUR('0.22'), status='pending') self.db.run("UPDATE payin_transfers SET ctime = ctime - interval '3 weeks'") update_payin_transfer(self.db, pt.id, pt.remote_id, 'succeeded', None) # At this point we should have a manual renewal scheduled in the past scheduled_payins = self.db.all("SELECT * FROM scheduled_payins") assert len(scheduled_payins) == 1 assert scheduled_payins[0].amount is None assert scheduled_payins[0].automatic is False payment_timedelta = scheduled_payins[0].execution_date - utcnow().date() assert payment_timedelta.days <= -6 # Running the scheduler again shouldn't change anything. old_scheduled_payins = scheduled_payins alice.schedule_renewals() scheduled_payins = self.db.all("SELECT * FROM scheduled_payins") assert old_scheduled_payins == scheduled_payins # Turn on automatic renewals. The execution date should now be in the future. r = self.client.PxST("/alice/giving/", {"auto_renewal": "yes"}, auth_as=alice) assert r.code == 302 tip = alice.get_tip_to(bob) assert tip.renewal_mode == 2 scheduled_payins = self.db.all("SELECT * FROM scheduled_payins WHERE payin IS NULL") assert len(scheduled_payins) == 1 assert scheduled_payins[0].amount == EUR('10.00') assert scheduled_payins[0].automatic is True payment_timedelta = scheduled_payins[0].execution_date - utcnow().date() assert payment_timedelta.days in (6, 7) assert scheduled_payins[0].customized is True assert scheduled_payins[0].last_notif_ts is None assert scheduled_payins[0].notifs_count == 0
def test_newly_scheduled_automatic_payments_are_at_least_a_week_away(self): # Set up an automatic donation funded 4 weeks ago alice = self.make_participant('alice', email='*****@*****.**') bob = self.make_participant('bob') alice.set_tip_to(bob, EUR('0.23'), renewal_mode=2) alice_sdd = self.upsert_route(alice, 'stripe-sdd') payin, pt = self.make_payin_and_transfer(alice_sdd, bob, EUR('0.22'), status='pending') self.db.run( "UPDATE payin_transfers SET ctime = ctime - interval '4 weeks'") update_payin_transfer(self.db, pt.id, pt.remote_id, 'succeeded', None) # At this point we should have an automatic renewal scheduled one week from now scheduled_payins = self.db.all("SELECT * FROM scheduled_payins") assert len(scheduled_payins) == 1 assert scheduled_payins[0].amount == EUR('10.12') assert scheduled_payins[0].automatic is True payment_timedelta = scheduled_payins[0].execution_date - utcnow().date( ) assert payment_timedelta.days in (6, 7) assert scheduled_payins[0].customized is True # Running the scheduler again shouldn't change anything. old_scheduled_payins = scheduled_payins alice.schedule_renewals() scheduled_payins = self.db.all("SELECT * FROM scheduled_payins") assert old_scheduled_payins == scheduled_payins
def make_payin_and_transfer(self, route, tippee, amount, status='succeeded', error=None, payer_country=None, unit_amount=None, period=None): payer = route.participant payin = prepare_payin(self.db, payer, amount, route) payin = update_payin(self.db, payin.id, 'fake', status, error) provider = route.network.split('-', 1)[0] try: destination = resolve_destination(self.db, tippee, provider, payer, payer_country, amount) except MissingPaymentAccount as e: destination = self.add_payment_account(e.args[0], provider) recipient = Participant.from_id(destination.participant) if tippee.kind == 'group': context = 'team-donation' team = tippee.id else: context = 'personal-donation' team = None pt = prepare_payin_transfer(self.db, payin, recipient, destination, context, amount, unit_amount, period, team) pt = update_payin_transfer(self.db, pt.id, 'fake', status, error) payer.update_giving() tippee.update_receiving() if team: recipient.update_receiving() return payin, pt
def make_payin_and_transfer(self, route, tippee, amount, provider, status='succeeded', error=None, payer_country=None, unit_amount=None, period=None): payer = route.participant payin = prepare_payin(self.db, payer, amount, route) payin = update_payin(self.db, payin.id, 'fake', status, error) destination = resolve_destination(self.db, tippee, provider, payer, payer_country, amount) recipient = Participant.from_id(destination.participant) if tippee.kind == 'group': context = 'team-donation' team = tippee else: context = 'personal-donation' team = None pt = prepare_payin_transfer(self.db, payin, recipient, destination, context, amount, unit_amount, period, team.id) pt = update_payin_transfer(self.db, pt.id, 'fake', status, error) return payin, pt
def make_payin_and_transfer( self, route, tippee, amount, status='succeeded', error=None, payer_country=None, unit_amount=None, period=None ): payer = route.participant payin = prepare_payin(self.db, payer, amount, route) payin = update_payin(self.db, payin.id, 'fake', status, error) provider = route.network.split('-', 1)[0] try: destination = resolve_destination( self.db, tippee, provider, payer, payer_country, amount ) except MissingPaymentAccount as e: destination = self.add_payment_account(e.args[0], provider) recipient = Participant.from_id(destination.participant) if tippee.kind == 'group': context = 'team-donation' team = tippee.id else: context = 'personal-donation' team = None pt = prepare_payin_transfer( self.db, payin, recipient, destination, context, amount, unit_amount, period, team ) pt = update_payin_transfer(self.db, pt.id, 'fake', status, error) payer.update_giving() tippee.update_receiving() if team: recipient.update_receiving() return payin, pt
def make_payin_and_transfers( self, route, amount, transfers, status='succeeded', error=None, payer_country=None, fee=None, remote_id='fake', ): payer = route.participant payin = prepare_payin(self.db, payer, amount, route) provider = route.network.split('-', 1)[0] for tippee, pt_amount, opt in transfers: tip = opt.get('tip') if tip: assert tip.tipper == payer.id assert tip.tippee == tippee.id else: tip = self.db.one(""" SELECT * FROM current_tips WHERE tipper = %s AND tippee = %s """, (payer.id, tippee.id)) assert tip for i in range(100): try: prepare_donation( self.db, payin, tip, tippee, provider, payer, payer_country, pt_amount ) except MissingPaymentAccount as e: if i > 95: # Infinite loop? raise recipient = e.args[0] if recipient.kind == 'group': raise self.add_payment_account(recipient, provider) else: break payin = update_payin(self.db, payin.id, remote_id, status, error, fee=fee) net_amount = payin.amount - (fee or 0) adjust_payin_transfers(self.db, payin, net_amount) payin_transfers = self.db.all(""" SELECT * FROM payin_transfers WHERE payin = %s ORDER BY ctime """, (payin.id,)) for tippee, pt_amount, opt in transfers: for i, pt in enumerate(payin_transfers): payin_transfers[i] = update_payin_transfer( self.db, pt.id, opt.get('remote_id', 'fake'), opt.get('status', status), opt.get('error', error) ) if pt.team: Participant.from_id(pt.recipient).update_receiving() tippee.update_receiving() payer.update_giving() return payin, payin_transfers
def make_payin_and_transfers( self, route, amount, transfers, status='succeeded', error=None, payer_country=None, remote_id='fake', ): payer = route.participant payin = prepare_payin(self.db, payer, amount, route) payin = update_payin(self.db, payin.id, remote_id, status, error) provider = route.network.split('-', 1)[0] payin_transfers = [] for tippee, pt_amount, opt in transfers: try: destination = resolve_destination(self.db, tippee, provider, payer, payer_country, pt_amount) except MissingPaymentAccount as e: destination = self.add_payment_account(e.args[0], provider) recipient = Participant.from_id(destination.participant) if tippee.kind == 'group': context = 'team-donation' team = tippee.id else: context = 'personal-donation' team = None pt = prepare_payin_transfer(self.db, payin, recipient, destination, context, pt_amount, opt.get('unit_amount'), opt.get('period'), team) pt = update_payin_transfer(self.db, pt.id, opt.get('remote_id', 'fake'), opt.get('status', status), opt.get('error', error)) payin_transfers.append(pt) tippee.update_receiving() if team: recipient.update_receiving() payer.update_giving() return payin, payin_transfers
def make_payin_and_transfers( self, route, amount, transfers, status='succeeded', error=None, payer_country=None, fee=None, remote_id='fake', ): payer = route.participant provider = route.network.split('-', 1)[0] proto_transfers = [] net_amount = 0 for tippee, pt_amount, opt in transfers: net_amount += pt_amount tip = opt.get('tip') if tip: assert tip.tipper == payer.id assert tip.tippee == tippee.id else: tip = self.db.one( """ SELECT * FROM current_tips WHERE tipper = %s AND tippee = %s """, (payer.id, tippee.id)) assert tip for i in range(100): try: proto_transfers.extend( resolve_tip(self.db, tip, tippee, provider, payer, payer_country, pt_amount)) except MissingPaymentAccount as e: if i > 95: # Infinite loop? raise recipient = e.args[0] if recipient.kind == 'group': raise self.add_payment_account(recipient, provider) else: break payin, payin_transfers = prepare_payin(self.db, payer, amount, route, proto_transfers) del proto_transfers payin = update_payin(self.db, payin.id, remote_id, status, error, fee=fee) if len(payin_transfers) > 1: adjust_payin_transfers(self.db, payin, net_amount) else: pt = payin_transfers[0] # Call `update_payin_transfer` twice to uncover bugs pt = update_payin_transfer(self.db, pt.id, None, pt.status, None, amount=net_amount) pt = update_payin_transfer(self.db, pt.id, None, pt.status, None) assert pt.amount == net_amount payin_transfers = self.db.all( """ SELECT * FROM payin_transfers WHERE payin = %s ORDER BY ctime """, (payin.id, )) fallback_remote_id = 'fake' if payin.status == 'succeeded' else None options_by_tippee = { tippee.id: opt for tippee, pt_amount, opt in transfers } for i, pt in enumerate(payin_transfers): opt = options_by_tippee[pt.team or pt.recipient] payin_transfers[i] = update_payin_transfer( self.db, pt.id, opt.get('remote_id', fallback_remote_id), opt.get('status', status), opt.get('error', error)) if pt.team: Participant.from_id(pt.recipient).update_receiving() for tippee, pt_amount, opt in transfers: tippee.update_receiving() payer.update_giving() # Call `update_payin` again to uncover bugs payin = update_payin(self.db, payin.id, remote_id, status, error) return payin, payin_transfers