spiral-project / ihatemoney

A simple shared budget manager web application
https://ihatemoney.org
Other
1.2k stars 269 forks source link

Recurring bills (ISP, electricity, water, charges...) #152

Open Vincent14 opened 8 years ago

Vincent14 commented 8 years ago

I would know if it's possible to add bills that could have a frequency (every day/week/month//year)?

Djabal commented 8 years ago

That will be very convenient !

aavenel commented 7 years ago

This could be useful ! However, it's not really clear how do we implement this. Mockups are welcome.

Although it's quite difficult to configure, it's possible to do this now using the API.

curl --basic -u demo:demo https://ihatemoney.org/api/projects/demo/members
[{"activated": true, "id": 31, "name": "Arnaud"},
 {"activated": true, "id": 32, "name": "Alexis"},
 {"activated": true, "id": 33, "name": "Olivier"},
 {"activated": true, "id": 34, "name": "Fred"}]

Note your member id, as it it required to configure the next request.

curl --basic -u demo:demo -X POST\
https://ihatemoney.org/api/projects/demo/bills\
-d "what=raclette&payer=31&payed_for=31&payed_for=32&amount=200"

If you omit the date field, we will use the current time at bill's creation.

You can find the documentation of the API here : https://github.com/spiral-project/ihatemoney/blob/master/docs/api.rst

To automate this, you can use a Cron script, or even use some service like IFTTT. I have set up an applet on IFTTT (Maker channel) to make the REST request.

This is pretty mush the same thing as using curl, except that you need to pass the authentification data like this : https://projectname:password@ihatemoney.org/api/projects/projectname

almet commented 7 years ago

We've not implemented this in the current version of the software in order to keep things easy to grasp (and the UX simple), but I can see why this would be useful.

As @aavenel says, mockups (or implementations!) would be welcome for this. For now, I don't think anyone volunteered.

SemperFu commented 6 years ago

I was actually just searching for a opensource system that could do this. I basically want to track multiple shared online services. I have an online service that costs $12 a month and 3 of us share it. So every month It should add debt to the other 2 people. One person pays monthly and I can track that and the other pays yearly so this would be useful with multiple online services and people who don't pay all the time.

So one of the users logs in and sees he owes me x amount of money total and he can see a break down of all each transaction built up over time.

almet commented 5 years ago

The way to do this in Flask would be to create a task (in manage.py) that would check all projects and see the recurring bills, each day, and mark them with the last date is was run.

I believe it's simple enough for a good first issue, so labeled as such.

Andrew-Dickinson commented 4 years ago

Hi @almet

I'm thinking of working on this issue, it looks like the first step would be mockup of the UI changes in the "Add a bill" dialog. It seems like you guys put a lot of emphasis on keeping the default workflow as simple as possible. For this feature, maybe the best way to implement that would be a "Make recurring" hyperlink just above the submit button which expands to reveal the interface for specifying the frequency, first occurrence, etc.

Something else I'm thinking about is the workflow for how to edit or cancel a recurring bill. Should that be integrated with the "Edit Bill" view, or should a separate workflow exist to manage recurring bills?

Andrew-Dickinson commented 4 years ago

I put together some mockups, please let me know what you think!

The behavior of the proposed changes requires the consideration of a back-end "recurrence object". This object would represent the concept of repeating bills. Each bill that is (or was) repeating would have a recurrence object associated with it, and all bills in the same "series" would reference the same recurrence object. Recurrence objects would be immutable, but could be un-linked from bills to cancel the recurrence.

The add bill form would include a small link to optionally make a bill repeating:

image

When expanded:

image

For the edit form, the UI gets a little more complicated and is sort of dependent on the behavior of the recurring bills. Here's how I imagined this could work, there are four possible states for a bill:

  1. Not Recurring (current behavior for all bills). Bills that are not recurring simply display the "Make repeating" link in their edit form (which expands similarly to the "Add Bill" form): image
  2. About to recur (bills whose recurrence object's "repeat until" date is in the future but have yet to create a bill). Bills that have a recurrence planned display the planned schedule of their recurrence object and give the opportunity to cancel the recurrence. Clicking "Cancel Recurrence" doesn't delete any bills. Clicking "Cancel Recurrence" simply deletes the recurrence object, moving the bill to state 1. This allows the user to "edit" the recurrence of the bill by adding a new recurrence object just like any other non-recurring bill. image
  3. Recurring Actively (bills whose recurrence object's "repeat until" date is in the future and have created a bill). If the recurrence object associated with this bill has already created bills, it behaves similarly to state 2 (and displays identically). However, the behavior of the cancel button is changed. If the user cancels a recurrence object in state 3, it simply sets its "Recur until" date to be the current date to prevent further recurrence (and therefore moves the bill to state 4).
  4. Previously Recurring (bills whose recurrence object's "repeat until" date is in the past). Bills which were recurring, but are no longer. This state exists to prevent the unexpected behavior of an expired repeating bill series from displaying "Make repeating", potentially confusing the user. No edits can be made to a bill's the recurrence from this state. However, users are allowed to delete bills as usual to remove unwanted Previously Recurring bills. image

Bills with a recurrence object could display an icon next to the edit and delete icons on the list bills view: image

The text of this tooltip could vary based on the recurrence object's state similar to the edit form text: image

If the user edits the date of a bill with a recurrence object, the behavior would depend on the state:

  1. Not Recurring - The date of the bill is changed and no further action is needed.
  2. About to recur - The starting date of the recurrence object is changed to match the bill.
  3. Recurring Actively (a) If the bill being edited is the latest bill in the "series", a new recurrence object is created to represent the future recurrence (the new recurrence is in state 2) and the "series" is split in two. The old recurrence object is cancelled and placed into state 4 by setting its repeat until date to be the current date. (b) If the bill being edited is not the latest bill in the "series", a new recurrence is created, similar to 3(a), but the old recurrence object is deleted. This makes all bills associated with it enter state 1 (except the latest bill in the series, which enters state 2).
  4. Previously recurring - The recurrence object is deleted, sending all bills associated with it to state 1.

If the user deletes a recurring bill, the behavior would depend on the state:

  1. Not Recurring - The bill is deleted and no further action is needed.
  2. About to recur - The recurrence object is deleted along with the bill.
  3. Recurring Actively (a) If the bill being deleted is the latest bill in the "series", the recurrence is cancelled. The bill is deleted and the repeat until date of its recurrence object is set to the date of the deleted bill (therefore the remaining bills are moved to state 4). (b) If the bill being deleted is not the latest bill in the "series", the behavior is similar to 3(b) above, where the recurrence is broken for all but the latest bill.
  4. Previously recurring - The recurrence object is deleted along with the bill, sending all remaining bills associated with it to state 1.

Here is a flowchart to help show the relationship between the states: image

Please let me know what you guys think!

eMerzh commented 4 years ago

Hi, didn't check the rest of the proposal, but little nitpick, please don't put recurring icon with other actions icons (edit, delete) i'd probably add it near the date or smth.

Other than that, visually, i like the fact that it's pretty discreet

indatwood commented 4 years ago

Wow, that's a nice proposal :-) Thank you for the work done already!

That looks great to me, go ahead !

Glandos commented 4 years ago

This is indeed a wonderful proposal!

However, to make code a lot simpler, I would like to have another proposal: a copy feature. We can add a "copy bill" that opens the "Add bill" form with all fields filled with the original bill. Of course, it's a manual operation, and it doesn't fit the original requirement completely.

By the way, a "copy" operation could be useful even with recurring bills implemented…

youegraillot commented 2 years ago

Is anyone on this ? I'm planning to :)

almet commented 2 years ago

Yay !

almet commented 2 years ago

@youegraillot If you still want to work on this that would be very useful. I'm volunteering to review and help you out to make things simpler, so we can have this in the next release.

Let me know what you think!

almet commented 2 years ago

I was thinking about how this should be done technically, and here is my thinking so far : We will need a routine that will check periodically for the tasks to repeat.

I think about multiple ways to do this, and I believe we should use option 2 (Flask Crontab).

  1. Using a cli task and a cronjob. It means that in order to be enabled, this feature will need some work from the admins in order to setup the cronjob.
  2. Using Flask Crontab, which is kinda the same option as 1, but with the heavy lifting done for us.

Here are some stuff I considered and let on the side :

  1. Using Celery periodic tasks. I feel this is quite too much for us, as it will add complexity to the project for a small feature like this one : we will need to tell people about brokers, add requirements like Redis or RabbitMQ.
Glandos commented 2 years ago

I am also against using Celery here. I set it up for Weblate, it's not useless, but really overkill. Flask Crontab seems nice, but apart for the 12 commits and 3 releases, there is no other commit since January 2020: don't you fear that it's in abandoned state?

almet commented 2 years ago

Don't you fear that it's in abandoned state?

I missed this info, and you're probably right, we should head another direction. I've found python-crontab which makes it possible to write crontabs for us, but I'm not even sure we will need it.

I suppose we can make things work with a command and then worry about the specifics on how we will ensure this command is summoned at the right times :-)