Added detailed specification for the kbenestad/invoice project, including goals, planned structure, features, and configuration file details.
7.1 KiB
kbenestad/invoice - specification
(C) 2026 Kristian Benestad. Licensed under the Apache 2 license.
Goal
kbenestad/invoice solves an important financial question for many small entities relying on freelancers and others who are not used to charging for their services by providing a static web app that produces ready-to-submit PDF invoices with prepared lines and rates if so defined in the configuration file.
This app works well together with kbenestad/reimburse, a static web app that provides structured reimbursement requests with built-in currency conversion and receipt references.
Planned structure for development
- app/index.html -- app file that consists of a form capturing user data which generates a PDF invoice.
- app/config.yml -- configuration file
- docs/ -- documentation for project
- docs/devdocs/ -- development documentation
- docs/devdocs/spec.md -- this document
- docs/devdocs/sampletheme.yml -- sample theme from MD-CMS
- docs/devdocs/reference-theme.md -- MD-CMS documentation for theme files
- docs/devdocs/ -- development documentation
Invoice features
The invoice form -- both input and output -- is a standard classic invoice. The form is multilingual, and if more than one language is defined, the user selects language at the top of the form. The form always prints in the default language.
Suggested layout for input form - output derives from this:
[ICON] Language: [SELECT]
--------------------------------------------------------------------------------
INVOICE
--------------------------------------------------------------------------------
[SENDER NAME - TEXT ] Phone: [SENDER PHONE - TEXT ]
[SENDER ADDRESS1 - TEXT ] Email: [SENDER EMAIL - TEXT ]
[SENDER ADDRESS2 - TEXT ]
[SENDER ADDRESS3 - TEXT ]
[SENDER ADDRESS4 - TEXT ]
[SENDER COUNTRY - SELECT ]
Charge to: [SELECT OR OTHER ]
----------------------------------------
[CHARGE TO NAME - TEXT ] Phone: [CHARGE TO PHONE - TEXT ]
[CHARGE TO ADDRESS1 - TEXT ] Email: [CHARGE TO EMAIL - TEXT ]
[CHARGE TO ADDRESS2 - TEXT ] VAT/Tax ID: [TEXT ]
[CHARGE TO ADDRESS3 - TEXT ] Invoice date: [MONTHPICKER]
[CHARGE TO ADDRESS4 - TEXT ] Project code: [SELECT ]
[CHARGE TO COUNTRY - SELECT ] Invoice no.: [ALFANUMERIC]
[CHARGE TO EMAIL ADDRESS - TEXT ] • [CHARGE TO TELEPHONE NUMBER - TEXT]
QTY | UOM | DESCRIPTION | PRICE | LINE TOTAL
-------|-------|---------------------------------------|------------|-----------
[NUM. ]|[SLCT ]|[SELECT OR TEXT ]| 999,999.00 | 999,999.00
| | Foreign currency: [NO] | |
-------|-------|---------------------------------------|------------|-----------
| | [+] Add new line | |
** If Foreign currency = Yes, input: **
-------|-------|---------------------------------------|------------|-----------
[NUM. ]|[SLCT ]|[SELECT OR TEXT ]| 999,999.00 | 999,999.00
| | Foreign currency: [YES ] | |
| | Currency code: [SELECT ] | |
| | Exchange rate: [NUMBER ] | |
| | Per item: [999,999.00] | |
| | Total local currency: [999,999.00] | |
-------|-------|---------------------------------------|------------|-----------
| | [+] Add new line | |
** End of form **
--------------------------------------------------------------------|-----------
Subtotal: |[CALCULATE]
[SELECT] Tax X.X%: |[CALCULATE]
Paid: |[NUMBER ]
--------------------------------------------------------------------|-----------
To pay: |[CALCULATE]
--------------------------------------------------------------------|-----------
[ GENERATE INVOICE ]
Features
- [ICON] Language: [SELECT]: Languages and icons are defined in
config.yml. This affects only the layout of the input form. - Sender name: Text input fields. Saved in local storage and retrieved next time.
- Charge to: Select a predefined recipient, or select
Otherand fill in all fields manually. Empty fields are not shown on invoice. - Invoice date: Date picker. Default to today.
- Project code: List of predefined project codes. If
Otherfield becomes a text field. - Invoice number: User sets an alfanumeric value. It is stored in local storage and retreived and bumped with 1 next time the user visits after having clicked
Generate invoice. Invoice lines: After the user clicks[+] Add new line, a new line appears.- Description: The user selects either a predefined product already;
DescriptionandUoMare then prefilled. - Qty: Numeric field. Multiply with
Priceto getLine total. - UoM: Prefilled if selected an existing product, if
Other - Price: If selecting an exsisting product,
Priceis prefilled but can be altered. - Calculated fields
Line total,Subtotal, andTo payare calculated bassed on the values provide. - Tax/VAT is set in the config.yml.
- Description: The user selects either a predefined product already;
- Foreign currency: Yes/no. Yes opens further options that must be defined. The form calculates the total price based ion the line items.
Configuration file
ICON is an SVG icon - either a name for a Material Icon hosted by Google, or the filename of an icon hosted in assets/icons.
Language is defined in config.yml:
default-code: en
default-name: English
default-direction: ltr
Languages are defined with lang-code, lang-name, and lang-direction.
Each piece of information is defined in config.yml, e.g.,:
language
default-lang: Language
de: Sprache
invoice
default-lang: Invoice
de: Faktura
sender-name
default-lang: Sender name
de: Aussteller
charge-to allows the app owner to predefine recipients:
charge-to: Organisation Name
charge-to-name: Legal Organisation Name
charge-to-address1: Address Line 1
charge-to-address2: Address Line 2
charge-to-address3: Address Line 3
charge-to-address4: Address Line 4
charge-to-phone: +66-(0)94 251 7500
charge-to-email: email@example.org
charge-to-vat-id: Text field
Project code is a list of available project codes.
project-codes:
Project 100
Project 110
Project 230
Units of measures are defined by config.yml:
uom
Each: EA
Hour: HR
Day: DY
Agent instructions
Build app/index.html and config.yml.
Use a neutral, authoritative colour scheme.