diff options
Diffstat (limited to 'docs/PROTOCOL.md')
| -rw-r--r-- | docs/PROTOCOL.md | 56 |
1 files changed, 40 insertions, 16 deletions
diff --git a/docs/PROTOCOL.md b/docs/PROTOCOL.md index 81eeb67..75f1990 100644 --- a/docs/PROTOCOL.md +++ b/docs/PROTOCOL.md @@ -396,10 +396,11 @@ characters. Verification ids are the concatenation of series and number required. `smtp_host` (up to 255 characters, no control characters), `smtp_user` (up to -255), `smtp_from` and `smtp_reply_to` (up to 254), `smtp_port` (digits, -1–65535) and `smtp_security` (`starttls`, `tls` or `plain`, default -`starttls` when unset) configure the outgoing mail used when invoices are -sent. +255), `smtp_from` and `smtp_reply_to` (up to 254) must be e-mail addresses +(one `@`, no spaces), `smtp_port` (digits, 1–65535) and `smtp_security` +(`starttls`, `tls` or `plain`, default `starttls` when unset) configure the +outgoing mail used when invoices are sent. The sender's display name is the +organization name; `smtp_from` is the address. `smtp_password` is a secret setting. `settings.set` encrypts the value with AES-256-GCM under the key in the `BOKFD_SECRET_KEY` environment variable (32 @@ -591,10 +592,11 @@ removes one link and is a `NOT_FOUND` when it does not exist. Both mutate | `invoice.sequence_set` | `next_number` (owner) | `next_number` | | `invoice.preview` | draft (below) | `content_base64`, `number`, `ocr`, `net_ore`, `vat_ore`, `total_ore` | | `invoice.issue` | draft, `dry_run?` | `id`, `number`, `ocr`, `document_id`, `voucher_id`, totals | -| `invoice.get` | `id` | header, `rows[]`, `document_id`, `voucher_id`, `last_sent_at`, `last_sent_to` | -| `invoice.list` | `customer_id?`, `status?` (`issued`/`credited`), `limit?` | `items[]`, newest first | +| `invoice.get` | `id` | header, `rows[]`, `document_id`, `voucher_id`, `paid_date`, `payment_voucher_id`, `last_sent_at`, `last_sent_to` | +| `invoice.list` | `customer_id?`, `status?` (`issued`/`credited`), `limit?` | `items[]`, newest first, with `paid_date` | | `invoice.pdf` | `id` | stored PDF as `content_base64` | | `invoice.send` | `id`, `to?` | `id`, `sent_to`, `at`; `dry_run` returns `to`, `subject` | +| `invoice.pay` | `id`, `voucher_id`, `dry_run?` | `id`, `number`, `paid_date`, `payment_voucher_id`, `voucher_series`, `voucher_number` | The draft object is the argument set shared by `invoice.preview` and `invoice.issue`: @@ -617,6 +619,13 @@ accounts are `ACCOUNT_NOT_FOUND`/`ACCOUNT_INACTIVE`. The customer must exist and be active (`NOT_FOUND`). A draft whose rows do not fit the single page is rejected with `TOO_LARGE`. +A row with `"text": true` is a free-text line: only `description` is used, +it has no quantity, unit, price or VAT, contributes nothing to the totals +and only prints its description in the document. Every draft still needs at +least one priced row (`INVALID_ARGS` otherwise, "invoice total must be +greater than zero"). `invoice.get` and `invoice.list` return rows with +`is_text`. + Numbering is a per-org, global series: `invoice_sequence.next_number` starts at 1, is set by the owner and is incremented by exactly one per issued invoice. The OCR reference is the number followed by its MOD10 (Luhn) check @@ -653,6 +662,15 @@ updated and the `invoice.send` audit entry stores `{id,to,subject}` only. `dry_run` validates configuration, recipient and stored document and returns the recipient and subject without sending or updating anything. +`invoice.pay` links a payment voucher (created by the client, normally from +the TUI's **Kvittera betalning** action, which prefills debit `bank_account` +and credit `invoice_receivable_account` in the ordinary voucher form) and +stamps `paid_date` with the voucher's date. The voucher must credit the +`invoice_receivable_account` (default `1510`) with exactly the invoice +total, else `INVALID_ARGS`; an already paid invoice and a `credited` one are +rejected (`CONFLICT` and `INVALID_ARGS`). `dry_run` validates without +writing, and the command is audited. + ### 7.11 Anställda (employees) The employee register. `personal_no` is checked for shape (10 or 12 digits, @@ -863,6 +881,7 @@ Args: `name:type(values)[!][=default]`, `!` = required. | `invoice.list` | viewer | yes | no | no | `customer_id:int`, `status:enum(issued\|credited)`, `limit:int=200` | | `invoice.pdf` | viewer | yes | no | no | `id:int!` | | `invoice.send` | bookkeeper | yes | yes | yes | `id:int!`, `to:string` | +| `invoice.pay` | bookkeeper | yes | yes | yes | `id:int!`, `voucher_id:int!` | | `employee.list` | viewer | yes | no | no | `active_only:bool` | | `employee.get` | viewer | yes | no | no | `id:int!` | | `employee.create` | bookkeeper | yes | yes | yes | `name:string!`, `personal_no:string!`, `address:string`, `postal_code:string`, `city:string`, `bank_account:string`, `email:string`, `salary_account:string`, `monthly_salary_ore:int=0`, `tax_table:int=30`, `tax_column:int=1` | @@ -921,16 +940,21 @@ commands. Implemented screens (0.1.0-dev): returns to the list. A failed auto-match keeps the posted voucher and shows the server error. - **Fakturor** — invoice list (`invoice.list`, newest first) with number, - date, customer, total and status (`utfärdad`/`krediterad`). Ctrl+N opens - the form, Enter the detail. The form has the customer picker, invoice/due - (due defaults from the customer's payment days) and delivery dates, er/var - referens and rows (beskrivning, antal, enhet, à-pris, moms, anm); `F5` - previews the real PDF (`invoice.preview`, nothing stored, no number - consumed), `Ctrl+Enter` issues (`invoice.issue`) and then asks - "Skicka faktura <nr> till <e-post>?". The detail shows header and rows; - `p` fetches the stored PDF (`invoice.pdf`) and `s` sends it - (`invoice.send`). In the list, `n` sets the next invoice number - (`invoice.sequence_get`/`sequence_set`, owner-only). + date, customer, total and status (`utfärdad`/`krediterad`/`betald + <datum>`). Ctrl+N opens the form, Enter the detail. The form has the + customer picker, invoice/due (due defaults from the customer's payment + days) and delivery dates, er/var referens and rows (beskrivning, antal, + enhet, à-pris, moms, anm); a row with only beskrivning is a free-text line + (`text` rows, no amount). `F5` previews the real PDF (`invoice.preview`, + nothing stored, no number consumed), `F9` issues (`invoice.issue`) and + then asks "Skicka faktura <nr> till <e-post>?". The detail shows header + and rows and offers `p = visa PDF` (`invoice.pdf`), `s = skicka` + (`invoice.send`), `u = duplicera` (a new draft with the same rows and + today's dates) and, on unpaid invoices, `b = kvittera betalning`: a + prefilled payment voucher (debit `bank_account`, credit + `invoice_receivable_account`) is opened in the ordinary voucher form and, + once posted, linked with `invoice.pay`. In the list, `n` sets the next + invoice number (`invoice.sequence_get`/`sequence_set`, owner-only). - **Kunder** — the customer register (name, address, postal code, city, VAT number, e-mail, your reference, payment days, notes). Ctrl+N creates, Enter edits (F5 validates with a dry run, Ctrl+Enter saves), `d` |
