DEV Community

Alexandr K
Alexandr K

Posted on

3 3

Build invoices based on Wunderlist

The last 8 years I am working on contracts on remote and for the clients that are charging by hours, it would require to send invoices hourly every 2 weeks. I was trying to use the different applications for invoicing but then moved away and used google docs to build it.

Then I found Wunderlist, nice todo list application. I created Shopping and TODO lists and started to use daily. as result it became like a habit for me to write there. I decided that it would be awesome to track my hours there as well.

Example format for task hours:

<hours> hours TASK-1
<minutes> minutes TASK-2
<days> days TASK-3
Enter fullscreen mode Exit fullscreen mode

After month I decided to download this list and calculate hours that spent for the month. As result I did the script for downloading the hours report into csv file.

import wunderpy2


from dateutil import parser
from datetime import date
from csv import writer


ACCESS_TOKEN = '<WUNDERLIST_ACCESS_TOKEN>'
CLIENT_ID = '<WUNDERLIST_CLIENT_ID>'
PROJECT_BOARD = 'LIST_TITLE'
HOUR_RATE = 1


def __build_hour(task):
    '''
    Example:
        dict(title='1 hour CORE-1234')
        dict(title='5 hours CORE-4321')
        dict(title='1 minute CORE-1234')
    '''
    columns = task['title'].strip().split(' ')
    time, measure, task_id = columns
    if measure == 'hour' or measure == 'hours':
        hours = float(time)
    elif measure == 'minute' or measure == 'minutes':
        hours = float(time) / 60
    elif measure == 'day' or measure == 'days':
        hours = 24 * float(time)
    else:
        raise 'unknown measure from the task title: ' + task['title']

    return dict(
        task_id=task_id,
        created_at=parser.parse(task['created_at']),
        hours=hours)


def __main__():
    api = wunderpy2.WunderApi()
    client = api.get_client(ACCESS_TOKEN, CLIENT_ID)
    board = [l for l in client.get_lists() if l['title'] == PROJECT_BOARD][0]
    active_tasks = [t for t in client.get_tasks(board['id']) if not t['completed']]
    report = [__build_hour(task) for task in active_tasks]

    estimated_earnings = sum([task['hours'] for task in report]) * HOUR_RATE
    print(estimated_earnings)

    with open(f"report-{date.today()}.csv", 'w+') as f:
        w = writer(f)
        rows = [[task['task_id'], task['hours'], task['created_at'].date()]
                for task in report]
        w.writerows(rows)

    for task in active_tasks:
        client.update_task(task['id'], task['revision'], completed=True)

    # TODO: make monthly output report to pdf file based on created_at field.


if __name__ == '__main__':
    __main__()

Enter fullscreen mode Exit fullscreen mode

Heroku

This site is built on Heroku

Join the ranks of developers at Salesforce, Airbase, DEV, and more who deploy their mission critical applications on Heroku. Sign up today and launch your first app!

Get Started

Top comments (0)

Sentry image

See why 4M developers consider Sentry, “not bad.”

Fixing code doesn’t have to be the worst part of your day. Learn how Sentry can help.

Learn more

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay