Add --verbose flag to print full transaction details
Also document that the format is based on previous Perl code that used the (now non-working) SOAP API.
This commit is contained in:
parent
24862460ca
commit
8fd968c6f9
1 changed files with 39 additions and 9 deletions
|
@ -4,6 +4,7 @@
|
||||||
import argparse
|
import argparse
|
||||||
import collections
|
import collections
|
||||||
import datetime
|
import datetime
|
||||||
|
import pprint
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
|
@ -26,9 +27,24 @@ Run them like this:
|
||||||
$ export PAYPAL_CLIENT_ID=XXX
|
$ export PAYPAL_CLIENT_ID=XXX
|
||||||
$ export PAYPAL_CLIENT_SECRET=YYY
|
$ export PAYPAL_CLIENT_SECRET=YYY
|
||||||
$ python3 paypal_report.py transactions 2021-11-01T00:00:00-07:00 2021-11-30T23:59:59-07:00 > transactions.txt
|
$ python3 paypal_report.py transactions 2021-11-01T00:00:00-07:00 2021-11-30T23:59:59-07:00 > transactions.txt
|
||||||
|
|
||||||
|
Format is:
|
||||||
|
TRANSACTION_ID <TAB> REFERENCE_ID
|
||||||
|
|
||||||
|
Where REFERENCE_ID is equivalent to what PayPal previously called "Profile ID".
|
||||||
|
|
||||||
$ python3 paypal_report.py profiles 2021-11-01T00:00:00-07:00 2021-11-30T23:59:59-07:00 > profiles.txt
|
$ python3 paypal_report.py profiles 2021-11-01T00:00:00-07:00 2021-11-30T23:59:59-07:00 > profiles.txt
|
||||||
|
|
||||||
|
Format is:
|
||||||
|
REFERENCE_ID <TAB> TRANSACTION_SUBJECT
|
||||||
|
|
||||||
$ python3 paypal_report.py suspend 2022-10-01T00:00:00-07:00 2022-10-31T23:59:59-07:00 homebrew
|
$ python3 paypal_report.py suspend 2022-10-01T00:00:00-07:00 2022-10-31T23:59:59-07:00 homebrew
|
||||||
|
|
||||||
|
The output format of these reports is based on the prior Perl code by bkuhn that
|
||||||
|
used the SOAP APIs. These APIs stoped working around 2021, hence the need for
|
||||||
|
this rewrite. Unfortunately, the current APIs don't allow us to directly query
|
||||||
|
for subscriptions, so these are instead extracted from the list of transactions.
|
||||||
|
|
||||||
NOTE: Newly created PayPal "apps"/credentials initially authenticate, but can
|
NOTE: Newly created PayPal "apps"/credentials initially authenticate, but can
|
||||||
then return PERMISSION_DENIED for ~ 40 mins.
|
then return PERMISSION_DENIED for ~ 40 mins.
|
||||||
|
|
||||||
|
@ -111,9 +127,9 @@ def main():
|
||||||
access_token = paypal_login(client_id, client_secret)
|
access_token = paypal_login(client_id, client_secret)
|
||||||
transactions = get_all_transactions(access_token, args.start_date, args.end_date)
|
transactions = get_all_transactions(access_token, args.start_date, args.end_date)
|
||||||
if args.report == 'profiles':
|
if args.report == 'profiles':
|
||||||
report_on_unique_profiles(transactions)
|
report_on_unique_profiles(transactions, verbose=args.verbose)
|
||||||
elif args.report == 'transactions':
|
elif args.report == 'transactions':
|
||||||
report_on_transactions(transactions)
|
report_on_transactions(transactions, verbose=args.verbose)
|
||||||
else:
|
else:
|
||||||
suspend_subscriptions_interactively(transactions, args.pattern, access_token)
|
suspend_subscriptions_interactively(transactions, args.pattern, access_token)
|
||||||
except PayPalException as e:
|
except PayPalException as e:
|
||||||
|
@ -126,6 +142,11 @@ def parse_args():
|
||||||
description="""Download or cancel subscribers or subscriber transactions from PayPal.""",
|
description="""Download or cancel subscribers or subscriber transactions from PayPal.""",
|
||||||
epilog=HELP,
|
epilog=HELP,
|
||||||
)
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
'-v',
|
||||||
|
'--verbose',
|
||||||
|
action='store_true',
|
||||||
|
)
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
'report', help='report or action"', choices=['profiles', 'transactions', 'suspend']
|
'report', help='report or action"', choices=['profiles', 'transactions', 'suspend']
|
||||||
)
|
)
|
||||||
|
@ -200,31 +221,34 @@ def get_transactions_for_period(access_token, start_date, end_date, page=1):
|
||||||
return data['transaction_details']
|
return data['transaction_details']
|
||||||
|
|
||||||
|
|
||||||
def report_on_unique_profiles(transactions):
|
def report_on_unique_profiles(transactions, verbose=False):
|
||||||
"""Print a list of subscribers from a set of transactions.
|
"""Print a list of subscribers from a set of transactions.
|
||||||
|
|
||||||
PayPal doesn't provide a way to query for subscribers directly, so we build
|
PayPal doesn't provide a way to query for subscribers directly, so we build
|
||||||
this by scanning through the list of transactions and finding the unique
|
this by scanning through the list of transactions and finding the unique
|
||||||
subscribers.
|
subscribers.
|
||||||
"""
|
"""
|
||||||
records = set()
|
records = {}
|
||||||
for t in transactions:
|
for t in transactions:
|
||||||
transaction_info = t['transaction_info']
|
transaction_info = t['transaction_info']
|
||||||
if 'paypal_reference_id' in transaction_info:
|
if 'paypal_reference_id' in transaction_info:
|
||||||
records.add(
|
records[
|
||||||
(
|
(
|
||||||
transaction_info['paypal_reference_id'],
|
transaction_info['paypal_reference_id'],
|
||||||
transaction_info.get('transaction_subject', 'NO TRANSACTION SUBJECT'),
|
transaction_info.get('transaction_subject', 'NO TRANSACTION SUBJECT'),
|
||||||
),
|
)
|
||||||
)
|
] = t
|
||||||
else:
|
else:
|
||||||
print(
|
print(
|
||||||
f'Skipping transaction {transaction_info["transaction_id"]} with no PayPal Reference ID.',
|
f'Skipping transaction {transaction_info["transaction_id"]} with no PayPal Reference ID.',
|
||||||
file=sys.stderr,
|
file=sys.stderr,
|
||||||
)
|
)
|
||||||
|
|
||||||
for ref_id, desc in sorted(records):
|
for key, trans in sorted(records.items()):
|
||||||
|
ref_id, desc = key
|
||||||
print(f'{ref_id} {desc}')
|
print(f'{ref_id} {desc}')
|
||||||
|
if verbose:
|
||||||
|
pprint.pprint(trans)
|
||||||
count = collections.Counter([ref_id for ref_id, _ in records])
|
count = collections.Counter([ref_id for ref_id, _ in records])
|
||||||
dupes = [id for id, total in count.items() if total > 1]
|
dupes = [id for id, total in count.items() if total > 1]
|
||||||
print(f'Reference IDs with changing subject: {dupes}', file=sys.stderr)
|
print(f'Reference IDs with changing subject: {dupes}', file=sys.stderr)
|
||||||
|
@ -251,7 +275,7 @@ def get_subscriptions_matching_subject(transactions, pattern):
|
||||||
return records
|
return records
|
||||||
|
|
||||||
|
|
||||||
def report_on_transactions(transactions):
|
def report_on_transactions(transactions, verbose=False):
|
||||||
"""Print a formatted list of transactions."""
|
"""Print a formatted list of transactions."""
|
||||||
for t in transactions:
|
for t in transactions:
|
||||||
transaction_info = t['transaction_info']
|
transaction_info = t['transaction_info']
|
||||||
|
@ -270,6 +294,8 @@ def report_on_transactions(transactions):
|
||||||
transaction_info['paypal_reference_id'],
|
transaction_info['paypal_reference_id'],
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
if verbose:
|
||||||
|
pprint.pprint(t)
|
||||||
else:
|
else:
|
||||||
print(
|
print(
|
||||||
f'Skipping transaction {transaction_info["transaction_id"]} with no PayPal Reference ID.',
|
f'Skipping transaction {transaction_info["transaction_id"]} with no PayPal Reference ID.',
|
||||||
|
@ -317,3 +343,7 @@ def suspend_subscriptions_interactively(transactions, pattern, access_token):
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
main()
|
main()
|
||||||
|
|
||||||
|
# Local Variables:
|
||||||
|
# fill-column: 80
|
||||||
|
# End:
|
||||||
|
|
Loading…
Add table
Reference in a new issue