Skip to content

Commit

Permalink
feat: add fortnightly interval
Browse files Browse the repository at this point in the history
In some countries (such as Australia), it is very common for wages to be
paid on a fortnightly basis, that is, every 2 weeks. As a result, a
number of other expenses are also paid on a fortnightly basis.

This commit extends the `Interval` enum by adding a `FORTNIGHT` option.
I have added a test for that, and have updated the translations where
possible (not that other than for English and French, the other
translations may be suboptimal).

Resolves: beancount#1939
Signed-off-by: JP-Ellis <[email protected]>
  • Loading branch information
JP-Ellis committed Feb 8, 2025
1 parent 576cc37 commit 2e73a92
Show file tree
Hide file tree
Showing 21 changed files with 218 additions and 42 deletions.
12 changes: 12 additions & 0 deletions frontend/src/format.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,12 @@ export const dateFormat: Record<Interval, DateFormatter> = {
quarter: (date) =>
`${date.getUTCFullYear().toString()}Q${(Math.floor(date.getUTCMonth() / 3) + 1).toString()}`,
month: utcFormat("%b %Y"),
fortnight: (date) => {
const year = Number.parseInt(utcFormat("%G")(date));
const week = Number.parseInt(utcFormat("%V")(date));
const [w1, w2] = week % 2 === 0 ? [week - 1, week] : [week, week + 1];
return `${year.toString()}W${w1.toString().padStart(2, "0")}/${w2.toString().padStart(2, "0")}`;
},
week: utcFormat("%YW%W"),
day,
};
Expand All @@ -61,6 +67,12 @@ export const timeFilterDateFormat: Record<Interval, DateFormatter> = {
quarter: (date) =>
`${date.getUTCFullYear().toString()}-Q${(Math.floor(date.getUTCMonth() / 3) + 1).toString()}`,
month: utcFormat("%Y-%m"),
fortnight: (date) => {
const year = Number.parseInt(utcFormat("%G")(date));
const week = Number.parseInt(utcFormat("%V")(date));
const [w1, w2] = week % 2 === 0 ? [week - 1, week] : [week, week + 1];
return `${year.toString()}-W${w1.toString().padStart(2, "0")}/${w2.toString().padStart(2, "0")}`;
},
week: utcFormat("%Y-W%W"),
day,
};
Expand Down
10 changes: 9 additions & 1 deletion frontend/src/lib/interval.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,20 @@
import { _ } from "../i18n";

export type Interval = "year" | "quarter" | "month" | "week" | "day";
export type Interval =
| "year"
| "quarter"
| "month"
| "fortnight"
| "week"
| "day";

export const DEFAULT_INTERVAL: Interval = "month";

export const INTERVALS: Interval[] = [
"year",
"quarter",
"month",
"fortnight",
"week",
"day",
];
Expand All @@ -22,6 +29,7 @@ export function intervalLabel(s: Interval): string {
year: _("Yearly"),
quarter: _("Quarterly"),
month: _("Monthly"),
fortnight: _("Fortnightly"),
week: _("Weekly"),
day: _("Daily"),
}[s];
Expand Down
17 changes: 11 additions & 6 deletions frontend/test/format.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,33 +29,38 @@ test("locale number formatting", () => {
});

test("time filter date formatting", () => {
const { day, month, week, quarter, year, ...rest } = timeFilterDateFormat;
const { day, week, fortnight, month, quarter, year, ...rest } =
timeFilterDateFormat;
assert.equal(rest, {});
const janfirst = new Date("2020-01-01");
const date = new Date("2020-03-20");
assert.is(day(janfirst), "2020-01-01");
assert.is(day(date), "2020-03-20");
assert.is(month(janfirst), "2020-01");
assert.is(month(date), "2020-03");
assert.is(week(janfirst), "2020-W00");
assert.is(week(date), "2020-W11");
assert.is(fortnight(janfirst), "2020-W01/02");
assert.is(fortnight(date), "2020-W11/12");
assert.is(month(janfirst), "2020-01");
assert.is(month(date), "2020-03");
assert.is(quarter(janfirst), "2020-Q1");
assert.is(quarter(date), "2020-Q1");
assert.is(year(janfirst), "2020");
assert.is(year(date), "2020");
});

test("human-readable date formatting", () => {
const { day, month, week, quarter, year, ...rest } = dateFormat;
const { day, week, fortnight, month, quarter, year, ...rest } = dateFormat;
assert.equal(rest, {});
const janfirst = new Date("2020-01-01");
const date = new Date("2020-03-20");
assert.is(day(janfirst), "2020-01-01");
assert.is(day(date), "2020-03-20");
assert.is(month(janfirst), "Jan 2020");
assert.is(month(date), "Mar 2020");
assert.is(week(janfirst), "2020W00");
assert.is(week(date), "2020W11");
assert.is(fortnight(janfirst), "2020W01/02");
assert.is(fortnight(date), "2020W11/12");
assert.is(month(janfirst), "Jan 2020");
assert.is(month(date), "Mar 2020");
assert.is(quarter(janfirst), "2020Q1");
assert.is(quarter(date), "2020Q1");
assert.is(year(janfirst), "2020");
Expand Down
1 change: 1 addition & 0 deletions src/fava/core/budgets.py
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ def parse_budgets(
interval_map = {
"daily": Interval.DAY,
"weekly": Interval.WEEK,
"fortnightly": Interval.FORTNIGHT,
"monthly": Interval.MONTH,
"quarterly": Interval.QUARTER,
"yearly": Interval.YEAR,
Expand Down
9 changes: 5 additions & 4 deletions src/fava/help/budgets.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,18 @@ Beancount file:
<pre><textarea is="beancount-textarea">
2012-01-01 custom "budget" Expenses:Coffee "daily" 4.00 EUR
2013-01-01 custom "budget" Expenses:Books "weekly" 20.00 EUR
2013-01-01 custom "budget" Expenses:Fuel "fortnightly" 60.00 EUR
2014-02-10 custom "budget" Expenses:Groceries "monthly" 40.00 EUR
2015-05-01 custom "budget" Expenses:Electricity "quarterly" 85.00 EUR
2016-06-01 custom "budget" Expenses:Holiday "yearly" 2500.00 EUR</textarea></pre>

If budgets are specified, Fava's reports and charts will display remaining
budgets and related information.

The budget directives can be specified `daily`, `weekly`, `monthly`, `quarterly`
and `yearly`. The specified budget is valid until another budget directive for
the account is specified. The budget is broken down to a daily budget, and
summed up for a range of dates as needed.
The budget directives can be specified `daily`, `weekly`, `fortnightly`,
`monthly`, `quarterly` and `yearly`. The specified budget is valid until another
budget directive for the account is specified. The budget is broken down to a
daily budget, and summed up for a range of dates as needed.

This makes the budgets very flexible, allowing for a monthly budget, being taken
over by a weekly budget, and so on.
Expand Down
5 changes: 4 additions & 1 deletion src/fava/translations/bg/LC_MESSAGES/messages.po
Original file line number Diff line number Diff line change
Expand Up @@ -431,6 +431,10 @@ msgstr "Тримесечен"
msgid "Monthly"
msgstr "Месечен"

#: frontend/src/lib/interval.ts:25 src/fava/util/date.py:105
msgid "Fortnightly"
msgstr "На всеки две седмици"

#: frontend/src/lib/interval.ts:25 src/fava/util/date.py:105
msgid "Weekly"
msgstr "Седмичен"
Expand Down Expand Up @@ -592,4 +596,3 @@ msgstr "Изтриване..."
#: frontend/src/sidebar/AsideContents.svelte:60
msgid "Add Journal Entry"
msgstr ""

5 changes: 4 additions & 1 deletion src/fava/translations/ca/LC_MESSAGES/messages.po
Original file line number Diff line number Diff line change
Expand Up @@ -431,6 +431,10 @@ msgstr "Per trimestre"
msgid "Monthly"
msgstr "Per mes"

#: frontend/src/lib/interval.ts:25 src/fava/util/date.py:105
msgid "Fortnightly"
msgstr "Per quinzena"

#: frontend/src/lib/interval.ts:25 src/fava/util/date.py:105
msgid "Weekly"
msgstr "Per setmana"
Expand Down Expand Up @@ -592,4 +596,3 @@ msgstr "S'està suprimint..."
#: frontend/src/sidebar/AsideContents.svelte:60
msgid "Add Journal Entry"
msgstr ""

5 changes: 4 additions & 1 deletion src/fava/translations/de/LC_MESSAGES/messages.po
Original file line number Diff line number Diff line change
Expand Up @@ -431,6 +431,10 @@ msgstr "Quartalsweise"
msgid "Monthly"
msgstr "Monatlich"

#: frontend/src/lib/interval.ts:25 src/fava/util/date.py:105
msgid "Fortnightly"
msgstr "Zweiwöchentlich"

#: frontend/src/lib/interval.ts:25 src/fava/util/date.py:105
msgid "Weekly"
msgstr "Wöchentlich"
Expand Down Expand Up @@ -592,4 +596,3 @@ msgstr "Wird gelöscht..."
#: frontend/src/sidebar/AsideContents.svelte:60
msgid "Add Journal Entry"
msgstr "Journal-Eintrag hinzufügen"

5 changes: 4 additions & 1 deletion src/fava/translations/fa/LC_MESSAGES/messages.po
Original file line number Diff line number Diff line change
Expand Up @@ -431,6 +431,10 @@ msgstr "سه‌ماهه"
msgid "Monthly"
msgstr "ماهانه"

#: frontend/src/lib/interval.ts:25 src/fava/util/date.py:105
msgid "Fortnightly"
msgstr "هر دو هفته یکبار"

#: frontend/src/lib/interval.ts:25 src/fava/util/date.py:105
msgid "Weekly"
msgstr "هفتگی"
Expand Down Expand Up @@ -592,4 +596,3 @@ msgstr ""
#: frontend/src/sidebar/AsideContents.svelte:60
msgid "Add Journal Entry"
msgstr ""

5 changes: 4 additions & 1 deletion src/fava/translations/fr/LC_MESSAGES/messages.po
Original file line number Diff line number Diff line change
Expand Up @@ -431,6 +431,10 @@ msgstr "Trimestriel"
msgid "Monthly"
msgstr "Mensuel"

#: frontend/src/lib/interval.ts:25 src/fava/util/date.py:105
msgid "Fortnightly"
msgstr "Bimensuel"

#: frontend/src/lib/interval.ts:25 src/fava/util/date.py:105
msgid "Weekly"
msgstr "Hebdomadaire"
Expand Down Expand Up @@ -592,4 +596,3 @@ msgstr "Suppression..."
#: frontend/src/sidebar/AsideContents.svelte:60
msgid "Add Journal Entry"
msgstr ""

5 changes: 4 additions & 1 deletion src/fava/translations/nl/LC_MESSAGES/messages.po
Original file line number Diff line number Diff line change
Expand Up @@ -431,6 +431,10 @@ msgstr "Per kwartaal"
msgid "Monthly"
msgstr "Maandelijks"

#: frontend/src/lib/interval.ts:25 src/fava/util/date.py:105
msgid "Fortnightly"
msgstr "Tweewekelijks"

#: frontend/src/lib/interval.ts:25 src/fava/util/date.py:105
msgid "Weekly"
msgstr "Wekelijks"
Expand Down Expand Up @@ -592,4 +596,3 @@ msgstr ""
#: frontend/src/sidebar/AsideContents.svelte:60
msgid "Add Journal Entry"
msgstr ""

5 changes: 4 additions & 1 deletion src/fava/translations/pt_BR/LC_MESSAGES/messages.po
Original file line number Diff line number Diff line change
Expand Up @@ -432,6 +432,10 @@ msgstr "Trimestral"
msgid "Monthly"
msgstr "Mensal"

#: frontend/src/lib/interval.ts:25 src/fava/util/date.py:105
msgid "Fortnightly"
msgstr "Quinzenal"

#: frontend/src/lib/interval.ts:25 src/fava/util/date.py:105
msgid "Weekly"
msgstr "Semanal"
Expand Down Expand Up @@ -593,4 +597,3 @@ msgstr "Apagando..."
#: frontend/src/sidebar/AsideContents.svelte:60
msgid "Add Journal Entry"
msgstr "Adicionar Entrada"

5 changes: 4 additions & 1 deletion src/fava/translations/ru/LC_MESSAGES/messages.po
Original file line number Diff line number Diff line change
Expand Up @@ -430,6 +430,10 @@ msgstr "По кварталам"
msgid "Monthly"
msgstr "По месяцам"

#: frontend/src/lib/interval.ts:25 src/fava/util/date.py:105
msgid "Fortnightly"
msgstr "Каждые две недели"

#: frontend/src/lib/interval.ts:25 src/fava/util/date.py:105
msgid "Weekly"
msgstr "По неделям"
Expand Down Expand Up @@ -591,4 +595,3 @@ msgstr ""
#: frontend/src/sidebar/AsideContents.svelte:60
msgid "Add Journal Entry"
msgstr ""

5 changes: 4 additions & 1 deletion src/fava/translations/sk/LC_MESSAGES/messages.po
Original file line number Diff line number Diff line change
Expand Up @@ -436,6 +436,10 @@ msgstr "Kvartálne"
msgid "Monthly"
msgstr "Mesačne"

#: frontend/src/lib/interval.ts:25 src/fava/util/date.py:105
msgid "Fortnightly"
msgstr "Dvotýždenne"

#: frontend/src/lib/interval.ts:25 src/fava/util/date.py:105
msgid "Weekly"
msgstr "Týždenne"
Expand Down Expand Up @@ -597,4 +601,3 @@ msgstr ""
#: frontend/src/sidebar/AsideContents.svelte:60
msgid "Add Journal Entry"
msgstr ""

5 changes: 4 additions & 1 deletion src/fava/translations/sv/LC_MESSAGES/messages.po
Original file line number Diff line number Diff line change
Expand Up @@ -431,6 +431,10 @@ msgstr "Kvartalsvis"
msgid "Monthly"
msgstr "Månatligt"

#: frontend/src/lib/interval.ts:25 src/fava/util/date.py:105
msgid "Fortnightly"
msgstr "Var fjortonde dag"

#: frontend/src/lib/interval.ts:25 src/fava/util/date.py:105
msgid "Weekly"
msgstr "Veckovis"
Expand Down Expand Up @@ -592,4 +596,3 @@ msgstr ""
#: frontend/src/sidebar/AsideContents.svelte:60
msgid "Add Journal Entry"
msgstr ""

5 changes: 4 additions & 1 deletion src/fava/translations/uk/LC_MESSAGES/messages.po
Original file line number Diff line number Diff line change
Expand Up @@ -431,6 +431,10 @@ msgstr "Щоквартально"
msgid "Monthly"
msgstr "Щомісячно"

#: frontend/src/lib/interval.ts:25 src/fava/util/date.py:105
msgid "Fortnightly"
msgstr "двотижневий"

#: frontend/src/lib/interval.ts:25 src/fava/util/date.py:105
msgid "Weekly"
msgstr "Щотижнево"
Expand Down Expand Up @@ -592,4 +596,3 @@ msgstr ""
#: frontend/src/sidebar/AsideContents.svelte:60
msgid "Add Journal Entry"
msgstr ""

5 changes: 4 additions & 1 deletion src/fava/translations/zh/LC_MESSAGES/messages.po
Original file line number Diff line number Diff line change
Expand Up @@ -431,6 +431,10 @@ msgstr "按季"
msgid "Monthly"
msgstr "按月"

#: frontend/src/lib/interval.ts:25 src/fava/util/date.py:105
msgid "Fortnightly"
msgstr "按两周"

#: frontend/src/lib/interval.ts:25 src/fava/util/date.py:105
msgid "Weekly"
msgstr "按周"
Expand Down Expand Up @@ -592,4 +596,3 @@ msgstr "正在删除..."
#: frontend/src/sidebar/AsideContents.svelte:60
msgid "Add Journal Entry"
msgstr "添加日记账条目"

5 changes: 4 additions & 1 deletion src/fava/translations/zh_Hant_TW/LC_MESSAGES/messages.po
Original file line number Diff line number Diff line change
Expand Up @@ -432,6 +432,10 @@ msgstr "季度"
msgid "Monthly"
msgstr "月"

#: frontend/src/lib/interval.ts:25 src/fava/util/date.py:105
msgid "Fortnightly"
msgstr "兩周"

#: frontend/src/lib/interval.ts:25 src/fava/util/date.py:105
msgid "Weekly"
msgstr "週"
Expand Down Expand Up @@ -594,4 +598,3 @@ msgstr "正在删除..."
#: frontend/src/sidebar/AsideContents.svelte:60
msgid "Add Journal Entry"
msgstr ""

Loading

0 comments on commit 2e73a92

Please sign in to comment.