Beispiel #1
0
def get_ContactID(code = None):
    if code is None:
        url = 'https://api.xero.com/api.xro/2.0/Contacts'        
        contacts = utils.xero_get(url)
    else:
        # https://developer.xero.com/documentation/api/contacts#optimised-queryparameters
        url = f'https://api.xero.com/api.xro/2.0/Contacts?where=AccountNumber=="{code}"'
        contacts = utils.xero_get(url)
        if len(contacts['Contacts'])>0:
            return contacts['Contacts'][0]['ContactID']
        else:
            return None
Beispiel #2
0
def get_Xero_Contacts():
    has_more_pages = True
    page = 0
    contacts = []
    _contacts = {}
    # Go through pages (100 per page)
    while has_more_pages:
        page += 1
        print(f"{Fore.YELLOW}  Processing Page {page} of contacts...")
        url = f'https://api.xero.com/api.xro/2.0/Contacts?summaryOnly=True&page={page}'
        xero_contacts = utils.xero_get(url)
        if len(xero_contacts["Contacts"]) == 0:
            has_more_pages = False
        else:
            _contacts = [
                {
                    "memberCode":
                    _contact['AccountNumber'],
                    "Name":
                    _contact['FirstName'] + ' ' +
                    _contact['LastName'] if 'LastName' in _contact else '',
                    "ContactID":
                    _contact['ContactID']
                } for _contact in xero_contacts['Contacts']
                if ('AccountNumber' in _contact
                    # Exclude other contacts who have account numbers
                    and len(_contact['AccountNumber']) == 4 and
                    _contact['ContactStatus'] == 'ACTIVE')
            ]
            contacts.extend(_contacts)
    return contacts
def get_last_subscription_amount_by_contact_id(contact_id):
    list_last_invoice = []
    list_of_invoices = []
    list_of_invoices = utils.xero_get(
        f"https://api.xero.com/api.xro/2.0/Invoices?ContactIDs={contact_id}&Statuses=AUTHORISED,PAID"
    )
    if len(list_of_invoices["Invoices"]) > 0:
        # Get latest subscription amount
        list_last_invoice = [
            x for x in list_of_invoices["Invoices"]
            if x["InvoiceNumber"].startswith(
                SEARCH_STRING_FOR_PREVIOUS_SUBSCRIPTION)
        ]
        if len(list_last_invoice) == 1:
            return list_last_invoice[0]["Total"]
        elif len(list_last_invoice) == 0:
            utils.my_logger.warn(
                f"{member_code} has no previous subscription for '{SEARCH_STRING_FOR_PREVIOUS_SUBSCRIPTION}-*'; Skipping"
            )
            return None
        elif len(list_last_invoice) > 1:
            utils.my_logger.warn(
                f"{member_code} has more than one subscription for '{SEARCH_STRING_FOR_PREVIOUS_SUBSCRIPTION}-*'; setting to 0"
            )
            return 0
    else:
        utils.my_logger.warn(f"No Invoices found for {member_code}")
        return None
Beispiel #4
0
def get_member_txns(since_date):
    print(
        color(f"\nProcessing Member Transactions\n================",
              Colors.blue))
    _member_txns = {}
    for bank_account in bank_accounts.items():
        # Reset page counter for each account (DBS, NETS etc.)
        has_more_pages = True
        page = 0

        # Go through pages (100 txns per page)
        while has_more_pages:
            page += 1
            # This endpoint does not return payments applied to invoices, expense claims or transfers between bank accounts.
            url = f'https://api.xero.com/api.xro/2.0/BankTransactions?where=BankAccount.Code=="{bank_account[1]}"&page={page}'
            _header = {'If-Modified-Since': since_date}
            txns = utils.xero_get(url, **_header)
            if len(txns['BankTransactions']) == 0:
                has_more_pages = False
            else:
                print(
                    color(f"Processing {bank_account[0]}. Page {page}",
                          Colors.blue))
                # Keep only "Type":"RECEIVE" & construct a dict via Python List Comprehension
                _receive_txns = [
                    {
                        # Build the output item
                        "ContactID": _txn['Contact']['ContactID'],
                        "ContactName": _txn['Contact']['Name'],
                        "BankAccount": _txn['BankAccount']['Name'],
                        # "Year": _txn['DateString'].split('-')[0],
                        "Year": str(utils.parse_Xero_Date(_txn['Date']).year),
                        # Nested dict
                        "Line Items": _txn['LineItems'],
                        "Net Amount": _txn['Total'],
                        "Status": _txn['Status']
                    } for _txn in txns['BankTransactions'] if (
                        # Only those tnxs that are payments to STOSC
                        _txn['Type'] == 'RECEIVE' and _txn['Status'] ==
                        'AUTHORISED' and _txn['IsReconciled'] == True)
                ]
                receive_txns.extend(_receive_txns)

    return receive_txns
Beispiel #5
0
def get_member_invoice_payments(since_date):
    print(
        color(f"Processing Member Subscriptions\n================",
              Colors.blue))
    has_more_pages = True
    page = 0

    # Go through pages (100 txns per page)
    while has_more_pages:
        page += 1
        # This endpoint does not return payments applied to invoices, expense claims or transfers between bank accounts.
        url = f'https://api.xero.com/api.xro/2.0/Payments?where=PaymentType="ACCRECPAYMENT"&page={page}'
        _header = {'If-Modified-Since': since_date}
        payments = utils.xero_get(url, **_header)
        if len(payments['Payments']) == 0:
            has_more_pages = False
        else:
            # Keep only "Type":"RECEIVE" & construct a dict via Python List Comprehension
            _receive_payments = [
                {
                    # Build the output item
                    "ContactID":
                    _payments['Invoice']['Contact']['ContactID'],
                    "ContactName":
                    _payments['Invoice']['Contact']['Name'],
                    # We assume any invoices not starting with INV is issued for harvest Festival
                    "AccountCode":
                    '3010'
                    if _payments['Invoice']['InvoiceNumber'].startswith('INV')
                    else '3200',
                    #"Year": _txn['DateString'].split('-')[0],
                    "Year":
                    str(utils.parse_Xero_Date(_payments['Date']).year),
                    "LineAmount":
                    _payments['Amount']
                } for _payments in payments['Payments'] if (
                    # Only those tnxs that are payments to STOSC
                    _payments['Status'] == 'AUTHORISED'
                    and _payments['IsReconciled'] == True)
            ]
            receive_payments.extend(_receive_payments)
    return receive_payments
def get_member_invoice_payments(since_date):
    """
    Get Invoices that are named `INV-20` where 20 represents the year.
    Only check where Invoice status = AUTHORISED,PAID and startswith('INV'). 
    The invoices are checked to see if they were modified at the begining of 
    this year (as they should be when creating new invoices after Jan 1). 
    If this check is not there, we will get all invoices from years past.
    """
    has_more_pages = True
    page = 0

    # Go through pages (100 txns per page)
    while has_more_pages:
        page += 1
        # This endpoint does not return payments applied to invoices, expense claims or transfers between bank accounts.
        url = f'https://api.xero.com/api.xro/2.0/Invoices?page={page}&where=Type=="ACCREC"&Statuses=AUTHORISED,PAID&summaryonly=True'
        _header = {"If-Modified-Since": since_date}
        invoices = utils.xero_get(url, **_header)
        if len(invoices["Invoices"]) == 0:
            has_more_pages = False
        else:
            # Keep only "Type":"RECEIVE" & construct a dict via Python List Comprehension
            _invoices = [
                {
                    # Build the output item
                    "ContactName": _invoice["Contact"]["Name"],
                    "InvoiceNumber": _invoice["InvoiceNumber"],
                    "InvoiceDate":
                    utils.parse_Xero_Date(_invoice["Date"]).date(),
                    "InvoiceYear": "20" + _invoice["InvoiceNumber"][4:][:2],
                    "Total": _invoice["Total"],
                    "AmountDue": _invoice["AmountDue"],
                    "AmountPaid": _invoice["AmountPaid"],
                } for _invoice in invoices["Invoices"] if (
                    # Only Subscription invoices and No Harvest Festival ones
                    _invoice["InvoiceNumber"].startswith("INV"))
            ]
            receive_payments.extend(_invoices)
    print(
        color(f"Processed {len(receive_payments)} Subscriptions",
              Colors.orange))
    return receive_payments
        color(f"Did you set NEXT Invoice Numbers? to INV-22-001? ",
              Colors.red))
    sys.exit(0)

utils.my_logger.info(f"Processing Member Subscriptions\n================",
                     Colors.blue)
has_more_pages = True
page = 0

# Go through pages (100 txns per page)
while has_more_pages:
    page += 1
    # This endpoint does not return payments applied to invoices, expense claims or transfers between bank accounts.
    url = f'https://api.xero.com/api.xro/2.0/Payments?where=PaymentType="ACCRECPAYMENT"&page={page}'
    _header = {'If-Modified-Since': since_date}
    payments = utils.xero_get(url, **_header)
    if len(payments['Payments']) == 0:
        has_more_pages = False
    else:
        for _payments in payments['Payments']:
            # Paid invoices without a Reference will not have the Reference field.
            utils.my_logger.info(
                f"For Invoice {_payments['Invoice']['InvoiceNumber']}. [https://invoicing.xero.com/view/{_payments['Invoice']['InvoiceID']}]"
            )
            if _payments['Status'] == 'AUTHORISED' and _payments[
                    'Reference'] == '':
                if _payments['Invoice']['InvoiceNumber'].startswith('INV-21'):
                    updateInvoiceReference('Subscription 2021')
                elif _payments['Invoice']['InvoiceNumber'].startswith(
                        'INV-20'):
                    updateInvoiceReference('Subscription 2020')
Beispiel #8
0
import requests
import utils
# https://github.com/CodeForeverAndEver/ColorIt
from colorit import *

# Use this to ensure that ColorIt will be usable by certain command line interfaces
init_colorit()

def filter_journal(_journals):
    for _journal in _journals['Journals']:
        print(f"\nSource Type: {_journal['SourceType']}")
        for journal_line in _journal['JournalLines']:
            print(f"Account Type: {journal_line['AccountType']} towards {journal_line['AccountName']} ({journal_line['AccountCode']}) the amount {journal_line['NetAmount']}")            
    return _journals

def save_journals(_journals):    
    print("Saved")    

url = f"https://api.xero.com/api.xro/2.0/Journals"
# Get Invoices Created only this year 
_header = {'If-Modified-Since': utils.year_start()}
journals = utils.xero_get(url,**_header)

filtered_journals = filter_journal(journals)

save_journals(filtered_journals)

print("DONE")
def get_member_txns(since_date):

    print(color(f"\nProcessing Member Transactions\n================", Colors.blue))
    _member_txns = {}
    for bank_account in bank_accounts.items():
        # Reset page counter for each account (DBS, NETS etc.)
        has_more_pages = True
        page = 0

        # Go through pages (100 txns per page)
        while has_more_pages:
            page += 1
            # This endpoint does not return payments applied to invoices, expense claims or transfers between bank accounts.
            url = f'https://api.xero.com/api.xro/2.0/BankTransactions?where=BankAccount.Code=="{bank_account[1]}"&page={page}'
            _header = {"If-Modified-Since": since_date}
            txns = utils.xero_get(url, **_header)
            if len(txns["BankTransactions"]) == 0:
                has_more_pages = False
            else:
                print(color(f"Processing {bank_account[0]}. Page {page}", Colors.blue))
                # Keep only "Type":"RECEIVE" & construct a dict via Python List Comprehension
                _receive_txns = [
                    {
                        # Build the output item
                        "ContactID": _txn["Contact"]["ContactID"],
                        "ContactName": _txn["Contact"]["Name"],
                        "BankAccount": _txn["BankAccount"]["Name"],
                        # "Year": _txn['DateString'].split('-')[0],
                        "Year": str(utils.parse_Xero_Date(_txn["Date"]).year),
                        # Nested dict
                        "Line Items": _txn["LineItems"],
                        "Net Amount": _txn["Total"],
                        "Status": _txn["Status"],
                    }
                    for _txn in txns["BankTransactions"]
                    if (
                        # Only those tnxs that are payments to STOSC
                        _txn["Type"] == "RECEIVE"
                        and _txn["Status"] == "AUTHORISED"
                        and _txn["IsReconciled"] == True
                    )
                ]
                receive_txns.extend(_receive_txns)

                # Track accounts of interest
                for _txn in txns["BankTransactions"]:
                    if (
                        # Only those tnxs that are payments to STOSC
                        _txn["Type"] == "RECEIVE"
                        and _txn["Status"] == "AUTHORISED"
                        and _txn["IsReconciled"] == True
                    ):
                        # Build the member payments matrix
                        _receive_txns1 = {
                            # Build the output item
                            "ContactID": _txn["Contact"]["ContactID"],
                            "ContactName": _txn["Contact"]["Name"],
                            "BankAccount": _txn["BankAccount"]["Name"],
                            # "Year": _txn['DateString'].split('-')[0],
                            "Year": str(utils.parse_Xero_Date(_txn["Date"]).year),
                            # Nested dict
                            "Line Items": _txn["LineItems"],
                            "Net Amount": _txn["Total"],
                            "Status": _txn["Status"],
                        }
                        # Loop through each line item and see if it matches any "accounts of interest"
                        for lineItem in _txn["LineItems"]:
                            for account in accounts_of_interest:
                                if (
                                    account["AccountCode"] == lineItem["AccountCode"]
                                    and account["keyword"].upper() in lineItem["Description"].upper()
                                ):
                                    # Update Total
                                    account['Total'] += Decimal(lineItem["LineAmount"])
                                    account["modfied_ts"] = datetime.now().strftime("%d/%m/%Y %H:%M:%S")

    return receive_txns
Beispiel #10
0
            return None

contacts = open("contacts.txt", "r")
contacts = ['B030']

# For each member ID
for _contact in contacts1:
    print(color(f"Processing {_contact[:4]}",Colors.white))
    _contactID = get_ContactID(_contact[:4])
    if _contactID:

        # Get all Invoices for this contact 
        url = f"https://api.xero.com/api.xro/2.0/Invoices?ContactIDs={_contactID}&Statuses=AUTHORISED"
        # Get Invoices Created only this year 
        _header = {'If-Modified-Since': utils.year_start()}
        invoices = utils.xero_get(url,**_header)

        for invoice in invoices['Invoices']:
            print(color(f"Customer ID: {_contact}",Colors.purple))

            # Only for FY 21 invoices
            if invoice['InvoiceNumber'].startswith('INV-21'):
                if invoice['Status'] == 'AUTHORISED':
                    # 01. Rename the invoice
                    new_invoice_data = {}
                    contact = {}
                    lineItems = {}
                    
                    lineItems['LineItemID'] = invoice['LineItems'][0]['LineItemID']
                    lineItems['Description'] = "Subscription 2021"
                    lineItems['Quantity'] = 1.0