Commit Graph

34 Commits

Author SHA1 Message Date
jordi fita mas d6034ad732 Add discount and tax classes columns to invoice
This was actually the (first) reason we added the tax classes: to show
them in columns on the invoice—without the class we would need a column
for each tax rate, even though they are the same tax.

The invoice design has the product total with taxes at the last column,
above the tax base, that i am not so sure about, but it seems that it
has not brought any problem whatsoever so far, so it remains as is.

Had to reduce the invoice’s font size to give more space to the table
or the columns would be right next to each other.  Oriol also told me
to add more vertical spacing to the table’s footer.
2023-03-01 14:08:12 +01:00
jordi fita mas 6a8ebab686 Add “bottom margin” to the invoice’s legal text
I did not see it in the original design.
2023-03-01 11:43:06 +01:00
jordi fita mas 4d2379555e Convert invoices to PDF with WeasyPrint
Although it is possible to just print the invoice from the browser, many
people will not even try an assume that they can not create a PDF for
the invoice.

I thought of using Groff or TeX to create the PDF, but it would mean
maintaining two templates in two different systems (HTML and whatever i
would use), and would probably look very different, because i do not
know Groff or TeX that well.

I wish there was a way to tell the browser to print to PDF, and it can
be done, but only with the Chrome Protocol to a server-side running
Chrome instance.   This works, but i would need a Chrome running as a
daemon.

I also wrote a Qt application that uses QWebEngine to print the PDF,
much like wkhtmltopdf, but with support for more recent HTML and CSS
standards.  Unfortunately, Qt 6.4’s embedded Chromium does not follow
break-page-inside as well as WeasyPrint does.

To use WeasyPrint, at first i wanted to reach the same URL as the user,
passing the cookie to WeasyPrint so that i can access the same invoice
as the user, something that can be done with wkhtmltopdf, but WeasyPrint
does not have such option.  I did it with a custom Python script, but
then i need to package and install that script, that is not that much
work, but using the Debian-provided script is even less work, and less
likely to drift when WeasyPrint changes API.

Also, it is unnecessary to do a network round-trip from Go to Python
back to Go, because i can already write the invoice HTML as is to
WeasyPrint’s stdin.
2023-02-26 17:26:09 +01:00
jordi fita mas 843f7746cf Adapt the invoice design to Oriol’s 2023-02-25 13:48:57 +01:00
jordi fita mas 419ac3ed46 Adjust invoice.css to work with WeasyPrint too
I am planning to use WeasyPrint to “generate PDF” from the same HTML
that the user view, but it seems that it does not support flex’s gap
and some other properties that i had to change to work in both user
agents.

I also moved the invoice’s “footer” inside the last product’s body
because i do not want the footer to be a “widow”.
2023-02-25 03:16:20 +01:00
jordi fita mas 18fba2964f Add invoice view, with print CSS
Had to group name and description rows in tbody because i do not want
to break them on pagination.

I also could not use tfoot for subtotal, taxes, and total because then
they appear on every page.

The disclaimer should appear only at the very bottom of the last page,
but i do not know how to do that; using position fixed shows it on
every page.
2023-02-24 12:22:15 +01:00
jordi fita mas 97ef02b0f9 Add views to compute taxes and total amount of invoices
They are not functions because i need to join them with the main
invoice relation, and although possible is a bit more awkward with
functions.

The taxes have their own relation because i will need them grouped by
their name in the PDF, so it will probably be a select for that
relation.
2023-02-22 14:39:38 +01:00
jordi fita mas c1e443e3bc Move the new product description before the taxes
Because in the “default view” that position has a lot of space that is
best used by a large text area than a simple number input.
2023-02-21 13:55:59 +01:00
jordi fita mas 5c15b9de20 Add the bare-bones form for invoices 2023-02-11 22:16:48 +01:00
jordi fita mas 73ca559209 Add template for InputField of type textarea 2023-02-07 15:28:22 +01:00
jordi fita mas ae1949024b Allow optional select with empty label
This is not yet necessary, but the empty label is because i do not want
to select a default tax for products—at least, not without a setting for
it.

Since i need to add the required attribute now to select, because
otherwise the browser would allow sending that empty value, i did not
want to do it unconditionally, just in case.
2023-02-05 14:06:33 +01:00
jordi fita mas a0a3a5561d Add breadcrumbs 2023-02-03 13:58:10 +01:00
jordi fita mas 3b3c3bd302 Fix “translation” of ‘(opcional)’ for fields in Spanish and Catalan 2023-01-31 15:43:47 +01:00
jordi fita mas 9f17f55547 Validate profile form and use templates for fields
Let’s start first with a non-fancy validation method with just if
conditionals instead of bringing yet another complicated library.  I
hope i do not regret it.

I wanted to move all the input field to a template because all that
gobbledygook with the .input div and repeating the label in the
placeholder was starting to annoy me.  Now with error messages was even
more concerning.

I did not know whether the label should be a part of the input fields
or something that the template should do.  At the end i decided that
it makes more sense to be part of the input field because in the error
messages i use that same label, thus the template does not have a say
in that, and, besides, it was just easier to write the template.

The same with the error messages: i’ve seen frameworks that have a map
with the field’s id/name to the error slice, but then it would be
a bit harder to write the template.

I added AddError functions instead of just using append inside the
validator function, and have a local variable for whether it all went
OK, because i was worried that i would leave out the `ok = false`
in some conditions.

I had started writing “constructors” functions for InputField and
SelectField, but then had to add other methods to change the required
field and who knows what else, and in the end it was easier to just
construct the field inline.
2023-01-31 15:40:12 +01:00
jordi fita mas 3117c9a268 Rename #profilemenu to #profile-menu, for consistency 2023-01-31 13:25:57 +01:00
jordi fita mas 873d36abab Ignore an Intellij’s warning for remixicon font 2023-01-31 13:24:26 +01:00
jordi fita mas 93ec8b74c0 Move nav’s padding into its links
Otherwise, the padding is white on hover and looks weird.
2023-01-31 13:21:10 +01:00
jordi fita mas 5fc92a5748 Remove unused Remixicon files
The symbols.svg files is for referencing from other SVG files with
xlink; the .glyph.json seems to be used for the search app; and the
.less file is useless to me because i do not use less.
2023-01-31 13:17:51 +01:00
jordi fita mas de73743043 Fix use of invalid CSS property text-color 2023-01-30 16:38:15 +01:00
jordi fita mas 7b3dfc6e44 Remove redundant unit from CSS rule 2023-01-30 16:36:14 +01:00
jordi fita mas 69c60fe388 Clean up SVG icon 2023-01-30 16:33:49 +01:00
jordi fita mas 5a199a3d8e Add the contact relation and a rough first form 2023-01-29 15:14:31 +01:00
jordi fita mas 717ae9d5d4 Add an (optional) suffix to labels of optional fields
For now i use CSS because we are not sure whether we will keep it this
way or not and, until we finally decide, with CSS is the easiest to
remove later on.
2023-01-29 15:13:47 +01:00
jordi fita mas 666935b54c Add the tax relation with very rough form and handler 2023-01-28 14:18:58 +01:00
jordi fita mas 7513030334 Fix the width of the country’s select 2023-01-28 00:11:56 +01:00
jordi fita mas 627841d4dd Add the company relation and read-only form to edit
I do not have more time to update the update to the company today, but i
believe this is already a good amount of work for a commit.

The company is going to be used for row level security, as users will
only have access to the data from companies they are granted access, by
virtue of being in the company_user relation.

I did not know how add a row level security policy to the company_user
because i needed the to select on the same relation and this is not
allowed, because it would create an infinite loop.

Had to add the vat, pg_libphonenumber, and uri extensions in order to
validate VAT identification numbers, phone numbers, and URIs,
repectively.  These libraries are not in Debian, but i created packages
for them all in https://dev.tandem.ws/tandem.
2023-01-24 21:46:07 +01:00
jordi fita mas f9e22c0789 Complete the style of the profile dialog 2023-01-23 19:35:49 +01:00
jordi fita mas 22509dd683 Implement profile menu with <details>
It works better than with the weird hover behaviour i could do in CSS,
and it already has most of the aria roles needed.

The only tricky part is to allow closing it by clicking anywhere else,
that is done by “extending” the <summary> to the whole screen, with a
lower z-index than the menu but higher than the rest of controls, that
way we force people to click on that summary.
2023-01-23 18:52:18 +01:00
jordi fita mas c7e34cc488 Leave the label always to the same position on the left 2023-01-23 12:44:56 +01:00
jordi fita mas c6eb1ef24e Change input field to be “Material-like”, as per design 2023-01-23 00:41:54 +01:00
jordi fita mas 1675ada70b Make the menu work as a menu 2023-01-22 22:30:15 +01:00
jordi fita mas 6f2da865c0 Reduce HTML’s font-size to (usually) have 1rem = 10px
It is far easier for me to “see” the sizes if they are multiples of 10,
especially given that the designs we do in Penpot use a 10 × 10 pixels
grid.
2023-01-22 20:27:43 +01:00
jordi fita mas ea9e830a75 Add user_profile view to update the profile with form
Since users do not have access to the auth scheme, i had to add a view
that selects only the data that they can see of themselves (i.e., no
password or cookie).

I wanted to use the `request.user.id` setting that i set in
check_cookie, but this would be bad because anyone can change that
parameter and, since the view is created by the owner, could see and
*change* the values of everyone just by knowing their id.  Thus, now i
use the cookie instead, because it is way harder to figure out, and if
you already have it you can just set to your browser and the user is
fucked anyway; the database can not help here.

I **am** going to use the user id in row level security policies, but
not the value coming for the setting but instaed the one in the
`user_profile`, since it already is “derived” from the cookie, that’s
why i added that column to the view.

The profile includes the language, that i do not use it yet to switch
the locale, so i had to add a relation of the available languages, for
constraint purposes.  There is no NULL language, and instead i added the
“Undefined” language, with ‘und’ tag’, to represent “do not know/use
content negotiation”.

The languages in that relation are the same i used to have inside
locale.go, because there is no point on having options for languages i
do not have the translation for, so i now configure the list of
available languages user in content negotiation from that relation.

Finally, i have added all font from RemixIcon because that’s what we
used in the design and i am going to use quite a lot of them.

There is duplication in the views; i will address that in a different
commit.
2023-01-22 02:23:09 +01:00
jordi fita mas d434d040af Add the very basic styles 2023-01-17 22:28:47 +01:00