This is because when i create the demo users then i can no remove the
available languages before users, due the constrain, and i can no use
sqitch rebase or revert.
This is for new users that do not start using the application from the
beginning of the current fiscal year and, therefore, need to create
invoices starting from a specific number.
I had to change the constraint on the currval to allow zero, otherwise
it would not be possible to set 1 as the next number, because users
can also not delete the row.
It is better that way because it works without JavaScript; if HTMx is
not available, it will just use regulars forms.
The problem is that most of the submit buttons where using formaction
to send the request to a different action, and only one button was the
“real” action. Since i could not pass the formaction to
invoice-product-form template, i have changed the “default” action to
the one with “ancillary” functions.
I have to use a different action to remove for each product because i
can not pass the index to the backend without JavaScript: it only
depends on the button click, that already has a name for the action.
Thus, in a way, i have “merged” the action and the index in a single
name.
With this button, it is no longer necessary to set the quantity to zero
to remove, at least not with JavaScript. This is why i am using Alpine:
to use x-cloak and hide it from non-JavaScript users.
Although, i wonder if it would not be better to use HTMx for that?
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.
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.
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.
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.
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.
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.
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.
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.
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.