sqlExport: Merge the logic of members and transactions tables, w/ mappings defined in yaml

This commit is contained in:
Adam Goldsmith 2020-02-15 12:08:34 -05:00
parent 38ba551f1e
commit 8b54dc7fe3
2 changed files with 107 additions and 125 deletions

View File

@ -2,6 +2,7 @@
from datetime import datetime from datetime import datetime
import sqlite3 import sqlite3
import yaml
#from common import membershipworks #from common import membershipworks
@ -11,92 +12,21 @@ from passwords import MEMBERSHIPWORKS_USERNAME, MEMBERSHIPWORKS_PASSWORD
membershipworks = MembershipWorks() membershipworks = MembershipWorks()
membershipworks.login(MEMBERSHIPWORKS_USERNAME, MEMBERSHIPWORKS_PASSWORD) membershipworks.login(MEMBERSHIPWORKS_USERNAME, MEMBERSHIPWORKS_PASSWORD)
membersTableColumns = { def insertFromTableMap(table, data, tableMap):
'uid': {'type': 'TEXT PRIMARY KEY', 'label': 'Account ID'}, def formatRows(data):
'Year of Birth': {}, for d in data:
'Account Name': {},
'First Name': {},
'Last Name': {},
'Phone': {},
'Email': {},
'Address (Street)': {},
'Address (City)': {},
'Address (State/Province)': {},
'Address (Postal Code)': {},
'Address (Country)': {},
'Profile description': {},
'Website': {},
'Fax': {},
'Contact Person': {},
'Password': {},
'Position/relation': {},
'Parent Account ID': {},
'Gift Membership purchased by': {},
'Purchased Gift Membership for': {},
'Closet Storage #': {},
'Storage Shelf #': {},
'Personal Studio Space #': {},
'Access Permitted Shops During Extended Hours?': {'type': 'BOOLEAN'},
'Access Front Door and Studio Space During Extended Hours?': {'type': 'BOOLEAN'},
'Access Wood Shop?': {'type': 'BOOLEAN'},
'Access Metal Shop?': {'type': 'BOOLEAN'},
'Access Storage Closet?': {'type': 'BOOLEAN'},
'Access Studio Space?': {'type': 'BOOLEAN'},
'Access Front Door?': {'type': 'BOOLEAN'},
'Access Card Number': {'type': 'INTEGER'},
'Access Card Facility Code': {'type': 'INTEGER'},
'Auto Billing ID': {},
'Billing Method': {},
'Renewal Date': {},
'Join Date': {},
'Admin note': {},
'Profile gallery image URL': {},
'Business card image URL': {},
'Instagram': {},
'Pinterest': {},
'Youtube': {},
'Yelp': {},
'Google+': {},
'BBB': {},
'Twitter': {},
'Facebook': {},
'LinkedIn': {},
'Do not show street address in profile': {},
'Do not list in directory': {},
'Please tell us how you heard about the Claremont MakerSpace and what tools or shops you are most excited to start using:': {},
'Yes - I authorize TwinState MakerSpaces, Inc. to charge my credit card for the membership and other options that I have selected.': {},
'I have read the Claremont MakerSpace Membership Agreement & Policies, and agree to all terms stated therein.': {},
'Waiver form signed and on file date.': {},
'Membership Agreement signed and on file date.': {},
'IP Address': {},
}
def insertMembers(members):
def formatMembers(members):
for m in members:
yield [ yield [
m[v.get('label', k)] for k, v in membersTableColumns.items() d.get(v.get('source', k) if v is not None else k) for k, v in tableMap.items()
] ]
c.execute('BEGIN') c.execute('BEGIN')
# NOTE: this only works if in python >= 3.7 where `dict` is ordered # NOTE: this only works if in python >= 3.7 where `dict` is ordered
c.executemany('INSERT OR REPLACE INTO members (' + c.executemany('INSERT OR REPLACE INTO ' + table + ' (' +
','.join('"' + k + '"' for k in membersTableColumns.keys()) + ','.join('"' + k + '"' for k in tableMap.keys()) +
') values (' + ') values (' +
','.join(len(membersTableColumns) * '?') + ','.join(len(tableMap) * '?') +
');', ');',
list(formatMembers(members))) list(formatRows(data)))
c.execute('END') c.execute('END')
def insertLabels(members): def insertLabels(members):
@ -111,59 +41,30 @@ def insertLabels(members):
list(formatLabels(members))) list(formatLabels(members)))
c.execute('END') c.execute('END')
def insertTransactions(transactions): with open('tableMapping.yaml') as f:
def formatTransactions(transactions): tableMapping = yaml.load(f, yaml.SafeLoader)
for t in transactions:
yield [
t["sid"],
t["_dp"], # timestamp
t["typ"], # type
t["cur"], # currency
t["sum"],
t.get("fee"),
t["uid"],
t["nam"], # name
t.get("eid"), # event_id
t.get("ttl") # "For"
]
c.execute('BEGIN')
c.executemany('INSERT OR REPLACE INTO transactions (sid, timestamp, type, currency, sum, fee, uid, name, event_id, ttl) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?);',
list(formatTransactions(transactions)))
c.execute('END')
with sqlite3.connect('membershipworks.db') as conn: with sqlite3.connect('membershipworks.db') as conn:
c = conn.cursor() c = conn.cursor()
c.execute('CREATE TABLE IF NOT EXISTS members (' + c.execute('CREATE TABLE IF NOT EXISTS members (' +
', '.join([f'"{k}" {v.get("type", "")}' ', '.join([f'"{k}" {v.get("type", "") if v is not None else ""}'
for k, v in membersTableColumns.items()]) + for k, v in tableMapping['members'].items()]) +
')') ');')
c.execute("""CREATE TABLE IF NOT EXISTS transactions ( c.execute("CREATE TABLE IF NOT EXISTS transactions (" +
sid TEXT PRIMARY KEY, ', '.join([f'"{k}" {v.get("type", "") if v is not None else ""}'
timestamp INTEGER NOT NULL, for k, v in tableMapping['transactions'].items()]) +
type INTEGER NOT NULL, """, FOREIGN KEY(uid) REFERENCES member(uid)
currency TEXT NOT NULL,
sum INTEGER NOT NULL,
fee INTEGER,
uid TEXT NOT NULL,
name TEXT NOT NULL,
event_id TEXT,
ttl TEXT,
FOREIGN KEY(uid) REFERENCES member(uid)
-- FOREIGN KEY(event_id) REFERENCES event(eid) -- FOREIGN KEY(event_id) REFERENCES event(eid)
); );
""") """)
# TODO: define a pk constraint
c.execute("""CREATE TABLE IF NOT EXISTS labels ( c.execute("""CREATE TABLE IF NOT EXISTS labels (
uid TEXT, label Text, uid TEXT, label Text,
FOREIGN KEY(uid) REFERENCES member(uid), PRIMARY KEY(uid, label),
PRIMARY KEY(uid, label) FOREIGN KEY(uid) REFERENCES member(uid)
); );""")
""")
members = membershipworks.get_all_members() members = membershipworks.get_all_members()
@ -178,10 +79,10 @@ with sqlite3.connect('membershipworks.db') as conn:
if field.get('typ') == 8 and field['lbl'] in m: # check box if field.get('typ') == 8 and field['lbl'] in m: # check box
m[field['lbl']] = True if m[field['lbl']] == 'Y' else False m[field['lbl']] = True if m[field['lbl']] == 'Y' else False
insertMembers(members) insertFromTableMap('members', members, tableMapping['members'])
insertLabels(members) insertLabels(members)
transactions = membershipworks.get_transactions(datetime(2020, 1, 1), datetime.now()) transactions = membershipworks.get_transactions(datetime(2020, 1, 1), datetime.now())
insertTransactions(transactions) insertFromTableMap('transactions', transactions, tableMapping['transactions'])
# TODO: folders, levels, addons # TODO: folders, levels, addons

81
tableMapping.yaml Normal file
View File

@ -0,0 +1,81 @@
members:
'uid': {type: 'TEXT PRIMARY KEY', source: 'Account ID'}
'Year of Birth':
'Account Name':
'First Name':
'Last Name':
'Phone':
'Email':
'Address (Street)':
'Address (City)':
'Address (State/Province)':
'Address (Postal Code)':
'Address (Country)':
'Profile description':
'Website':
'Fax':
'Contact Person':
'Password':
'Position/relation':
'Parent Account ID':
'Gift Membership purchased by':
'Purchased Gift Membership for':
'Closet Storage #':
'Storage Shelf #':
'Personal Studio Space #':
'Access Permitted Shops During Extended Hours?': {type: 'BOOLEAN'}
'Access Front Door and Studio Space During Extended Hours?': {type: 'BOOLEAN'}
'Access Wood Shop?': {type: 'BOOLEAN'}
'Access Metal Shop?': {type: 'BOOLEAN'}
'Access Storage Closet?': {type: 'BOOLEAN'}
'Access Studio Space?': {type: 'BOOLEAN'}
'Access Front Door?': {type: 'BOOLEAN'}
'Access Card Number': {type: 'INTEGER'}
'Access Card Facility Code': {type: 'INTEGER'}
'Auto Billing ID':
'Billing Method':
'Renewal Date':
'Join Date':
'Admin note':
'Profile gallery image URL':
'Business card image URL':
'Instagram':
'Pinterest':
'Youtube':
'Yelp':
'Google+':
'BBB':
'Twitter':
'Facebook':
'LinkedIn':
'Do not show street address in profile':
'Do not list in directory':
'Please tell us how you heard about the Claremont MakerSpace and what tools or shops you are most excited to start using:':
'Yes - I authorize TwinState MakerSpaces, Inc. to charge my credit card for the membership and other options that I have selected.':
'I have read the Claremont MakerSpace Membership Agreement & Policies, and agree to all terms stated therein.':
'Waiver form signed and on file date.':
'Membership Agreement signed and on file date.':
'IP Address':
transactions:
'sid': {type: TEXT PRIMARY KEY}
'timestamp': {type: INTEGER, source: '_dp'}
'type': {type: INTEGER, source: 'typ'} # transaction type
'currency': {source: 'cur'}
'sum': {type: INTEGER}
'fee': {type: INTEGER}
'uid':
'name': {source: 'nam'}
'event_id': {source: 'eid'}
'ttl': # 'For'