Giter Club home page Giter Club logo

payshare's Introduction

Payshare

A web app to track shared expenses in a group of people.

Build Status Codacy Badge

Payshare is the equivalent of a whiteboard in the kitchen of your shared flat where everyone writes down how much they paid for groceries, who paid the cinema ticket or pizza for whom and so on, while it does the math for you to figure out who should buy the next round.

Demo

You can login using the password demo here.

License

MIT, see LICENSE.txt

Screenshots

Terminology

  • Collective: This is basically your shared flat, sports team, whatever
  • User: A person that can be a member of one or more Collectives
  • Membership: The connection of a User to a Collective
  • Purchase: A User bought something and the cost is shared equally in the Collective
  • Liquidation (named "Outlay" in the frontend): Some User gave money to another one and that debt will have to be paid back later

Development Setup

If you want to setup and run the project yourself, follow these steps (assuming you are on a Unix OS):

Backend

  • Make sure you have Python 3.x installed
  • Clone the project and cd into its root directory
  • $ virtualenv venv
  • $ source venv/bin/activate
  • $ pip install pip-tools
  • $ pip-sync
  • $ python manage.py migrate
  • $ python manage.py createsuperuser
  • $ python manage.py runserver

Frontend

Make sure to have npm or yarn installed globally

  • $ cd payshare/purchases/static/client
  • $ yarn/ $ npm install
  • $ npm run serve

Creating initial Data

The project currently relies on the Django admin pages to create new Collectives and Users and add Memberships between them.

Assuming your Django dev-server is running at the default port, go to:

https://localhost:8000/admin

  • Create a Collective and set a password for it
  • Create some Users (username is the only field that is displayed. Django requires us to set a password here, but you can just give any, it isn't used)
  • Create Memberships for those Users in your Collective

The URL for your collective will be e.g. http://localhost:8000/<collective-key>. You can get the key from the admin pages. Send the URL (and the Collective's password of course) to everyone you want to participate, they will be asked to choose a User when logging in for the first time.

You can also assign an avatar for each user by assigning some URL to a hosted image (there is no own upload feature, sorry). You can do that in the User profiles area in the admin pages. There are many avatar generators, I like these:

A Note about Security

The whiteboard metaphor is valid: Anyone with a "key" to your flat (aka password for the Collective) can create and delete content or impersonate other Users. It's based on trust between the people in the group.

Tech Stack

Project is build with Django 2.1, Django-REST-Framework 3, Vue 2.5, vue-cli-3 and the wonderful Vuetify 1.1.0. It is build mainly to be used on a mobile phone, but responsive and very usable on desktop as well. Technically it is a PWA, but right now that is only used to cache the app shell, not any API responses. Uses SQLite as its database, creating a single file for easy backup.

Deployment

Oh the joy of deploying custom web apps to your own server. Our backend can be setup as a systemd service that runs a WSGI app via gunicorn, whereas the frontend is built into a bundle of static files that our nginx webserver can serve.

Building the Frontend

  • $ cd payshare/purchases/static/client
  • Update the src/store.js apiBaseUrl as needed, depending where your API lives on.
  • $ npm run build
  • $ cd -
  • $ python manage.py collectstatic --noinput
  • Copy the results from public to a folder that your webserver knows, e.g. /var/www/payshare
  • Configure your webserver and systemd, see below
  • Don't forget to install gunicorn: $ pip install gunicorn

Please see the following files for examples on simple systemd and nginx configurations:

Notes: We should use https in any case, but it is also a requirement for the service-worker. One specialty about location blocks here is that for some we'll want to pass through the URL path and for others we don't.

Image Hosting (e.g. avatars)

You can upload images within the admin page using Filer which is particularly helpful to upload avatars to use within the UserProfile model. Any URLs that may have been used to create the avatar can be stored in the 'description' field of the image so it can be used later on.

Images are hosted efficiently by making use of Whitenoise, so there is no need to configure your webserver for it in addition.

Paypal.me Integration

Well, integration is a big word. You can set a paypal.me username in the profile of each User and the app will show a button on the cashup page to open a tab in the browser with the correct amount for that payback action.

payshare's People

Contributors

cb109 avatar dependabot[bot] avatar hackebrot avatar zarathustra2 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

payshare's Issues

Aid in simple calculations

Sometimes a Purchase consists of multiple entries that need to be summed together. It would be nice to be able to just type it in and let it sum up automatically (or offer to use the sum as the price value).

Example:

Could have an extra multiline field where we just type numbers on each line and it sums them up

17.45
6.20
-------
23.65

Add average Purchase value

The median can be interesting for some use cases, like having only two users over a longer period of time, but it is not very helpful for having many users over a short period of time (like a weekend trip).

Either add it next to the median or as an optional value that can be swapped by clicking the median.

Allow splitting Purchase unevenly, by weights (e.g. days of stay)

Example: Hotel is split evenly, as we can't give any of it back. But if some stays only 1 of 3 days it would be unfair to pay for the same amount e.g. for things like food, so we can assign weights for a Purchase for each member to split this more fairly.

This could also be used to model #63 by assigning a 0 weight or maybe removing the weight/unchecking it.

Add a button to generate paypal.me url for a cash-up step

  • Allow to add paypal.me usernames to user-profiles
  • In a step on the cash-up page, if the creditor has such a username in his profile, add a button that opens the www.paypal.me/<username>/<amount> in a new tab to give the debtor a quick way to pay back

Support having members share costs only beginning from a certain date

Take e.g. a shared flat: People come and go. A new flatmate should not be responsible for old purchases. Also we should not be forced to create a new Collective everytime the member number/constellation changes (which is currently pretty much the only effective way to deal with this).

This could probably be implemented by adding a join_date to each Membership and calculating each member's share of the Purchases/Liquidations starting from that date only, so that someone joining later will effectively have to pay only what he made use of.

Upload and host avatars images while keeping the generator URL

This will make it easy to use the generator when needed, but we don't have to rely on avataaars.io being available, because it often is not. Instead download the result of the generator as an image and host it somehere and use the URL for the actual avatar.

Liquidation VS Debt

The concept of a liquidation seems to be hard to grasp in some instances. It's kind of the opposite of how people seem to think about money and how one person is in debt to another.

We could possibly rephrase the whole concept in the frontend by swapping directions basically. Inside the dialog the 2nd option would then be "Add new Debt".

SQLite3 Version may clash with Django on testruns

With a fresh setup of Python 3.7 and SQlite 3.29.0-1 testruns fail for some tests like:

self = <django.db.backends.sqlite3.base.SQLiteCursorWrapper object at 0x7fb4d359faf8>, query = 'INSERT INTO "purchases_membership" ("created_at", "modified_at", "member_id", "collective_id") VALUES (?, ?, ?, ?)'
params = ['2019-07-19 13:41:23.327457', '2019-07-19 13:41:23.327563', 1, 1]

    def execute(self, query, params=None):
        if params is None:
            return Database.Cursor.execute(self, query)
        query = self.convert_query(query)
>       return Database.Cursor.execute(self, query, params)
E       django.db.utils.OperationalError: no such table: main.purchases_collective__old

venv/lib/python3.7/site-packages/django/db/backends/sqlite3/base.py:303: OperationalError
________________________________________________________________________________________________ ERROR at setup of test_collective_purchases _________________________________________________________________________________________________

See:

This should most likely be fixed by upgrading Django to 2.2+.
EDIT: Confirmed by @Zarathustra2 this seems to fix it.

Readonly mode for a Collective

It would be nice to mark a Collective as readonly so that no addition/modification can be done (UI should reflect that), but everything can still be viewed. We may be able to handle this in a generic way inside a middleware.

error : Email Password: Password (again): |--|||||||||||||||||||||| (dockerfile)

hello ,
error exec python manage.py createsuperuser
FROM python:3-slim-jessie

I need Help me plz ! :(

root@82eab9cc7148:/var/app# python manage.py createsuperuser
Username (leave blank to use 'root'): fbclol
Email address: [email protected]
Password:
Password (again):
Traceback (most recent call last):
File "manage.py", line 22, in
execute_from_command_line(sys.argv)
File "/usr/local/lib/python3.6/site-packages/django/core/management/init.py", line 371, in execute_from_command_line
utility.execute()
File "/usr/local/lib/python3.6/site-packages/django/core/management/init.py", line 365, in execute
self.fetch_command(subcommand).run_from_argv(self.argv)
File "/usr/local/lib/python3.6/site-packages/django/core/management/base.py", line 288, in run_from_argv
self.execute(*args, **cmd_options)
File "/usr/local/lib/python3.6/site-packages/django/contrib/auth/management/commands/createsuperuser.py", line 59, in execute
return super().execute(*args, **options)
File "/usr/local/lib/python3.6/site-packages/django/core/management/base.py", line 335, in execute
output = self.handle(*args, **options)
File "/usr/local/lib/python3.6/site-packages/django/contrib/auth/management/commands/createsuperuser.py", line 160, in handle
validate_password(password2, self.UserModel(**fake_user_data))
File "/usr/local/lib/python3.6/site-packages/django/contrib/auth/password_validation.py", line 44, in validate_password
password_validators = get_default_password_validators()
File "/usr/local/lib/python3.6/site-packages/django/contrib/auth/password_validation.py", line 19, in get_default_password_validators
return get_password_validators(settings.AUTH_PASSWORD_VALIDATORS)
File "/usr/local/lib/python3.6/site-packages/django/contrib/auth/password_validation.py", line 26, in get_password_validators
klass = import_string(validator['NAME'])
KeyError: 'NAME'

Add support for negative Purchase prices

There are use cases for this I haven't thought of yet, e.g. things like yearly refunds (electricity) or changes in costs that have already been paid by everyone.

Make all URLs unique by including the collective ID or key

After logging in the URL will e.g. look like host.com/transfers. This is not something that can easily be shared or bookmarked, as it contains no reference to the collective currently being logged in.

It would be nice to use host.com/collective-key/transfers instead.

Allow for easy switching between Collectives

It is currently quite annoying when switching between collectives, especially with using the app from a homescreen icon.

It would be nice to store tokens for all currently logged in collectives and allow for a quick change. One way to do that could be by scoping all localStorage values by collective id so that we can store as many as wanted next to each other.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.