Commit Graph

284 Commits

Author SHA1 Message Date
jordi fita mas 689eab3a08 Use “Save” for all submit buttons of new/edit forms
Oriol says it is easier to understand for users.
2023-05-26 13:38:04 +02:00
jordi fita mas bec1305e8a Add an empty product to blank invoice form
There is no point in creating a new invoice without products, thus we
were forcing users to always use the “Add product” button for no reason
other than it was easier for me….

I wanted to add the product inside ServeInvoice, when the slug is “new”,
but then it tried to compute the invoice total without price or quantity
and it failed.  Thus, i add that product after it has done the
computation query.
2023-05-26 13:33:49 +02:00
jordi fita mas cbe868b6d6 Remove “shadow” variables inside invoices.ServeInvoice 2023-05-26 13:30:45 +02:00
jordi fita mas 992bbf32a9 Toggle filters forms
I tried this already when i started adding filters, but i tried to use
AlpineJS for that, and could not because it would reset the context each
time i submitted the filters, due to HTMx replacing the whole content.

I realized that the only thing i need is some “flag” to show and hide
the form with CSS.  I do not even need AlpineJS for that, but i used it
anyway because then i can use the x-cloak thing to hidde the toggle
button for users with JavaScript disabled.

Similarly, the body by default has that “flag” set in the markup, and is
removed when AlpineJS is initialized, thus if JavaScript is disabled the
filters form is shown nevertheless.
2023-05-24 12:13:09 +02:00
jordi fita mas 92edbdfc4d Reindent numerus.css with IntelliJ 2023-05-24 12:06:03 +02:00
jordi fita mas e68eb52578 Don’t show the “(optional)” label for filter inputs
It adds nothing, as all input fields for filters show be optional.
2023-05-24 11:41:48 +02:00
oriol carbonell pujolàs 79ec3ae4d6 Improve the CSS and general design 2023-05-23 23:13:21 +02:00
jordi fita mas bf2796190f Change the rows of the product description to 1 2023-05-23 15:25:55 +02:00
jordi fita mas d2a06dd1c0 Add class=filters to filters forms 2023-05-23 14:50:46 +02:00
jordi fita mas 9096cfe4f2 Wrap filter buttons with <noscript>
Since forms are already submitted on change, Oriol does not like the
idea of having a useless button around breaking the form grid.
2023-05-23 14:34:46 +02:00
jordi fita mas e974406870 Remove the “all” columns from products and contacts
That column was supposed to have a checkbox for batch operations, but
we do not have any operation that would like to perform to many products
or contacts at the same time.  For now, at least.
2023-05-23 14:21:04 +02:00
jordi fita mas 6c7762057c Change “Edit Invoice” button to just “Save” 2023-05-23 14:18:26 +02:00
jordi fita mas 65ee8a139c Use white-space: pre-line for invoice notes and payment instructions
I want the `white-space: pre` to preserve the newline characters that
users may have used, but this prevents line wrapping and long lines are
not confined within the page margins.

`pre-line` preserves the newlines, but collapses spaces and tabs, and
wraps long text, which is more what i want.
2023-05-22 11:23:19 +02:00
jordi fita mas 5cae0efe8f Fix validation of product ID for invoice products that have none
For some reason, i assumed that if the invoice product has and ID, that
is it comes from the database, it must also have a product ID, which is
incorrect, because we allow invoice lines with products not added to the
product relation.

I am using zero to mean “no product ID”, so now that validation has to
include the zero as well.
2023-05-22 11:16:21 +02:00
jordi fita mas bbabf5c733 Use a null as product ID when adding new products to invoices
Otherwise, pgx (rightfully) tries to convert a "" into a integer, as
this is the field’s type, cannot, and panics with an error.

Added a IntegerOrNull method to FormField because this is exactly the
same that happens with the invoiceProductId, and made no sense to have
to do the logic twice, or in a function inside form.
2023-05-22 11:06:06 +02:00
jordi fita mas 46b079cb0b Add tooltips to the SVG chart with date and amount 2023-05-21 19:22:46 +02:00
jordi fita mas 02a4fad443 Refactor a bit the code that draws SVG polylines in circles 2023-05-21 18:59:42 +02:00
jordi fita mas eb47988464 Add a background rectangle to the chart and fix NaN when max = 0 2023-05-21 00:14:48 +02:00
jordi fita mas 39b0b801b2 Add income and expenses chart in SVG 2023-05-20 15:53:59 +02:00
jordi fita mas d1b978054b Fix dashboard period ranges and add previous month and quarter options
Oriol told me what he actually wants: a way to see the current month,
quarter, and year for both double-check that the taxes form are filled
in correct and to see whether the business is doing well.  This is
specially important for the quarter period, as he has to fill taxes
each quarter.  Thus, the “last 90 days” thing i did was easier for me,
but completely useless for him.

We also decided to add previous month and previous quarter options
because it would be unfair to expect users check that data exactly the
last day or “lose access” to it.
2023-05-19 14:05:57 +02:00
jordi fita mas 121f03b63c Add expense_tax_amount to properly compute the net income 2023-05-18 12:36:18 +02:00
oriol carbonell pujolàs 31eff5e3ab Update 'web/static/numerus.css' 2023-05-17 15:50:08 +00:00
jordi fita mas 987a99e0df Add a period filter for the dashboard
I do not yet know whether Oriol wants a YTD or MAT period, and i went
for the easiest for me: everything is MAT.
2023-05-17 12:05:30 +02:00
jordi fita mas f68aba1387 Coalesce individual dashboard results to 0 when computing net income 2023-05-16 15:24:14 +02:00
jordi fita mas ef1003a685 Coalesce dashboard results to 0 2023-05-16 15:14:20 +02:00
jordi fita mas ce42880697 Begin the dashboard with expenses, gross income, net income, and taxes
For now i use a too-long SQL query for that, but will probably replace
it with a view.  I have to check that it is correct before i do so,
however.
2023-05-16 14:56:49 +02:00
jordi fita mas 7921b9cf80 Add attach_to_expense SQL function
Just to avoid SQL “logic” in Go source.
2023-05-15 12:38:40 +02:00
jordi fita mas ee2ed598a3 Fix invoice’s colspan for the empty index table’s row 2023-05-14 18:47:16 +02:00
jordi fita mas 3161d54aba Add expense’s file input to new and edit forms
I had to change MethodOverrider to check whether the form is encoded as
multipart/form-data or i would not be able to get the method field from
forms with files.

For now i add the file manually, i.e., outside add_expense and
edit_expense PL/pgSQL functions, because it was faster for me, but i
will probably add an attach_to_expense function, or something like that,
to avoid having the whole ON CONFLICT logic inside Golang—this belongs
to the database.
2023-05-14 18:46:16 +02:00
jordi fita mas 5d46bbb95b Add the relation to store the expense’s attachment files
It is a separate table because we allow expenses to not have such an
attachment, although we allow only an attachment per expense, and i do
not want to have a bunch of nullable columns for that.

I decided to keep the files in the database, contrary to “conventional
wisdom” of storing files in the filesystem, because these attachments
are invoices and such documets that are an integral part of the expense
relation.  In other words, losing these files would render the expense
(almost) useless.  Thus, the ACID guarantees of the database are the
most appropriate place for them.
2023-05-13 21:23:24 +02:00
jordi fita mas f639602170 Add contact’s inline form for tags 2023-05-12 11:32:39 +02:00
jordi fita mas df37583cc6 Add the actions menu to products and contacts 2023-05-11 23:32:21 +02:00
jordi fita mas 970340277d Add the contact filter form 2023-05-10 18:56:07 +02:00
jordi fita mas 856ddde00e Add the inline form for product tags 2023-05-09 12:18:31 +02:00
jordi fita mas f0f98e200c Add inline tag form for expenses 2023-05-08 12:58:54 +02:00
jordi fita mas 664088c748 Add filter form to expenses 2023-05-07 22:49:52 +02:00
jordi fita mas 1415c3ef10 Moved the link to edit expense from the invoicer’s name to a menu
This menu will also have options like delete, and whatever we like to do
to expenses, like invoices do.
2023-05-06 11:08:21 +02:00
jordi fita mas 49c41681ce Add PUT method to expense’s URL and call edit_expense 2023-05-05 10:59:35 +02:00
jordi fita mas 4a9c3748cd Guard a StatusUnprocessableEntity with check for HTMx request
Otherwise, HTMx would just ignore the HTML returned by the server and
dispatch an error.
2023-05-05 10:57:48 +02:00
jordi fita mas 73497eb051 Add missing return on not found for edit product 2023-05-05 10:54:40 +02:00
jordi fita mas 251080cbe5 Add SQL function to edit expenses 2023-05-04 12:34:47 +02:00
jordi fita mas 55d650bd62 Add expenses’ index and add form 2023-05-03 12:46:25 +02:00
jordi fita mas 97ad76d82c Deduplicate the SQL for getting the options for customer’s select field 2023-05-03 12:40:07 +02:00
jordi fita mas 5984745c89 Add function to create expenses 2023-05-02 11:29:57 +02:00
jordi fita mas b904aea9f2 Add the relation of expense taxes 2023-05-01 16:17:36 +02:00
jordi fita mas 781c935703 Add the expense relation 2023-04-30 16:06:16 +02:00
jordi fita mas 19bcfc29e8 Update HTMx version to 1.9.2
I was hit with a couple of bugs: hx-on not properly de-initializing,
with a workaround in 43fffb68 and properly fixed with version 1.9.2;
and elements with naked hx-trigger did not work with hx-boost, as i do
for the tag inline form, fixed in 1.9.1.

The other bug fixed in 1.9.1, play well with other libraries that also
use the window.onpopstate, did not affect me, i believe.
2023-04-29 16:20:13 +02:00
jordi fita mas 4162da3a06 Force Content-Type to text/html when rendering a template
By chance, i found out that sometimes Go returned a Content-Type header
of text/plain for some responses to HTMx request.  Go’s documentation
for http.ResponseWriter.Write sheds some light to this issue:

> If the Header does not contain a Content-Type line, Write adds a
> Content-Type set to the result of passing the initial 512 bytes of
> written data to DetectContentType.

http.DetectContentType has “sniff signatures” for the most common HTML
elements, such as `<BODY`, `<P`, or even `<!--`, but when the template
only has elements not in that list, the text “text sniff signature”
kicks in because the content does not contain binary data bytes, as
specified in [0], §7.1, step 9.

I can not change mustRenderTemplate’s wr parameter, and its callers’,
to be of type http.ResponseWriter because mustWriteInvoicePdf writes
the template to a pipe object, which is not of this type.  Thus, i have
to resort to type assertion inside the method.

[0]: https://mimesniff.spec.whatwg.org/#identifying-a-resource-with-an-unknown-mime-type
2023-04-29 15:59:26 +02:00
jordi fita mas d941adcdfe Trigger a recompute when price, quantity, discount, or vat changes
I had to add the correct change event to the select in order for this to
work, too; in tags it was already done, i and did something very
similar.
2023-04-28 00:22:28 +02:00
jordi fita mas 86ccbbe830 Add keyboard controls for product search
They are almost the same as for the multiselect, except that it “clicks”
the option to “select” it, as this will trigger the replacement of the
<fieldset> with the whole product.
2023-04-28 00:06:48 +02:00