def recover_lost_funds(db, exchange, lost_amount, repudiation_id): """Recover as much money as possible from a payin which has been reverted. """ original_owner = exchange.participant # Try (again) to swap the disputed bundles with db.get_cursor() as cursor: cursor.run("LOCK TABLE cash_bundles IN EXCLUSIVE MODE") disputed_bundles = [ NS(d._asdict()) for d in cursor.all( """ SELECT * FROM cash_bundles WHERE origin = %s AND disputed = true """, (exchange.id, )) ] bundles_sum = sum(b.amount for b in disputed_bundles) assert bundles_sum == lost_amount - exchange.fee for b in disputed_bundles: if b.owner == original_owner: continue try_to_swap_bundle(cursor, b, original_owner) # Move the funds back to the original wallet currency = exchange.amount.currency chargebacks_account, credit_wallet = Participant.get_chargebacks_account( currency) LiberapayOrg = Participant.from_username('LiberapayOrg') assert LiberapayOrg return_payin_bundles_to_origin(db, exchange, LiberapayOrg, create_debts=True) # Add a debt for the fee create_debt(db, original_owner, LiberapayOrg.id, exchange.fee, exchange.id) # Send the funds to the credit wallet # We have to do a SettlementTransfer instead of a normal Transfer. The amount # can't exceed the original payin amount, so we can't settle the fee debt. original_owner = Participant.from_id(original_owner) from_wallet = original_owner.get_current_wallet(currency).remote_id to_wallet = credit_wallet.remote_id t_id = prepare_transfer( db, original_owner.id, chargebacks_account.id, exchange.amount, 'chargeback', from_wallet, to_wallet, prefer_bundles_from=exchange.id, ) tr = SettlementTransfer() tr.AuthorId = original_owner.mangopay_user_id tr.CreditedUserId = chargebacks_account.mangopay_user_id tr.CreditedWalletId = to_wallet tr.DebitedFunds = exchange.amount.int() tr.DebitedWalletId = from_wallet tr.Fees = Money(0, currency) tr.RepudiationId = repudiation_id tr.Tag = str(t_id) return execute_transfer(db, t_id, tr)
def test_CreateSettlementTransfer(self): dispute = None for d in self._client_disputes: if d.status == 'CLOSED' and d.dispute_type == 'NOT_CONTESTABLE': dispute = d break self.assertIsNotNone( dispute, 'Cannot test creating settlement transfer because there\'s no closed and not contestable disputes in the disputes list.' ) repudiation = dispute.transactions.all()[0] self.assertIsNotNone(repudiation) debit_funds = Money() fees = Money() debit_funds.currency = 'EUR' debit_funds.amount = 1 fees.currency = 'EUR' fees.amount = 0 st = SettlementTransfer() st.author = repudiation.author st.debited_funds = debit_funds st.fees = fees st.repudiation_id = repudiation.id result = st.save() self.assertIsNotNone(result) self.assertEqual(result['author_id'], st.author.id)
def recover_lost_funds(db, exchange, lost_amount, repudiation_id): """Recover as much money as possible from a payin which has been reverted. """ original_owner = exchange.participant # Try (again) to swap the disputed bundles with db.get_cursor() as cursor: cursor.run("LOCK TABLE cash_bundles IN EXCLUSIVE MODE") disputed_bundles = [NS(d._asdict()) for d in cursor.all(""" SELECT * FROM cash_bundles WHERE origin = %s AND disputed = true """, (exchange.id,))] bundles_sum = sum(b.amount for b in disputed_bundles) assert bundles_sum == lost_amount - exchange.fee for b in disputed_bundles: if b.owner == original_owner: continue try_to_swap_bundle(cursor, b, original_owner) # Move the funds back to the original wallet currency = exchange.amount.currency chargebacks_account, credit_wallet = Participant.get_chargebacks_account(currency) LiberapayOrg = Participant.from_username('LiberapayOrg') assert LiberapayOrg return_payin_bundles_to_origin(db, exchange, LiberapayOrg, create_debts=True) # Add a debt for the fee create_debt(db, original_owner, LiberapayOrg.id, exchange.fee, exchange.id) # Send the funds to the credit wallet # We have to do a SettlementTransfer instead of a normal Transfer. The amount # can't exceed the original payin amount, so we can't settle the fee debt. original_owner = Participant.from_id(original_owner) from_wallet = original_owner.get_current_wallet(currency).remote_id to_wallet = credit_wallet.remote_id t_id = prepare_transfer( db, original_owner.id, chargebacks_account.id, exchange.amount, 'chargeback', from_wallet, to_wallet, prefer_bundles_from=exchange.id, ) tr = SettlementTransfer() tr.AuthorId = original_owner.mangopay_user_id tr.CreditedUserId = chargebacks_account.mangopay_user_id tr.CreditedWalletId = to_wallet tr.DebitedFunds = Money_to_cents(exchange.amount) tr.DebitedWalletId = from_wallet tr.Fees = Money(0, currency) tr.RepudiationId = repudiation_id tr.Tag = str(t_id) return execute_transfer(db, t_id, tr)
def test_CreateSettlementTransfer(self): dispute = None for d in self._client_disputes: if d.status == 'CLOSED' and d.dispute_type == 'NOT_CONTESTABLE': dispute = d break self.assertIsNotNone(dispute, 'Cannot test creating settlement transfer because there\'s no closed and not contestable disputes in the disputes list.') repudiation = dispute.transactions.all()[0] self.assertIsNotNone(repudiation) debit_funds = Money() fees = Money() debit_funds.currency = 'EUR' debit_funds.amount = 1 fees.currency = 'EUR' fees.amount = 0 st = SettlementTransfer() st.author = repudiation.author st.debited_funds = debit_funds st.fees = fees st.repudiation_id = repudiation.id result = st.save() self.assertIsNotNone(result) self.assertEqual(result['author_id'], st.author.id)
def recover_lost_funds(db, exchange, lost_amount, repudiation_id): """Recover as much money as possible from a payin which has been reverted. """ original_owner = exchange.participant # Try (again) to swap the disputed bundles with db.get_cursor() as cursor: cursor.run("LOCK TABLE cash_bundles IN EXCLUSIVE MODE") disputed_bundles = [ NS(d._asdict()) for d in cursor.all( """ SELECT * FROM cash_bundles WHERE origin = %s AND disputed = true """, (exchange.id, )) ] bundles_sum = sum(b.amount for b in disputed_bundles) assert bundles_sum == lost_amount - exchange.fee for b in disputed_bundles: if b.owner == original_owner: continue try_to_swap_bundle(cursor, b, original_owner) # Move the funds back to the original wallet chargebacks_account = Participant.get_chargebacks_account() LiberapayOrg = Participant.from_username('LiberapayOrg') assert LiberapayOrg grouped = group_by(disputed_bundles, lambda b: (b.owner, b.withdrawal)) for (owner, withdrawal), bundles in grouped.items(): assert owner != chargebacks_account.id if owner == original_owner: continue amount = sum(b.amount for b in bundles) if owner is None: bundles = None withdrawer = db.one( "SELECT participant FROM exchanges WHERE id = %s", (withdrawal, )) payer = LiberapayOrg.id create_debt(db, withdrawer, payer, amount, exchange.id) create_debt(db, original_owner, withdrawer, amount, exchange.id) else: payer = owner create_debt(db, original_owner, payer, amount, exchange.id) transfer(db, payer, original_owner, amount, 'chargeback', bundles=bundles) # Add a debt for the fee create_debt(db, original_owner, LiberapayOrg.id, exchange.fee, exchange.id) # Send the funds to the credit wallet # We have to do a SettlementTransfer instead of a normal Transfer. The amount # can't exceed the original payin amount, so we can't settle the fee debt. original_owner = Participant.from_id(original_owner) t_id = prepare_transfer( db, original_owner.id, chargebacks_account.id, exchange.amount, 'chargeback', original_owner.mangopay_wallet_id, chargebacks_account.mangopay_wallet_id, prefer_bundles_from=exchange.id, ) tr = SettlementTransfer() tr.AuthorId = original_owner.mangopay_user_id tr.CreditedUserId = chargebacks_account.mangopay_user_id tr.CreditedWalletId = chargebacks_account.mangopay_wallet_id tr.DebitedFunds = Money(int(exchange.amount * 100), 'EUR') tr.DebitedWalletId = original_owner.mangopay_wallet_id tr.Fees = Money(0, 'EUR') tr.RepudiationId = repudiation_id tr.Tag = str(t_id) tr.save() return record_transfer_result(db, t_id, tr)