def get(self): # HANDLE PARAM : search_stirng - Any search string. An empty string (or None) will just return everything! search_string = request.args.get('search_string') or '' # HANDLE PARAM : params - Standard filter object. Exact same as the ones Metrics uses! encoded_filters = request.args.get('params') filters = process_transfer_filters(encoded_filters) # HANDLE PARAM : order # Valid orders types are: `ASC` and `DESC` # Default: DESC order_arg = request.args.get('order') or 'DESC' if order_arg.upper() not in ['ASC', 'DESC']: return { 'message': 'Invalid order value \'{}\'. Please use \'ASC\' or \'DESC\''.format(order_arg)} order = asc if order_arg.upper()=='ASC' else desc # HANDLE PARAM: sort_by # Valid orders types are: first_name, last_name, email, date_account_created, rank, balance, status # Default: rank sort_by_arg = request.args.get('sort_by') or 'rank' final_query = generate_search_query(search_string, filters, order, sort_by_arg) transfer_accounts, total_items, total_pages, _ = paginate_query(final_query, ignore_last_fetched=True) if AccessControl.has_sufficient_tier(g.user.roles, 'ADMIN', 'admin'): result = transfer_accounts_schema.dump(transfer_accounts) elif AccessControl.has_any_tier(g.user.roles, 'ADMIN'): result = view_transfer_accounts_schema.dump(transfer_accounts) return { 'message': 'Successfully Loaded.', 'items': total_items, 'pages': total_pages, 'query_time': datetime.datetime.utcnow(), 'data': { 'transfer_accounts': result.data } }
def put(self): put_data = request.get_json() # HANDLE PARAM : search_stirng - Any search string. An empty string (or None) will just return everything! search_string = put_data.get('search_string') or '' # HANDLE PARAM : params - Standard filter object. Exact same as the ones Metrics uses! encoded_filters = put_data.get('params') filters = process_transfer_filters(encoded_filters) # HANDLE PARAM : include_accounts - Explicitly include these users include_accounts = put_data.get('include_accounts', []) # HANDLE PARAM : include_accounts - Explicitly exclude these users exclude_accounts = put_data.get('exclude_accounts', []) approve = put_data.get('approve') if include_accounts and exclude_accounts: return { 'message': 'Please either include or exclude users (include is additive from the whole search, while exclude is subtractive)' } order_arg = request.args.get('order') or 'DESC' if order_arg.upper() not in ['ASC', 'DESC']: return { 'message': 'Invalid order value \'{}\'. Please use \'ASC\' or \'DESC\''. format(order_arg) } order = asc if order_arg.upper() == 'ASC' else desc sort_by_arg = request.args.get('sort_by') or 'rank' if include_accounts: transfer_accounts = db.session.query(TransferAccount).filter( TransferAccount.id.in_(include_accounts)).all() else: search_query = generate_search_query(search_string, filters, order, sort_by_arg, include_user=True) search_query = search_query.filter( TransferAccount.id.notin_(exclude_accounts)) results = search_query.all() transfer_accounts = [ r[0] for r in results ] # Get TransferAccount (TransferAccount, searchRank, User) for ta in transfer_accounts: if approve == True: ta.is_approved = True elif approve == False: ta.is_approved = False db.session.commit() response_object = { 'status': 'success', 'message': 'Successfully Edited Transfer Accounts.', } return make_response(jsonify(response_object)), 201
def get(self, credit_transfer_id): transfer_account_ids = request.args.get('transfer_account_ids') # Handle search parameters # HANDLE PARAM : search_string - Any search string. An empty string (or None) will just return everything! search_string = request.args.get('search_string') or '' # HANDLE PARAM : params - Standard filter object. Exact same as the ones Metrics uses! encoded_filters = request.args.get('params') filters = process_transfer_filters(encoded_filters) # HANDLE PARAM : order # Valid orders types are: `ASC` and `DESC` # Default: DESC order_arg = request.args.get('order') or 'DESC' if order_arg.upper() not in ['ASC', 'DESC']: return { 'message': 'Invalid order value \'{}\'. Please use \'ASC\' or \'DESC\''. format(order_arg) } order = asc if order_arg.upper() == 'ASC' else desc # HANDLE PARAM: sort_by # Valid orders types are: first_name, last_name, email, date_account_created, rank, balance, status # Default: rank sort_by_arg = request.args.get('sort_by') or 'rank' if credit_transfer_id: credit_transfer = CreditTransfer.query.get(credit_transfer_id) if credit_transfer is None: return make_response( jsonify({'message': 'Credit transfer not found'})), 404 if AccessControl.has_sufficient_tier(g.user.roles, 'ADMIN', 'admin'): result = credit_transfer_schema.dump(credit_transfer).data elif AccessControl.has_any_tier(g.user.roles, 'ADMIN'): result = view_credit_transfer_schema.dump(credit_transfer).data transfer_stats = [] response_object = { 'status': 'success', 'message': 'Successfully Loaded.', 'data': { 'credit_transfer': result, 'transfer_stats': transfer_stats } } return make_response(jsonify(response_object)), 200 else: if transfer_account_ids: # We're getting a list of transfer accounts - parse try: parsed_transfer_account_ids = list( map(lambda x: int(x), filter(None, transfer_account_ids.split(',')))) except Exception as e: response_object = {'status': 'fail', 'message': str(e)} return make_response(jsonify(response_object)), 400 if parsed_transfer_account_ids: try: query = generate_search_query( search_string, filters, order, sort_by_arg, search_type=CREDIT_TRANSFER) except Exception as e: response_object = {'status': 'fail', 'message': str(e)} return make_response(jsonify(response_object)), 200 final_query = query.filter( or_( CreditTransfer.recipient_transfer_account_id.in_( parsed_transfer_account_ids), CreditTransfer.sender_transfer_account_id.in_( parsed_transfer_account_ids))) credit_transfers, total_items, total_pages, new_last_fetched = paginate_query( final_query, ignore_last_fetched=True) if AccessControl.has_sufficient_tier( g.user.roles, 'ADMIN', 'admin'): result = credit_transfers_schema.dump(credit_transfers) elif AccessControl.has_any_tier(g.user.roles, 'ADMIN'): result = view_credit_transfers_schema.dump( credit_transfers) return { 'status': 'success', 'message': 'Successfully Loaded.', 'items': total_items, 'pages': total_pages, 'last_fetched': new_last_fetched, 'query_time': datetime.datetime.utcnow(), 'data': { 'credit_transfers': result.data } } else: try: final_query = generate_search_query( search_string, filters, order, sort_by_arg, search_type=CREDIT_TRANSFER) except Exception as e: response_object = {'status': 'fail', 'message': str(e)} return make_response(jsonify(response_object)), 200 credit_transfers, total_items, total_pages, new_last_fetched = paginate_query( final_query, ignore_last_fetched=True) if AccessControl.has_sufficient_tier(g.user.roles, 'ADMIN', 'admin'): result = credit_transfers_schema.dump(credit_transfers) elif AccessControl.has_any_tier(g.user.roles, 'ADMIN'): result = view_credit_transfers_schema.dump(credit_transfers) return { 'status': 'success', 'message': 'Successfully Loaded.', 'items': total_items, 'pages': total_pages, 'last_fetched': new_last_fetched, 'query_time': datetime.datetime.utcnow(), 'data': { 'credit_transfers': result.data } }
def get(self, transfer_account_id): account_type_filter = request.args.get('account_type') result = None if transfer_account_id: transfer_account = TransferAccount.query.get(transfer_account_id) if transfer_account is None: response_object = { 'message': 'No such transfer account: {}'.format(transfer_account_id), } return make_response(jsonify(response_object)), 400 if AccessControl.has_sufficient_tier(g.user.roles, 'ADMIN', 'admin'): result = transfer_account_schema.dump(transfer_account) elif AccessControl.has_any_tier(g.user.roles, 'ADMIN'): result = view_transfer_account_schema.dump(transfer_account) response_object = { 'message': 'Successfully Loaded.', 'data': { 'transfer_account': result.data, } } return make_response(jsonify(response_object)), 201 else: search_string = request.args.get('search_string') or '' # HANDLE PARAM : params - Standard filter object. Exact same as the ones Metrics uses! encoded_filters = request.args.get('params') filters = process_transfer_filters(encoded_filters) # HANDLE PARAM : order # Valid orders types are: `ASC` and `DESC` # Default: DESC order_arg = request.args.get('order') or 'DESC' if order_arg.upper() not in ['ASC', 'DESC']: return { 'message': 'Invalid order value \'{}\'. Please use \'ASC\' or \'DESC\'' .format(order_arg) } order = asc if order_arg.upper() == 'ASC' else desc # HANDLE PARAM: sort_by # Valid orders types are: first_name, last_name, email, date_account_created, rank, balance, status # Default: rank sort_by_arg = request.args.get('sort_by') or 'rank' base_query = generate_search_query( search_string, filters, order, sort_by_arg).filter(TransferAccount.is_ghost != True) if account_type_filter == 'vendor': transfer_accounts_query = base_query.filter_by(is_vendor=True) elif account_type_filter == 'beneficiary': transfer_accounts_query = base_query.filter_by( is_beneficiary=True) else: pass # Filter Contract, Float and Organisation Transfer Accounts transfer_accounts_query = (base_query.filter( TransferAccount.account_type == TransferAccountType.USER)) transfer_accounts, total_items, total_pages, new_last_fetched = paginate_query( transfer_accounts_query) if transfer_accounts is None: response_object = { 'message': 'No transfer accounts', } return make_response(jsonify(response_object)), 400 if AccessControl.has_sufficient_tier(g.user.roles, 'ADMIN', 'admin'): result = transfer_accounts_schema.dump(transfer_accounts) elif AccessControl.has_any_tier(g.user.roles, 'ADMIN'): result = view_transfer_accounts_schema.dump(transfer_accounts) response_object = { 'message': 'Successfully Loaded.', 'items': total_items, 'pages': total_pages, 'last_fetched': new_last_fetched, 'query_time': datetime.datetime.utcnow().strftime("%m/%d/%Y, %H:%M:%S"), 'data': { 'transfer_accounts': result.data } } return make_response(json.dumps(response_object), 200)
def post(self): post_data = request.get_json() # --- Handle Parameters --- # HANDLE PARAM : label - Name for the disbursement label = post_data.get('label') or '' # HANDLE PARAM : search_string - Any search string. An empty string (or None) will just return everything! search_string = post_data.get('search_string') or '' # HANDLE PARAM : params - Standard filter object. Exact same as the ones Metrics uses! encoded_filters = post_data.get('params') filters = process_transfer_filters(encoded_filters) # HANDLE PARAM : include_accounts - Explicitly include these users include_accounts = post_data.get('include_accounts', []) # HANDLE PARAM : include_accounts - Explicitly exclude these users exclude_accounts = post_data.get('exclude_accounts', []) disbursement_amount = abs( round(Decimal(post_data.get('disbursement_amount') or 0), 6)) if include_accounts and exclude_accounts: return { 'message': 'Please either include or exclude users (include is additive from the whole search, while exclude is subtractive)' } # HANDLE PARAM : transfer_type - Transfer type-- either DISBURSEMENT, RECLAMATION, or BALANCE transfer_type = post_data.get('transfer_type', 'DISBURSEMENT') if transfer_type not in ['DISBURSEMENT', 'RECLAMATION', 'BALANCE']: return { 'message': f'{transfer_type} not a valid transfer type. Please choose one of DISBURSEMENT, RECLAMATION, or BALANCE' } order_arg = request.args.get('order') or 'DESC' if order_arg.upper() not in ['ASC', 'DESC']: return { 'message': 'Invalid order value \'{}\'. Please use \'ASC\' or \'DESC\''. format(order_arg) } order = asc if order_arg.upper() == 'ASC' else desc sort_by_arg = request.args.get('sort_by') or 'rank' # --- Build Disbursement Object --- d = Disbursement(creator_user=g.user, label=label, search_string=search_string, search_filter_params=encoded_filters, include_accounts=include_accounts, exclude_accounts=exclude_accounts, disbursement_amount=disbursement_amount, transfer_type=transfer_type) if include_accounts: transfer_accounts = db.session.query(TransferAccount).filter( TransferAccount.id.in_(include_accounts)).all() else: search_query = generate_search_query(search_string, filters, order, sort_by_arg, include_user=True) search_query = search_query.filter( TransferAccount.id.notin_(exclude_accounts)) results = search_query.all() transfer_accounts = [ r[0] for r in results ] # Get TransferAccount (TransferAccount, searchRank, User) d.transfer_accounts.extend(transfer_accounts) db.session.flush() disbursement = disbursement_schema.dump(d).data response_object = { 'data': { 'status': 'success', 'disbursement': disbursement } } return make_response(jsonify(response_object)), 201
def generate_export(post_data): from server.models.credit_transfer import CreditTransfer from server.models.transfer_account import TransferAccount from server.models.user import User export_type = post_data.get('export_type') include_transfers = post_data.get('include_transfers') # True or False include_custom_attributes = post_data.get( 'include_custom_attributes') # True or False user_type = post_data.get('user_type') # Beneficiaries, Vendors, All # TODO: implement date_range date_range = post_data.get('date_range') # last day, previous week, or all payable_period_type = post_data.get('payable_period_type', 'month') # day, week, month payable_period_length = post_data.get( 'payable_period_length', 1) # Integer, ie "payable every _2_ months" payable_epoch = post_data.get( 'payable_epoch') # When did the very first cycle begin? payable_period_start_date = post_data.get( 'payable_period_start_date' ) # any sort of reasonable date string for custom date period payable_period_end_date = post_data.get('payable_period_end_date') transfer_account_columns = [ { 'header': 'Account ID', 'query_type': 'db', 'query': 'id' }, { 'header': 'User ID', 'query_type': 'custom', 'query': 'user_id' }, { 'header': 'First Name', 'query_type': 'custom', 'query': 'first_name' }, { 'header': 'Last Name', 'query_type': 'custom', 'query': 'last_name' }, { 'header': 'Public Serial Number', 'query_type': 'custom', 'query': 'public_serial_number' }, { 'header': 'Phone', 'query_type': 'custom', 'query': 'phone' }, { 'header': 'Created (UTC)', 'query_type': 'db', 'query': 'created' }, { 'header': 'Approved', 'query_type': 'db', 'query': 'is_approved' }, { 'header': 'Beneficiary', 'query_type': 'custom', 'query': 'has_beneficiary_role' }, { 'header': 'Vendor', 'query_type': 'custom', 'query': 'has_vendor_role' }, { 'header': 'Location', 'query_type': 'custom', 'query': 'location' }, { 'header': 'Current Balance', 'query_type': 'custom', 'query': 'balance' }, { 'header': 'Amount Received', 'query_type': 'custom', 'query': 'received' }, { 'header': 'Amount Sent', 'query_type': 'custom', 'query': 'sent' } # {'header': 'Prev. Period Payable', 'query_type': 'custom', 'query': 'prev_period_payable'}, # {'header': 'Total Payable', 'query_type': 'custom', 'query': 'total_payable'}, ] credit_transfer_columns = [ { 'header': 'ID', 'query_type': 'db', 'query': 'id' }, { 'header': 'Transfer Amount', 'query_type': 'custom', 'query': 'transfer_amount' }, { 'header': 'Created', 'query_type': 'db', 'query': 'created' }, { 'header': 'Resolved Date', 'query_type': 'db', 'query': 'resolved_date' }, { 'header': 'Transfer Type', 'query_type': 'enum', 'query': 'transfer_type' }, { 'header': 'Transfer Type', 'query_type': 'enum', 'query': 'transfer_subtype' }, { 'header': 'Transfer Status', 'query_type': 'enum', 'query': 'transfer_status' }, { 'header': 'Sender ID', 'query_type': 'db', 'query': 'sender_transfer_account_id' }, { 'header': 'Recipient ID', 'query_type': 'db', 'query': 'recipient_transfer_account_id' }, { 'header': 'Transfer Uses', 'query_type': 'custom', 'query': 'transfer_usages' }, ] # need to add Balance (Payable) random_string = ''.join(random.choices(string.ascii_letters, k=5)) # TODO MAKE THIS API AUTHED time = str(datetime.utcnow()) base_filename = current_app.config['DEPLOYMENT_NAME'] + '-id' + str( g.user.id) + '-' + str(time[0:10]) + '-' + random_string workbook_filename = base_filename + '.xlsx' # e.g. dev-id1-2018-09-19-asfi.xlsx pdf_filename = base_filename + '.pdf' wb = Workbook() ws = wb.new_sheet("transfer_accounts") # ws1 = wb.create_sheet(title='transfer_accounts') start_date = None end_date = None user_filter = None for index, column in enumerate(transfer_account_columns): ws[1][index + 1] = column['header'] # Create transfer_accounts workbook headers for index, column in enumerate(transfer_account_columns): ws[1][index + 1] = column['header'] user_accounts = [] credit_transfer_list = [] # filter user accounts if user_type == 'beneficiary': user_filter = User.has_beneficiary_role if user_type == 'vendor': user_filter = User.has_vendor_role if date_range == 'all': end_date = datetime.utcnow() start_date = end_date - timedelta(weeks=520) if date_range == 'day': # return previous day of transactions end_date = datetime.utcnow() start_date = end_date - timedelta(days=1) if date_range == 'week': # return previous week of transactions end_date = datetime.utcnow() start_date = end_date - timedelta(weeks=1) if user_filter is not None: user_accounts = User.query.filter(user_filter == True).options( joinedload(User.transfer_accounts)) user_accounts = partition_query(user_accounts) elif user_type == 'selected': # HANDLE PARAM : search_string - Any search string. An empty string (or None) will just return everything! search_string = post_data.get('search_string') or '' # HANDLE PARAM : params - Standard filter object. Exact same as the ones Metrics uses! encoded_filters = post_data.get('params') filters = process_transfer_filters(encoded_filters) # HANDLE PARAM : include_accounts - Explicitly include these users include_accounts = post_data.get('include_accounts', []) # HANDLE PARAM : include_accounts - Explicitly exclude these users exclude_accounts = post_data.get('exclude_accounts', []) if include_accounts: transfer_accounts = db.session.query( TransferAccount).options().filter( TransferAccount.id.in_(include_accounts)) transfer_accounts = partition_query(transfer_accounts) else: search_query = generate_search_query(search_string, filters, order=desc, sort_by_arg='rank', include_user=True) search_query = search_query.filter( TransferAccount.id.notin_(exclude_accounts)) results = partition_query(search_query) transfer_accounts = [ r[0] for r in results ] # Get TransferAccount (TransferAccount, searchRank, User) user_accounts = [ta.primary_user for ta in transfer_accounts] else: user_accounts = User.query.filter( or_(User.has_beneficiary_role == True, User.has_vendor_role == True)).options( joinedload(User.transfer_accounts)) user_accounts = partition_query(user_accounts) if export_type == 'pdf': file_url = generate_pdf_export(user_accounts, pdf_filename) response_object = { 'message': 'Export file created.', 'data': { 'file_url': file_url, } } return make_response(jsonify(response_object)), 201 if user_accounts is not None: custom_attribute_columns = [] for index, user_account in enumerate(user_accounts): transfer_account = user_account.transfer_account if transfer_account: for jindix, column in enumerate(transfer_account_columns): if column['query_type'] == 'db': cell_contents = "{0}".format( getattr(transfer_account, column['query'])) elif column['query'] == 'user_id': cell_contents = "{0}".format( transfer_account.primary_user.id) elif column['query'] == 'first_name': cell_contents = "{0}".format( transfer_account.primary_user.first_name) elif column['query'] == 'last_name': cell_contents = "{0}".format( transfer_account.primary_user.last_name) elif column['query'] == 'phone': cell_contents = "{0}".format( transfer_account.primary_user.phone or '') elif column['query'] == 'public_serial_number': cell_contents = "{0}".format( transfer_account.primary_user.public_serial_number or '') elif column['query'] == 'location': cell_contents = "{0}".format( transfer_account.primary_user._location) elif column['query'] == 'balance': cell_contents = getattr(transfer_account, column['query']) / 100 elif column['query'] == 'has_beneficiary_role': cell_contents = "{0}".format( transfer_account.primary_user.has_beneficiary_role) elif column['query'] == 'has_vendor_role': cell_contents = "{0}".format( transfer_account.primary_user.has_vendor_role) elif column['query'] == 'received': received_amount = transfer_account.total_received cell_contents = received_amount / 100 elif column['query'] == 'sent': sent_amount = transfer_account.total_sent cell_contents = sent_amount / 100 elif column['query'] == 'prev_period_payable': if payable_period_start_date and payable_period_end_date: prior_period_start = parser.parse( payable_period_start_date) prior_period_end = parser.parse( payable_period_end_date) else: if payable_epoch is None: payable_epoch = transfer_account.created else: payable_epoch = parser.parse( str(payable_epoch)) prior_period_start, prior_period_end = find_last_period_dates( payable_epoch, datetime.utcnow(), payable_period_type, payable_period_length) in_for_period = 0 # All funds start of last period, up to end of last period, NOT including after last period in_transactions = CreditTransfer.query.filter( and_( CreditTransfer.recipient_transfer_account_id == transfer_account.id, CreditTransfer.transfer_status == TransferStatusEnum.COMPLETE, CreditTransfer.resolved_date.between( prior_period_start, prior_period_end))) in_transactions = partition_query(in_transactions) for transaction in in_transactions: in_for_period += transaction.transfer_amount out_for_period = 0 # Out transactions DO NOT include reimbursements (withdrawals) from the previous month out_transactions = CreditTransfer.query.filter( and_( CreditTransfer.sender_transfer_account_id == transfer_account.id, CreditTransfer.transfer_status == TransferStatusEnum.COMPLETE, CreditTransfer.resolved_date.between( prior_period_start, prior_period_end), CreditTransfer.transfer_type != TransferTypeEnum.WITHDRAWAL)) out_transactions = partition_query(out_transactions) for transaction in out_transactions: out_for_period += transaction.transfer_amount payable_balance = in_for_period - out_for_period cell_contents = payable_balance / 100 elif column['query'] == 'total_payable': if payable_period_end_date: prior_period_end = parser.parse( payable_period_end_date) else: if payable_epoch is None: payable_epoch = transfer_account.created else: payable_epoch = parser.parse( str(payable_epoch)) prior_period_start, prior_period_end = find_last_period_dates( payable_epoch, datetime.utcnow(), payable_period_type, payable_period_length) in_for_period = 0 # All funds in from epoch, up to end of last period, NOT including after last period in_transactions = CreditTransfer.query.filter( and_( CreditTransfer.recipient_transfer_account_id == transfer_account.id, CreditTransfer.transfer_status == TransferStatusEnum.COMPLETE, CreditTransfer.resolved_date.between( payable_epoch, prior_period_end))) in_transactions = partition_query(in_transactions) for transaction in in_transactions: in_for_period += transaction.transfer_amount out_for_period = 0 # All funds out over all time, _including_ withdrawals out_transactions = CreditTransfer.query.filter( and_( CreditTransfer.sender_transfer_account_id == transfer_account.id, CreditTransfer.transfer_status == TransferStatusEnum.COMPLETE, CreditTransfer.resolved_date.between( payable_epoch, datetime.utcnow()))) out_transactions = partition_query(out_transactions) for transaction in out_transactions: out_for_period += transaction.transfer_amount payable_balance = in_for_period - out_for_period cell_contents = payable_balance / 100 else: cell_contents = "" ws[index + 2][jindix + 1] = cell_contents if include_custom_attributes: # Add custom attributes as columns at the end for attribute in transfer_account.primary_user.custom_attributes: name = (attribute.custom_attribute and attribute.custom_attribute.name) or ' ' try: col_num = custom_attribute_columns.index( name) + 1 + len(transfer_account_columns) except ValueError: custom_attribute_columns.append(name) col_num = len(custom_attribute_columns) + len( transfer_account_columns) ws[index + 2][col_num] = attribute.value else: print('No Transfer Account for user account id: ', user_account.id) # Add custom attribute headers: if include_custom_attributes: for index, column_name in enumerate(custom_attribute_columns): ws[1][index + 1 + len(transfer_account_columns)] = column_name if include_transfers and user_accounts is not None: base_credit_transfer_query = CreditTransfer.query.enable_eagerloads( False) if start_date and end_date is not None: credit_transfer_list = base_credit_transfer_query.filter( CreditTransfer.created.between(start_date, end_date)) if date_range == 'all': credit_transfer_list = base_credit_transfer_query credit_transfer_list = partition_query(credit_transfer_list) transfer_sheet = wb.new_sheet("credit_transfers") # Create credit_transfers workbook headers for index, column in enumerate(credit_transfer_columns): transfer_sheet[1][index + 1] = column['header'] if credit_transfer_list is not None: for index, credit_transfer in enumerate(credit_transfer_list): for jindix, column in enumerate(credit_transfer_columns): if column['query_type'] == 'db': cell_contents = "{0}".format( getattr(credit_transfer, column['query'])) elif column['query_type'] == 'enum': enum = getattr(credit_transfer, column['query']) cell_contents = "{0}".format(enum and enum.value) elif column['query'] == 'transfer_amount': cell_contents = "{0}".format( getattr(credit_transfer, column['query']) / 100) elif column['query'] == 'transfer_usages': cell_contents = ', '.join([ usage.name for usage in credit_transfer.transfer_usages ]) else: cell_contents = "" transfer_sheet[index + 2][jindix + 1] = cell_contents else: print('No Credit Transfers') file_url = export_workbook_via_s3(wb, workbook_filename) response_object = { 'message': 'Export file created.', 'data': { 'file_url': file_url, } } return make_response(jsonify(response_object)), 201