From 42cd4ef0e7e794e603dbb63dde6aa54855c711ee Mon Sep 17 00:00:00 2001 From: Tanner Collin Date: Thu, 13 Feb 2020 22:49:08 +0000 Subject: [PATCH] Add script to import missing paypal txs from their API --- apiserver/.gitignore | 1 + apiserver/apiserver/api/utils_paypal.py | 2 +- apiserver/import_missing_paypal.py | 186 ++++++++++++++++++++++++ apiserver/missing_paypal/.gitkeep | 0 4 files changed, 188 insertions(+), 1 deletion(-) create mode 100755 apiserver/import_missing_paypal.py create mode 100644 apiserver/missing_paypal/.gitkeep diff --git a/apiserver/.gitignore b/apiserver/.gitignore index 8380732..2edfcbd 100644 --- a/apiserver/.gitignore +++ b/apiserver/.gitignore @@ -110,4 +110,5 @@ migrations/ data/ old_photos/ old_paypal/ +missing_paypal/ secrets.py diff --git a/apiserver/apiserver/api/utils_paypal.py b/apiserver/apiserver/api/utils_paypal.py index 08de0b1..0545eca 100644 --- a/apiserver/apiserver/api/utils_paypal.py +++ b/apiserver/apiserver/api/utils_paypal.py @@ -287,7 +287,7 @@ def process_paypal_ipn(data): member = members.get(id=member_id) monthly_fees = member.monthly_fees - if amount.is_integer() and amount % monthly_fees == 0: + if amount.is_integer() and monthly_fees and amount % monthly_fees == 0: num_months = int(amount // monthly_fees) else: num_months = 0 diff --git a/apiserver/import_missing_paypal.py b/apiserver/import_missing_paypal.py new file mode 100755 index 0000000..2e14da0 --- /dev/null +++ b/apiserver/import_missing_paypal.py @@ -0,0 +1,186 @@ +import django, sys, os +os.environ['DJANGO_SETTINGS_MODULE'] = 'apiserver.settings' +django.setup() + +import datetime +import json +from apiserver.api import models, old_models, utils + +def find_name(t): + try: + p_info = t['payer_info'] + except KeyError: + return 'Unknown Name' + try: + return p_info['payer_name']['given_name'] + ' ' + p_info['payer_name']['surname'] + except KeyError: + pass + try: + return t['shipping_info']['name'] + except KeyError: + pass + try: + return p_info['payer_name']['alternate_full_name'] + except KeyError: + return 'Unknown Name' + +def build_tx(t): + t_info = t['transaction_info'] + p_info = t['payer_info'] + amount = float(t_info['transaction_amount']['value']) + return dict( + account_type='PayPal', + amount=amount, + date=t_info['transaction_updated_date'].split('T')[0], + info_source='PayPal IPN', + payment_method='PayPal', + paypal_payer_id=t_info['paypal_account_id'], + paypal_txn_id=t_info['transaction_id'], + reference_number=t_info['transaction_id'], + memo=t_info.get('transaction_subject', 'no memo') + ' (import missing paypal script)', + ) + +def create_unmatched_member_tx(t): + t_info = t['transaction_info'] + p_info = t['payer_info'] + transactions = models.Transaction.objects + + report_memo = 'Cant link sender name, {}, email: {}, note: {}'.format( + find_name(t), + p_info['email_address'], + '(import missing paypal script)', + ) + + return transactions.create( + **build_tx(t), + report_memo=report_memo, + report_type='Unmatched Member', + ) + +def create_member_dues_tx(t, member, num_months): + transactions = models.Transaction.objects + + # new member 3 for 2 will have to be manual anyway + if num_months == 11: + num_months = 12 + + user = getattr(member, 'user', None) + + tx = transactions.create( + **build_tx(t), + member_id=member.id, + number_of_membership_months=num_months, + user=user, + ) + utils.tally_membership_months(member) + return tx + +def create_unmatched_purchase_tx(t, member): + t_info = t['transaction_info'] + p_info = t['payer_info'] + transactions = models.Transaction.objects + + user = getattr(member, 'user', None) + report_memo = 'Unknown payment reason, {}, email: {}, note: {}'.format( + find_name(t), + p_info['email_address'], + '(import missing paypal script)', + ) + + return transactions.create( + **build_tx(t), + member_id=member.id, + report_memo=report_memo, + report_type='Unmatched Purchase', + user=user, + ) + + +PAYPAL_FOLDER = 'missing_paypal/' + +transactions = models.Transaction.objects.all() +hints = models.PayPalHint.objects.all() +members = models.Member.objects.all() + +paypal_files = os.listdir(PAYPAL_FOLDER) +paypal_json = [x for x in paypal_files if x.endswith('.json')] + +if paypal_json: + print('Found paypal json files:', paypal_json) +else: + print('Couldnt find any paypal json files in', PAYPAL_FOLDER) + exit(1) + +paypal_txs = [] +num_unmatched = 0 +num_dues = 0 +num_noreason = 0 + +for filename in paypal_json: + with open(PAYPAL_FOLDER + filename) as f: + j = json.load(f) + paypal_txs.extend(j['transaction_details']) + +print('Num transactions found:', len(paypal_txs)) +print('Importing transactions into portal...') + +for t in paypal_txs: + t_info = t['transaction_info'] + + account_id = t_info.get('paypal_account_id', None) + if not account_id: + print('Skipping tx id: {}, no payer (could be bank tx):'.format( + t_info['transaction_id'], + )) + print(t_info) + print() + continue + + reference = t_info['transaction_id'][:11] + + similar = transactions.filter(reference_number__startswith=reference) + if similar.exists(): + tx = similar.first() + print('Skipping tx id: {}, transaction already in portal:'.format( + t_info['transaction_id'], + )) + print('https://spaceport.dns.t0.vc/transactions/'+str(tx.id)) + print() + continue + + print('Inspecting tx id:', t_info['transaction_id']) + + if not hints.filter(account=t_info['paypal_account_id']).exists(): + print('Unable to associate with member, reporting') + create_unmatched_member_tx(t) + num_unmatched += 1 + continue + + amount = float(t_info['transaction_amount']['value']) + + member_id = hints.get(account=t_info['paypal_account_id']).member_id + member = members.get(id=member_id) + print('Found member', member.first_name, member.last_name) + monthly_fees = member.monthly_fees + + if amount.is_integer() and monthly_fees and amount % monthly_fees == 0: + num_months = int(amount // monthly_fees) + else: + num_months = 0 + + if num_months: + print('Amount valid for membership dues, adding months:', num_months) + create_member_dues_tx(t, member, num_months) + num_dues += 1 + continue + + print('Unable to find a reason for payment, reporting') + create_unmatched_purchase_tx(t, member) + num_noreason += 1 + + +print('Num unmatched members:', num_unmatched) +print('Num member dues:', num_dues) +print('Num no reason:', num_noreason) +print('Num skipped:', len(paypal_txs) - num_unmatched - num_dues - num_noreason) +print('Done.') diff --git a/apiserver/missing_paypal/.gitkeep b/apiserver/missing_paypal/.gitkeep new file mode 100644 index 0000000..e69de29