Compare commits

...

5 Commits

Author SHA1 Message Date
jordi fita mas ee0b5d0bdc Rename Contact to Customer in quotes and invoices’ fields
In this case, the invoicee or quotee _is_ a (potential) customer, so
there is no point on calling them “contact”.
2023-06-20 11:37:02 +02:00
jordi fita mas de2a2f5912 Updated contacts’ table heading to read Contact instead of Customer 2023-06-20 11:34:00 +02:00
jordi fita mas 07c1071975 Add total amount for quotes, invoices, and expenses tables
We have shown the application to a potential user, and they told us that
it would be very useful to have a total in the table’s footer, so that
they can verify the amount with the bank’s extracts.
2023-06-20 11:33:28 +02:00
jordi fita mas 8a4f80783d Rename Customer expense filter to Contact
It would be very unusual to have an expense from a customer, and we do
not have (yet) a name for supplier or whatever it should be here, so i
used the same name we use for the column in the table.
2023-06-20 11:17:07 +02:00
jordi fita mas 1ad771b771 Update module dependencies to match the version of Debian 12 packages 2023-06-17 20:42:23 +02:00
12 changed files with 399 additions and 298 deletions

17
go.mod
View File

@ -1,15 +1,22 @@
module dev.tandem.ws/tandem/numerus
go 1.16
go 1.19
require (
github.com/jackc/pgx/v4 v4.17.2
github.com/jackc/pgtype v1.10.0
github.com/jackc/pgx/v4 v4.15.0
github.com/julienschmidt/httprouter v1.3.0
github.com/leonelquinteros/gotext v1.5.1
golang.org/x/text v0.3.8
github.com/leonelquinteros/gotext v1.5.0
golang.org/x/text v0.7.0
)
require (
github.com/jackc/pgtype v1.12.0
github.com/jackc/chunkreader/v2 v2.0.1 // indirect
github.com/jackc/pgconn v1.13.0 // indirect
github.com/jackc/pgio v1.0.0 // indirect
github.com/jackc/pgpassfile v1.0.0 // indirect
github.com/jackc/pgproto3/v2 v2.3.1 // indirect
github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b // indirect
github.com/jackc/puddle v1.3.0 // indirect
golang.org/x/crypto v0.0.0-20220829220503-c86fa9a7ed90 // indirect
)

38
go.sum
View File

@ -14,7 +14,6 @@ github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/me
github.com/gofrs/uuid v4.0.0+incompatible h1:1SD/1F5pU8p29ybwgQSwpQk+mwdRrXCYuPhW6m+TnJw=
github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
github.com/jackc/chunkreader v1.0.0 h1:4s39bBR8ByfqH+DKm8rQA3E1LHZWB9XWcrz8fqaZbe0=
github.com/jackc/chunkreader v1.0.0/go.mod h1:RT6O25fNZIuasFJRyZ4R/Y2BbhasbmZXF9QQ7T3kePo=
github.com/jackc/chunkreader/v2 v2.0.0/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk=
github.com/jackc/chunkreader/v2 v2.0.1 h1:i+RDz65UE+mmpjTfyz0MoVTnzeYxroil2G82ki7MGG8=
@ -25,6 +24,7 @@ github.com/jackc/pgconn v0.0.0-20190831204454-2fabfa3c18b7/go.mod h1:ZJKsE/KZfsU
github.com/jackc/pgconn v1.8.0/go.mod h1:1C2Pb36bGIP9QHGBYCjnyhqu7Rv3sGshaQUvmfGIB/o=
github.com/jackc/pgconn v1.9.0/go.mod h1:YctiPyvzfU11JFxoXokUOOKQXQmDMoJL9vJzHH8/2JY=
github.com/jackc/pgconn v1.9.1-0.20210724152538-d89c8390a530/go.mod h1:4z2w8XhRbP1hYxkpTuBjTS3ne3J48K83+u0zoyvg2pI=
github.com/jackc/pgconn v1.11.0/go.mod h1:4z2w8XhRbP1hYxkpTuBjTS3ne3J48K83+u0zoyvg2pI=
github.com/jackc/pgconn v1.13.0 h1:3L1XMNV2Zvca/8BYhzcRFS70Lr0WlDg16Di6SFGAbys=
github.com/jackc/pgconn v1.13.0/go.mod h1:AnowpAqO4CMIIJNZl2VJp+KrkAZciAkhEl0W0JIobpI=
github.com/jackc/pgio v1.0.0 h1:g12B9UwVnzGhueNavwioyEEpAmqMe1E/BN9ES+8ovkE=
@ -35,7 +35,6 @@ github.com/jackc/pgmock v0.0.0-20210724152146-4ad1a8207f65 h1:DadwsjnMwFjfWc9y5W
github.com/jackc/pgmock v0.0.0-20210724152146-4ad1a8207f65/go.mod h1:5R2h2EEX+qri8jOWMbJCtaPWkrrNc7OHwsp2TCqp7ak=
github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM=
github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
github.com/jackc/pgproto3 v1.1.0 h1:FYYE4yRw+AgI8wXIinMlNjBbp/UitDJwfj5LqqewP1A=
github.com/jackc/pgproto3 v1.1.0/go.mod h1:eR5FA3leWg7p9aeAqi37XOTgTIbkABlvcPB3E5rlc78=
github.com/jackc/pgproto3/v2 v2.0.0-alpha1.0.20190420180111-c116219b62db/go.mod h1:bhq50y+xrl9n5mRYyCBFKkpRVTLYJVWeCc+mEAI3yXA=
github.com/jackc/pgproto3/v2 v2.0.0-alpha1.0.20190609003834-432c2951c711/go.mod h1:uH0AWtUmuShn0bcesswc4aBTWGvw0cAxIJp+6OB//Wg=
@ -43,6 +42,7 @@ github.com/jackc/pgproto3/v2 v2.0.0-rc3/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvW
github.com/jackc/pgproto3/v2 v2.0.0-rc3.0.20190831210041-4c03ce451f29/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvWKnT95C46ckYeM=
github.com/jackc/pgproto3/v2 v2.0.6/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA=
github.com/jackc/pgproto3/v2 v2.1.1/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA=
github.com/jackc/pgproto3/v2 v2.2.0/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA=
github.com/jackc/pgproto3/v2 v2.3.1 h1:nwj7qwf0S+Q7ISFfBndqeLwSwxs+4DPsbRFjECT1Y4Y=
github.com/jackc/pgproto3/v2 v2.3.1/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA=
github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b h1:C8S2+VttkHFdOOCXJe+YGfa4vHYwlt4Zx+IVXQ97jYg=
@ -51,17 +51,18 @@ github.com/jackc/pgtype v0.0.0-20190421001408-4ed0de4755e0/go.mod h1:hdSHsc1V01C
github.com/jackc/pgtype v0.0.0-20190824184912-ab885b375b90/go.mod h1:KcahbBH1nCMSo2DXpzsoWOAfFkdEtEJpPbVLq8eE+mc=
github.com/jackc/pgtype v0.0.0-20190828014616-a8802b16cc59/go.mod h1:MWlu30kVJrUS8lot6TQqcg7mtthZ9T0EoIBFiJcmcyw=
github.com/jackc/pgtype v1.8.1-0.20210724151600-32e20a603178/go.mod h1:C516IlIV9NKqfsMCXTdChteoXmwgUceqaLfjg2e3NlM=
github.com/jackc/pgtype v1.12.0 h1:Dlq8Qvcch7kiehm8wPGIW0W3KsCCHJnRacKW0UM8n5w=
github.com/jackc/pgtype v1.12.0/go.mod h1:LUMuVrfsFfdKGLw+AFFVv6KtHOFMwRgDDzBt76IqCA4=
github.com/jackc/pgtype v1.10.0 h1:ILnBWrRMSXGczYvmkYD6PsYyVFUNLTnIUJHHDLmqk38=
github.com/jackc/pgtype v1.10.0/go.mod h1:LUMuVrfsFfdKGLw+AFFVv6KtHOFMwRgDDzBt76IqCA4=
github.com/jackc/pgx/v4 v4.0.0-20190420224344-cc3461e65d96/go.mod h1:mdxmSJJuR08CZQyj1PVQBHy9XOp5p8/SHH6a0psbY9Y=
github.com/jackc/pgx/v4 v4.0.0-20190421002000-1b8f0016e912/go.mod h1:no/Y67Jkk/9WuGR0JG/JseM9irFbnEPbuWV2EELPNuM=
github.com/jackc/pgx/v4 v4.0.0-pre1.0.20190824185557-6972a5742186/go.mod h1:X+GQnOEnf1dqHGpw7JmHqHc1NxDoalibchSk9/RWuDc=
github.com/jackc/pgx/v4 v4.12.1-0.20210724153913-640aa07df17c/go.mod h1:1QD0+tgSXP7iUjYm9C1NxKhny7lq6ee99u/z+IHFcgs=
github.com/jackc/pgx/v4 v4.17.2 h1:0Ut0rpeKwvIVbMQ1KbMBU4h6wxehBI535LK6Flheh8E=
github.com/jackc/pgx/v4 v4.17.2/go.mod h1:lcxIZN44yMIrWI78a5CpucdD14hX0SBDbNRvjDBItsw=
github.com/jackc/pgx/v4 v4.15.0 h1:B7dTkXsdILD3MF987WGGCcg+tvLW6bZJdEcqVFeU//w=
github.com/jackc/pgx/v4 v4.15.0/go.mod h1:D/zyOyXiaM1TmVWnOM18p0xdDtdakRBa0RsVGI3U3bw=
github.com/jackc/puddle v0.0.0-20190413234325-e4ced69a3a2b/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
github.com/jackc/puddle v0.0.0-20190608224051-11cab39313c9/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
github.com/jackc/puddle v1.1.3/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
github.com/jackc/puddle v1.2.1/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
github.com/jackc/puddle v1.3.0 h1:eHK/5clGOatcjX3oWGBO/MpxpbHzSwud5EWTSCI+MX0=
github.com/jackc/puddle v1.3.0/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
github.com/julienschmidt/httprouter v1.3.0 h1:U0609e9tgbseu3rBINet9P48AI/D3oJs4dN7jwJOQ1U=
@ -73,8 +74,8 @@ github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORN
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/leonelquinteros/gotext v1.5.1 h1:vmddRn3gHp67YFjZLZE2AZsgYMT4IBTJhua4yfe7/4Q=
github.com/leonelquinteros/gotext v1.5.1/go.mod h1:/A4Y7BvIsf5JHO60E43ZQDVkV3qO+7eP8HjeqD6ChIA=
github.com/leonelquinteros/gotext v1.5.0 h1:ODY7LzLpZWWSJdAHnzhreOr6cwLXTAmc914FOauSkBM=
github.com/leonelquinteros/gotext v1.5.0/go.mod h1:OCiUVHuhP9LGFBQ1oAmdtNCHJCiHiQA8lf4nAifHkr0=
github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/lib/pq v1.1.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
@ -111,8 +112,6 @@ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q=
go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
@ -134,26 +133,19 @@ golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPh
golang.org/x/crypto v0.0.0-20201203163018-be400aefbc4c/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.0.0-20220829220503-c86fa9a7ed90 h1:Y/gsMcFOcR+6S6f3YeMKl5g+dZMEWqcz5Czj/GWYbkM=
golang.org/x/crypto v0.0.0-20220829220503-c86fa9a7ed90/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@ -167,20 +159,16 @@ golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.3.8 h1:nAL+RVCQ9uMn3vJZbV+MRnydTJFPf8qqY42YiA6MrqY=
golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
golang.org/x/text v0.7.0 h1:4BRB4x83lYWy72KwLD/qYDuTu7q9PjSagHvijDw7cLo=
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190425163242-31fd60d6bfdc/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
@ -188,10 +176,8 @@ golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgw
golang.org/x/tools v0.0.0-20190823170909-c4a336ef6a2f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20200103221440-774c71fcf114/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.1.10/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/tools v0.0.0-20200221224223-e1da425f72fd/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=

View File

@ -24,6 +24,7 @@ type ExpenseEntry struct {
type expensesIndexPage struct {
Expenses []*ExpenseEntry
TotalAmount string
Filters *expenseFilterForm
}
@ -38,41 +39,14 @@ func IndexExpenses(w http.ResponseWriter, r *http.Request, _ httprouter.Params)
}
page := &expensesIndexPage{
Expenses: mustCollectExpenseEntries(r.Context(), conn, company, filters),
TotalAmount: mustComputeExpensesTotalAmount(r.Context(), conn, filters),
Filters: filters,
}
mustRenderMainTemplate(w, r, "expenses/index.gohtml", page)
}
func mustCollectExpenseEntries(ctx context.Context, conn *Conn, company *Company, filters *expenseFilterForm) []*ExpenseEntry {
args := []interface{}{company.Id}
where := []string{"expense.company_id = $1"}
appendWhere := func(expression string, value interface{}) {
args = append(args, value)
where = append(where, fmt.Sprintf(expression, len(args)))
}
maybeAppendWhere := func(expression string, value string, conv func(string) interface{}) {
if value != "" {
if conv == nil {
appendWhere(expression, value)
} else {
appendWhere(expression, conv(value))
}
}
}
maybeAppendWhere("contact_id = $%d", filters.Customer.String(), func(v string) interface{} {
customerId, _ := strconv.Atoi(filters.Customer.Selected[0])
return customerId
})
maybeAppendWhere("invoice_number = $%d", filters.InvoiceNumber.String(), nil)
maybeAppendWhere("invoice_date >= $%d", filters.FromDate.String(), nil)
maybeAppendWhere("invoice_date <= $%d", filters.ToDate.String(), nil)
if len(filters.Tags.Tags) > 0 {
if filters.TagsCondition.Selected == "and" {
appendWhere("expense.tags @> $%d", filters.Tags)
} else {
appendWhere("expense.tags && $%d", filters.Tags)
}
}
where, args := filters.BuildQuery(nil)
rows := conn.MustQuery(ctx, fmt.Sprintf(`
select expense.slug
, invoice_date
@ -87,7 +61,7 @@ func mustCollectExpenseEntries(ctx context.Context, conn *Conn, company *Company
join currency using (currency_code)
where (%s)
order by invoice_date
`, strings.Join(where, ") AND (")), args...)
`, where), args...)
defer rows.Close()
var entries []*ExpenseEntry
@ -104,6 +78,18 @@ func mustCollectExpenseEntries(ctx context.Context, conn *Conn, company *Company
return entries
}
func mustComputeExpensesTotalAmount(ctx context.Context, conn *Conn, filters *expenseFilterForm) string {
where, args := filters.BuildQuery(nil)
return conn.MustGetText(ctx, "0", fmt.Sprintf(`
select to_price(sum(amount)::integer, decimal_digits)
from expense
join currency using (currency_code)
where (%s)
group by decimal_digits
`, where), args...)
}
func ServeExpenseForm(w http.ResponseWriter, r *http.Request, params httprouter.Params) {
locale := getLocale(r)
conn := getConn(r)
@ -323,7 +309,7 @@ func HandleUpdateExpense(w http.ResponseWriter, r *http.Request, params httprout
type expenseFilterForm struct {
locale *Locale
company *Company
Customer *SelectField
Contact *SelectField
InvoiceNumber *InputField
FromDate *InputField
ToDate *InputField
@ -335,10 +321,10 @@ func newExpenseFilterForm(ctx context.Context, conn *Conn, locale *Locale, compa
return &expenseFilterForm{
locale: locale,
company: company,
Customer: &SelectField{
Name: "customer",
Label: pgettext("input", "Customer", locale),
EmptyLabel: gettext("All customers", locale),
Contact: &SelectField{
Name: "contact",
Label: pgettext("input", "Contact", locale),
EmptyLabel: gettext("All contacts", locale),
Options: mustGetContactOptions(ctx, conn, company),
},
InvoiceNumber: &InputField{
@ -382,7 +368,7 @@ func (form *expenseFilterForm) Parse(r *http.Request) error {
if err := r.ParseForm(); err != nil {
return err
}
form.Customer.FillValue(r)
form.Contact.FillValue(r)
form.InvoiceNumber.FillValue(r)
form.FromDate.FillValue(r)
form.ToDate.FillValue(r)
@ -391,6 +377,41 @@ func (form *expenseFilterForm) Parse(r *http.Request) error {
return nil
}
func (form *expenseFilterForm) BuildQuery(args []interface{}) (string, []interface{}) {
var where []string
appendWhere := func(expression string, value interface{}) {
args = append(args, value)
where = append(where, fmt.Sprintf(expression, len(args)))
}
maybeAppendWhere := func(expression string, value string, conv func(string) interface{}) {
if value != "" {
if conv == nil {
appendWhere(expression, value)
} else {
appendWhere(expression, conv(value))
}
}
}
appendWhere("expense.company_id = $%d", form.company.Id)
maybeAppendWhere("contact_id = $%d", form.Contact.String(), func(v string) interface{} {
customerId, _ := strconv.Atoi(form.Contact.Selected[0])
return customerId
})
maybeAppendWhere("invoice_number = $%d", form.InvoiceNumber.String(), nil)
maybeAppendWhere("invoice_date >= $%d", form.FromDate.String(), nil)
maybeAppendWhere("invoice_date <= $%d", form.ToDate.String(), nil)
if len(form.Tags.Tags) > 0 {
if form.TagsCondition.Selected == "and" {
appendWhere("expense.tags @> $%d", form.Tags)
} else {
appendWhere("expense.tags && $%d", form.Tags)
}
}
return strings.Join(where, ") AND ("), args
}
func ServeEditExpenseTags(w http.ResponseWriter, r *http.Request, params httprouter.Params) {
conn := getConn(r)
locale := getLocale(r)

View File

@ -35,6 +35,7 @@ type InvoiceEntry struct {
type InvoicesIndexPage struct {
Invoices []*InvoiceEntry
TotalAmount string
Filters *invoiceFilterForm
InvoiceStatuses map[string]string
}
@ -49,44 +50,16 @@ func IndexInvoices(w http.ResponseWriter, r *http.Request, _ httprouter.Params)
return
}
page := &InvoicesIndexPage{
Invoices: mustCollectInvoiceEntries(r.Context(), conn, company, locale, filters),
Invoices: mustCollectInvoiceEntries(r.Context(), conn, locale, filters),
TotalAmount: mustComputeInvoicesTotalAmount(r.Context(), conn, filters),
Filters: filters,
InvoiceStatuses: mustCollectInvoiceStatuses(r.Context(), conn, locale),
}
mustRenderMainTemplate(w, r, "invoices/index.gohtml", page)
}
func mustCollectInvoiceEntries(ctx context.Context, conn *Conn, company *Company, locale *Locale, filters *invoiceFilterForm) []*InvoiceEntry {
args := []interface{}{locale.Language.String(), company.Id}
where := []string{"invoice.company_id = $2"}
appendWhere := func(expression string, value interface{}) {
args = append(args, value)
where = append(where, fmt.Sprintf(expression, len(args)))
}
maybeAppendWhere := func(expression string, value string, conv func(string) interface{}) {
if value != "" {
if conv == nil {
appendWhere(expression, value)
} else {
appendWhere(expression, conv(value))
}
}
}
maybeAppendWhere("contact_id = $%d", filters.Customer.String(), func(v string) interface{} {
customerId, _ := strconv.Atoi(filters.Customer.Selected[0])
return customerId
})
maybeAppendWhere("invoice.invoice_status = $%d", filters.InvoiceStatus.String(), nil)
maybeAppendWhere("invoice_number = $%d", filters.InvoiceNumber.String(), nil)
maybeAppendWhere("invoice_date >= $%d", filters.FromDate.String(), nil)
maybeAppendWhere("invoice_date <= $%d", filters.ToDate.String(), nil)
if len(filters.Tags.Tags) > 0 {
if filters.TagsCondition.Selected == "and" {
appendWhere("invoice.tags @> $%d", filters.Tags)
} else {
appendWhere("invoice.tags && $%d", filters.Tags)
}
}
func mustCollectInvoiceEntries(ctx context.Context, conn *Conn, locale *Locale, filters *invoiceFilterForm) []*InvoiceEntry {
where, args := filters.BuildQuery([]interface{}{locale.Language.String()})
rows := conn.MustQuery(ctx, fmt.Sprintf(`
select invoice.slug
, invoice_date
@ -104,7 +77,7 @@ func mustCollectInvoiceEntries(ctx context.Context, conn *Conn, company *Company
where (%s)
order by invoice_date desc
, invoice_number desc
`, strings.Join(where, ") AND (")), args...)
`, where), args...)
defer rows.Close()
var entries []*InvoiceEntry
@ -122,6 +95,18 @@ func mustCollectInvoiceEntries(ctx context.Context, conn *Conn, company *Company
return entries
}
func mustComputeInvoicesTotalAmount(ctx context.Context, conn *Conn, filters *invoiceFilterForm) string {
where, args := filters.BuildQuery(nil)
return conn.MustGetText(ctx, "0", fmt.Sprintf(`
select to_price(sum(total)::integer, decimal_digits)
from invoice
join invoice_amount using (invoice_id)
join currency using (currency_code)
where (%s)
group by decimal_digits
`, where), args...)
}
func mustCollectInvoiceStatuses(ctx context.Context, conn *Conn, locale *Locale) map[string]string {
rows := conn.MustQuery(ctx, "select invoice_status.invoice_status, isi18n.name from invoice_status join invoice_status_i18n isi18n using(invoice_status) where isi18n.lang_tag = $1 order by invoice_status", locale.Language.String())
defer rows.Close()
@ -220,6 +205,41 @@ func (form *invoiceFilterForm) Parse(r *http.Request) error {
return nil
}
func (form *invoiceFilterForm) BuildQuery(args []interface{}) (string, []interface{}) {
var where []string
appendWhere := func(expression string, value interface{}) {
args = append(args, value)
where = append(where, fmt.Sprintf(expression, len(args)))
}
maybeAppendWhere := func(expression string, value string, conv func(string) interface{}) {
if value != "" {
if conv == nil {
appendWhere(expression, value)
} else {
appendWhere(expression, conv(value))
}
}
}
appendWhere("invoice.company_id = $%d", form.company.Id)
maybeAppendWhere("contact_id = $%d", form.Customer.String(), func(v string) interface{} {
customerId, _ := strconv.Atoi(form.Customer.Selected[0])
return customerId
})
maybeAppendWhere("invoice.invoice_status = $%d", form.InvoiceStatus.String(), nil)
maybeAppendWhere("invoice_number = $%d", form.InvoiceNumber.String(), nil)
maybeAppendWhere("invoice_date >= $%d", form.FromDate.String(), nil)
maybeAppendWhere("invoice_date <= $%d", form.ToDate.String(), nil)
if len(form.Tags.Tags) > 0 {
if form.TagsCondition.Selected == "and" {
appendWhere("invoice.tags @> $%d", form.Tags)
} else {
appendWhere("invoice.tags && $%d", form.Tags)
}
}
return strings.Join(where, ") AND ("), args
}
func ServeInvoice(w http.ResponseWriter, r *http.Request, params httprouter.Params) {
conn := getConn(r)
company := mustGetCompany(r)

View File

@ -33,6 +33,7 @@ type QuoteEntry struct {
type QuotesIndexPage struct {
Quotes []*QuoteEntry
TotalAmount string
Filters *quoteFilterForm
QuoteStatuses map[string]string
}
@ -47,44 +48,16 @@ func IndexQuotes(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
return
}
page := &QuotesIndexPage{
Quotes: mustCollectQuoteEntries(r.Context(), conn, company, locale, filters),
Quotes: mustCollectQuoteEntries(r.Context(), conn, locale, filters),
TotalAmount: mustComputeQuotesTotalAmount(r.Context(), conn, filters),
Filters: filters,
QuoteStatuses: mustCollectQuoteStatuses(r.Context(), conn, locale),
}
mustRenderMainTemplate(w, r, "quotes/index.gohtml", page)
}
func mustCollectQuoteEntries(ctx context.Context, conn *Conn, company *Company, locale *Locale, filters *quoteFilterForm) []*QuoteEntry {
args := []interface{}{locale.Language.String(), company.Id}
where := []string{"quote.company_id = $2"}
appendWhere := func(expression string, value interface{}) {
args = append(args, value)
where = append(where, fmt.Sprintf(expression, len(args)))
}
maybeAppendWhere := func(expression string, value string, conv func(string) interface{}) {
if value != "" {
if conv == nil {
appendWhere(expression, value)
} else {
appendWhere(expression, conv(value))
}
}
}
maybeAppendWhere("contact_id = $%d", filters.Customer.String(), func(v string) interface{} {
customerId, _ := strconv.Atoi(filters.Customer.Selected[0])
return customerId
})
maybeAppendWhere("quote.quote_status = $%d", filters.QuoteStatus.String(), nil)
maybeAppendWhere("quote_number = $%d", filters.QuoteNumber.String(), nil)
maybeAppendWhere("quote_date >= $%d", filters.FromDate.String(), nil)
maybeAppendWhere("quote_date <= $%d", filters.ToDate.String(), nil)
if len(filters.Tags.Tags) > 0 {
if filters.TagsCondition.Selected == "and" {
appendWhere("quote.tags @> $%d", filters.Tags)
} else {
appendWhere("quote.tags && $%d", filters.Tags)
}
}
func mustCollectQuoteEntries(ctx context.Context, conn *Conn, locale *Locale, filters *quoteFilterForm) []*QuoteEntry {
where, args := filters.BuildQuery([]interface{}{locale.Language.String()})
rows := conn.MustQuery(ctx, fmt.Sprintf(`
select quote.slug
, quote_date
@ -103,7 +76,7 @@ func mustCollectQuoteEntries(ctx context.Context, conn *Conn, company *Company,
where (%s)
order by quote_date desc
, quote_number desc
`, strings.Join(where, ") AND (")), args...)
`, where), args...)
defer rows.Close()
var entries []*QuoteEntry
@ -121,6 +94,19 @@ func mustCollectQuoteEntries(ctx context.Context, conn *Conn, company *Company,
return entries
}
func mustComputeQuotesTotalAmount(ctx context.Context, conn *Conn, filters *quoteFilterForm) string {
where, args := filters.BuildQuery(nil)
return conn.MustGetText(ctx, "0", fmt.Sprintf(`
select to_price(sum(total)::integer, decimal_digits)
from quote
left join quote_contact using (quote_id)
join quote_amount using (quote_id)
join currency using (currency_code)
where (%s)
group by decimal_digits
`, where), args...)
}
func mustCollectQuoteStatuses(ctx context.Context, conn *Conn, locale *Locale) map[string]string {
rows := conn.MustQuery(ctx, "select quote_status.quote_status, isi18n.name from quote_status join quote_status_i18n isi18n using(quote_status) where isi18n.lang_tag = $1 order by quote_status", locale.Language.String())
defer rows.Close()
@ -219,6 +205,42 @@ func (form *quoteFilterForm) Parse(r *http.Request) error {
return nil
}
func (form *quoteFilterForm) BuildQuery(args []interface{}) (string, []interface{}) {
var where []string
appendWhere := func(expression string, value interface{}) {
args = append(args, value)
where = append(where, fmt.Sprintf(expression, len(args)))
}
maybeAppendWhere := func(expression string, value string, conv func(string) interface{}) {
if value != "" {
if conv == nil {
appendWhere(expression, value)
} else {
appendWhere(expression, conv(value))
}
}
}
appendWhere("quote.company_id = $%d", form.company.Id)
maybeAppendWhere("contact_id = $%d", form.Customer.String(), func(v string) interface{} {
customerId, _ := strconv.Atoi(form.Customer.Selected[0])
return customerId
})
maybeAppendWhere("quote.quote_status = $%d", form.QuoteStatus.String(), nil)
maybeAppendWhere("quote_number = $%d", form.QuoteNumber.String(), nil)
maybeAppendWhere("quote_date >= $%d", form.FromDate.String(), nil)
maybeAppendWhere("quote_date <= $%d", form.ToDate.String(), nil)
if len(form.Tags.Tags) > 0 {
if form.TagsCondition.Selected == "and" {
appendWhere("quote.tags @> $%d", form.Tags)
} else {
appendWhere("quote.tags && $%d", form.Tags)
}
}
return strings.Join(where, ") AND ("), args
}
func ServeQuote(w http.ResponseWriter, r *http.Request, params httprouter.Params) {
conn := getConn(r)
company := mustGetCompany(r)

163
po/ca.po
View File

@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: numerus\n"
"Report-Msgid-Bugs-To: jordi@tandem.blog\n"
"POT-Creation-Date: 2023-06-16 10:55+0200\n"
"POT-Creation-Date: 2023-06-20 11:35+0200\n"
"PO-Revision-Date: 2023-01-18 17:08+0100\n"
"Last-Translator: jordi fita mas <jordi@tandem.blog>\n"
"Language-Team: Catalan <ca@dodds.net>\n"
@ -157,7 +157,6 @@ msgid "Invoice Num."
msgstr "Núm. factura"
#: web/template/invoices/index.gohtml:52 web/template/quotes/index.gohtml:52
#: web/template/contacts/index.gohtml:40
msgctxt "title"
msgid "Customer"
msgstr "Client"
@ -216,6 +215,11 @@ msgstr "Duplica"
msgid "No invoices added yet."
msgstr "No hi ha cap factura."
#: web/template/invoices/index.gohtml:144 web/template/quotes/index.gohtml:152
#: web/template/expenses/index.gohtml:105
msgid "Total"
msgstr "Total"
#: web/template/invoices/view.gohtml:2 web/template/invoices/view.gohtml:33
msgctxt "title"
msgid "Invoice %s"
@ -449,6 +453,11 @@ msgctxt "action"
msgid "New contact"
msgstr "Nou contacte"
#: web/template/contacts/index.gohtml:40 web/template/expenses/index.gohtml:43
msgctxt "title"
msgid "Contact"
msgstr "Contacte"
#: web/template/contacts/index.gohtml:41
msgctxt "title"
msgid "Email"
@ -526,11 +535,6 @@ msgctxt "expense"
msgid "All"
msgstr "Totes"
#: web/template/expenses/index.gohtml:43
msgctxt "title"
msgid "Contact"
msgstr "Contacte"
#: web/template/expenses/index.gohtml:44
msgctxt "title"
msgid "Invoice Date"
@ -670,82 +674,82 @@ msgstr "No podeu deixar la contrasenya en blanc."
msgid "Invalid user or password."
msgstr "Nom dusuari o contrasenya incorrectes."
#: pkg/products.go:164 pkg/products.go:263 pkg/quote.go:801 pkg/invoices.go:851
#: pkg/products.go:164 pkg/products.go:263 pkg/quote.go:823 pkg/invoices.go:871
#: pkg/contacts.go:135
msgctxt "input"
msgid "Name"
msgstr "Nom"
#: pkg/products.go:169 pkg/products.go:290 pkg/quote.go:188 pkg/quote.go:608
#: pkg/expenses.go:202 pkg/expenses.go:361 pkg/invoices.go:189
#: pkg/invoices.go:603 pkg/invoices.go:1150 pkg/contacts.go:140
#: pkg/products.go:169 pkg/products.go:290 pkg/quote.go:174 pkg/quote.go:630
#: pkg/expenses.go:188 pkg/expenses.go:347 pkg/invoices.go:174
#: pkg/invoices.go:623 pkg/invoices.go:1170 pkg/contacts.go:140
#: pkg/contacts.go:325
msgctxt "input"
msgid "Tags"
msgstr "Etiquetes"
#: pkg/products.go:173 pkg/quote.go:192 pkg/expenses.go:365 pkg/invoices.go:193
#: pkg/products.go:173 pkg/quote.go:178 pkg/expenses.go:351 pkg/invoices.go:178
#: pkg/contacts.go:144
msgctxt "input"
msgid "Tags Condition"
msgstr "Condició de les etiquetes"
#: pkg/products.go:177 pkg/quote.go:196 pkg/expenses.go:369 pkg/invoices.go:197
#: pkg/products.go:177 pkg/quote.go:182 pkg/expenses.go:355 pkg/invoices.go:182
#: pkg/contacts.go:148
msgctxt "tag condition"
msgid "All"
msgstr "Totes"
#: pkg/products.go:178 pkg/expenses.go:370 pkg/invoices.go:198
#: pkg/products.go:178 pkg/expenses.go:356 pkg/invoices.go:183
#: pkg/contacts.go:149
msgid "Invoices must have all the specified labels."
msgstr "Les factures han de tenir totes les etiquetes."
#: pkg/products.go:182 pkg/quote.go:201 pkg/expenses.go:374 pkg/invoices.go:202
#: pkg/products.go:182 pkg/quote.go:187 pkg/expenses.go:360 pkg/invoices.go:187
#: pkg/contacts.go:153
msgctxt "tag condition"
msgid "Any"
msgstr "Qualsevol"
#: pkg/products.go:183 pkg/expenses.go:375 pkg/invoices.go:203
#: pkg/products.go:183 pkg/expenses.go:361 pkg/invoices.go:188
#: pkg/contacts.go:154
msgid "Invoices must have at least one of the specified labels."
msgstr "Les factures han de tenir com a mínim una de les etiquetes."
#: pkg/products.go:269 pkg/quote.go:815 pkg/invoices.go:865
#: pkg/products.go:269 pkg/quote.go:837 pkg/invoices.go:885
msgctxt "input"
msgid "Description"
msgstr "Descripció"
#: pkg/products.go:274 pkg/quote.go:819 pkg/invoices.go:869
#: pkg/products.go:274 pkg/quote.go:841 pkg/invoices.go:889
msgctxt "input"
msgid "Price"
msgstr "Preu"
#: pkg/products.go:284 pkg/quote.go:848 pkg/expenses.go:181 pkg/invoices.go:898
#: pkg/products.go:284 pkg/quote.go:870 pkg/expenses.go:167 pkg/invoices.go:918
msgctxt "input"
msgid "Taxes"
msgstr "Imposts"
#: pkg/products.go:309 pkg/quote.go:897 pkg/profile.go:92 pkg/invoices.go:947
#: pkg/products.go:309 pkg/quote.go:919 pkg/profile.go:92 pkg/invoices.go:967
msgid "Name can not be empty."
msgstr "No podeu deixar el nom en blanc."
#: pkg/products.go:310 pkg/quote.go:898 pkg/invoices.go:948
#: pkg/products.go:310 pkg/quote.go:920 pkg/invoices.go:968
msgid "Price can not be empty."
msgstr "No podeu deixar el preu en blanc."
#: pkg/products.go:311 pkg/quote.go:899 pkg/invoices.go:949
#: pkg/products.go:311 pkg/quote.go:921 pkg/invoices.go:969
msgid "Price must be a number greater than zero."
msgstr "El preu ha de ser un número major a zero."
#: pkg/products.go:313 pkg/quote.go:907 pkg/expenses.go:227 pkg/expenses.go:232
#: pkg/invoices.go:957
#: pkg/products.go:313 pkg/quote.go:929 pkg/expenses.go:213 pkg/expenses.go:218
#: pkg/invoices.go:977
msgid "Selected tax is not valid."
msgstr "Heu seleccionat un impost que no és vàlid."
#: pkg/products.go:314 pkg/quote.go:908 pkg/expenses.go:228 pkg/expenses.go:233
#: pkg/invoices.go:958
#: pkg/products.go:314 pkg/quote.go:930 pkg/expenses.go:214 pkg/expenses.go:219
#: pkg/invoices.go:978
msgid "You can only select a tax of each class."
msgstr "Només podeu seleccionar un impost de cada classe."
@ -852,141 +856,140 @@ msgstr "No podeu deixar el nom del mètode de pagament en blanc."
msgid "Payment instructions can not be empty."
msgstr "No podeu deixar les instruccions de pagament en blanc."
#: pkg/quote.go:161 pkg/quote.go:586 pkg/expenses.go:340 pkg/invoices.go:162
#: pkg/invoices.go:586
#: pkg/quote.go:147 pkg/quote.go:608 pkg/invoices.go:147 pkg/invoices.go:606
msgctxt "input"
msgid "Customer"
msgstr "Client"
#: pkg/quote.go:162 pkg/expenses.go:341 pkg/invoices.go:163
#: pkg/quote.go:148 pkg/invoices.go:148
msgid "All customers"
msgstr "Tots els clients"
#: pkg/quote.go:167 pkg/quote.go:580
#: pkg/quote.go:153 pkg/quote.go:602
msgctxt "input"
msgid "Quotation Status"
msgstr "Estat del pressupost"
#: pkg/quote.go:168 pkg/invoices.go:169
#: pkg/quote.go:154 pkg/invoices.go:154
msgid "All status"
msgstr "Tots els estats"
#: pkg/quote.go:173
#: pkg/quote.go:159
msgctxt "input"
msgid "Quotation Number"
msgstr "Número de pressupost"
#: pkg/quote.go:178 pkg/expenses.go:351 pkg/invoices.go:179
#: pkg/quote.go:164 pkg/expenses.go:337 pkg/invoices.go:164
msgctxt "input"
msgid "From Date"
msgstr "A partir de la data"
#: pkg/quote.go:183 pkg/expenses.go:356 pkg/invoices.go:184
#: pkg/quote.go:169 pkg/expenses.go:342 pkg/invoices.go:169
msgctxt "input"
msgid "To Date"
msgstr "Fins la data"
#: pkg/quote.go:197
#: pkg/quote.go:183
msgid "Quotations must have all the specified labels."
msgstr "Els pressuposts han de tenir totes les etiquetes."
#: pkg/quote.go:202
#: pkg/quote.go:188
msgid "Quotations must have at least one of the specified labels."
msgstr "Els pressuposts han de tenir com a mínim una de les etiquetes."
#: pkg/quote.go:528
#: pkg/quote.go:550
msgid "quotations.zip"
msgstr "pressuposts.zip"
#: pkg/quote.go:534 pkg/quote.go:1063 pkg/quote.go:1071 pkg/invoices.go:535
#: pkg/invoices.go:1125 pkg/invoices.go:1133
#: pkg/quote.go:556 pkg/quote.go:1085 pkg/quote.go:1093 pkg/invoices.go:555
#: pkg/invoices.go:1145 pkg/invoices.go:1153
msgid "Invalid action"
msgstr "Acció invàlida."
#: pkg/quote.go:587
#: pkg/quote.go:609
msgid "Select a customer to quote."
msgstr "Escolliu un client a pressupostar."
#: pkg/quote.go:592
#: pkg/quote.go:614
msgctxt "input"
msgid "Quotation Date"
msgstr "Data del pressupost"
#: pkg/quote.go:598
#: pkg/quote.go:620
msgctxt "input"
msgid "Terms and conditions"
msgstr "Condicions dacceptació"
#: pkg/quote.go:603 pkg/invoices.go:598
#: pkg/quote.go:625 pkg/invoices.go:618
msgctxt "input"
msgid "Notes"
msgstr "Notes"
#: pkg/quote.go:612 pkg/invoices.go:608
#: pkg/quote.go:634 pkg/invoices.go:628
msgctxt "input"
msgid "Payment Method"
msgstr "Mètode de pagament"
#: pkg/quote.go:613
#: pkg/quote.go:635
msgid "Select a payment method."
msgstr "Escolliu un mètode de pagament."
#: pkg/quote.go:649
#: pkg/quote.go:671
msgid "Selected quotation status is not valid."
msgstr "Heu seleccionat un estat de pressupost que no és vàlid."
#: pkg/quote.go:651 pkg/invoices.go:645
#: pkg/quote.go:673 pkg/invoices.go:665
msgid "Selected customer is not valid."
msgstr "Heu seleccionat un client que no és vàlid."
#: pkg/quote.go:653
#: pkg/quote.go:675
msgid "Quotation date can not be empty."
msgstr "No podeu deixar la data del pressupost en blanc."
#: pkg/quote.go:654
#: pkg/quote.go:676
msgid "Quotation date must be a valid date."
msgstr "La data del pressupost ha de ser vàlida."
#: pkg/quote.go:657 pkg/invoices.go:649
#: pkg/quote.go:679 pkg/invoices.go:669
msgid "Selected payment method is not valid."
msgstr "Heu seleccionat un mètode de pagament que no és vàlid."
#: pkg/quote.go:791 pkg/quote.go:796 pkg/invoices.go:841 pkg/invoices.go:846
#: pkg/quote.go:813 pkg/quote.go:818 pkg/invoices.go:861 pkg/invoices.go:866
msgctxt "input"
msgid "Id"
msgstr "Identificador"
#: pkg/quote.go:829 pkg/invoices.go:879
#: pkg/quote.go:851 pkg/invoices.go:899
msgctxt "input"
msgid "Quantity"
msgstr "Quantitat"
#: pkg/quote.go:838 pkg/invoices.go:888
#: pkg/quote.go:860 pkg/invoices.go:908
msgctxt "input"
msgid "Discount (%)"
msgstr "Descompte (%)"
#: pkg/quote.go:892
#: pkg/quote.go:914
msgid "Quotation product ID must be a number greater than zero."
msgstr "LID del producte de pressupost ha de ser un número major a zero."
#: pkg/quote.go:895 pkg/invoices.go:945
#: pkg/quote.go:917 pkg/invoices.go:965
msgid "Product ID must be a positive number or zero."
msgstr "LID del producte ha de ser un número positiu o zero."
#: pkg/quote.go:901 pkg/invoices.go:951
#: pkg/quote.go:923 pkg/invoices.go:971
msgid "Quantity can not be empty."
msgstr "No podeu deixar la quantitat en blanc."
#: pkg/quote.go:902 pkg/invoices.go:952
#: pkg/quote.go:924 pkg/invoices.go:972
msgid "Quantity must be a number greater than zero."
msgstr "La quantitat ha de ser un número major a zero."
#: pkg/quote.go:904 pkg/invoices.go:954
#: pkg/quote.go:926 pkg/invoices.go:974
msgid "Discount can not be empty."
msgstr "No podeu deixar el descompte en blanc."
#: pkg/quote.go:905 pkg/invoices.go:955
#: pkg/quote.go:927 pkg/invoices.go:975
msgid "Discount must be a percentage between 0 and 100."
msgstr "El descompte ha de ser un percentatge entre 0 i 100."
@ -1053,88 +1056,92 @@ msgctxt "period option"
msgid "Previous year"
msgstr "Any anterior"
#: pkg/expenses.go:129
#: pkg/expenses.go:115
msgid "Select a contact."
msgstr "Escolliu un contacte."
#: pkg/expenses.go:164
#: pkg/expenses.go:150 pkg/expenses.go:326
msgctxt "input"
msgid "Contact"
msgstr "Contacte"
#: pkg/expenses.go:170
#: pkg/expenses.go:156
msgctxt "input"
msgid "Invoice number"
msgstr "Número de factura"
#: pkg/expenses.go:175 pkg/invoices.go:592
#: pkg/expenses.go:161 pkg/invoices.go:612
msgctxt "input"
msgid "Invoice Date"
msgstr "Data de factura"
#: pkg/expenses.go:187
#: pkg/expenses.go:173
msgctxt "input"
msgid "Amount"
msgstr "Import"
#: pkg/expenses.go:197
#: pkg/expenses.go:183
msgctxt "input"
msgid "File"
msgstr "Fitxer"
#: pkg/expenses.go:225
#: pkg/expenses.go:211
msgid "Selected contact is not valid."
msgstr "Heu seleccionat un contacte que no és vàlid."
#: pkg/expenses.go:226 pkg/invoices.go:647
#: pkg/expenses.go:212 pkg/invoices.go:667
msgid "Invoice date must be a valid date."
msgstr "La data de facturació ha de ser vàlida."
#: pkg/expenses.go:229
#: pkg/expenses.go:215
msgid "Amount can not be empty."
msgstr "No podeu deixar limport en blanc."
#: pkg/expenses.go:230
#: pkg/expenses.go:216
msgid "Amount must be a number greater than zero."
msgstr "Limport ha de ser un número major a zero."
#: pkg/expenses.go:346 pkg/invoices.go:174
#: pkg/expenses.go:327
msgid "All contacts"
msgstr "Tots els contactes"
#: pkg/expenses.go:332 pkg/invoices.go:159
msgctxt "input"
msgid "Invoice Number"
msgstr "Número de factura"
#: pkg/invoices.go:168 pkg/invoices.go:580
#: pkg/invoices.go:153 pkg/invoices.go:600
msgctxt "input"
msgid "Invoice Status"
msgstr "Estat de la factura"
#: pkg/invoices.go:428
#: pkg/invoices.go:448
msgid "Select a customer to bill."
msgstr "Escolliu un client a facturar."
#: pkg/invoices.go:529
#: pkg/invoices.go:549
msgid "invoices.zip"
msgstr "factures.zip"
#: pkg/invoices.go:644
#: pkg/invoices.go:664
msgid "Selected invoice status is not valid."
msgstr "Heu seleccionat un estat de factura que no és vàlid."
#: pkg/invoices.go:646
#: pkg/invoices.go:666
msgid "Invoice date can not be empty."
msgstr "No podeu deixar la data de la factura en blanc."
#: pkg/invoices.go:782
#: pkg/invoices.go:802
#, c-format
msgid "Re: quotation #%s of %s"
msgstr "Ref: pressupost núm. %s del %s"
#: pkg/invoices.go:783
#: pkg/invoices.go:803
msgctxt "to_char"
msgid "MM/DD/YYYY"
msgstr "DD/MM/YYYY"
#: pkg/invoices.go:942
#: pkg/invoices.go:962
msgid "Invoice product ID must be a number greater than zero."
msgstr "LID del producte de factura ha de ser un número major a zero."

163
po/es.po
View File

@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: numerus\n"
"Report-Msgid-Bugs-To: jordi@tandem.blog\n"
"POT-Creation-Date: 2023-06-16 10:55+0200\n"
"POT-Creation-Date: 2023-06-20 11:35+0200\n"
"PO-Revision-Date: 2023-01-18 17:45+0100\n"
"Last-Translator: jordi fita mas <jordi@tandem.blog>\n"
"Language-Team: Spanish <es@tp.org.es>\n"
@ -157,7 +157,6 @@ msgid "Invoice Num."
msgstr "N.º factura"
#: web/template/invoices/index.gohtml:52 web/template/quotes/index.gohtml:52
#: web/template/contacts/index.gohtml:40
msgctxt "title"
msgid "Customer"
msgstr "Cliente"
@ -216,6 +215,11 @@ msgstr "Duplicar"
msgid "No invoices added yet."
msgstr "No hay facturas."
#: web/template/invoices/index.gohtml:144 web/template/quotes/index.gohtml:152
#: web/template/expenses/index.gohtml:105
msgid "Total"
msgstr "Total"
#: web/template/invoices/view.gohtml:2 web/template/invoices/view.gohtml:33
msgctxt "title"
msgid "Invoice %s"
@ -449,6 +453,11 @@ msgctxt "action"
msgid "New contact"
msgstr "Nuevo contacto"
#: web/template/contacts/index.gohtml:40 web/template/expenses/index.gohtml:43
msgctxt "title"
msgid "Contact"
msgstr "Contacto"
#: web/template/contacts/index.gohtml:41
msgctxt "title"
msgid "Email"
@ -526,11 +535,6 @@ msgctxt "expense"
msgid "All"
msgstr "Todos"
#: web/template/expenses/index.gohtml:43
msgctxt "title"
msgid "Contact"
msgstr "Contacto"
#: web/template/expenses/index.gohtml:44
msgctxt "title"
msgid "Invoice Date"
@ -670,82 +674,82 @@ msgstr "No podéis dejar la contraseña en blanco."
msgid "Invalid user or password."
msgstr "Nombre de usuario o contraseña inválido."
#: pkg/products.go:164 pkg/products.go:263 pkg/quote.go:801 pkg/invoices.go:851
#: pkg/products.go:164 pkg/products.go:263 pkg/quote.go:823 pkg/invoices.go:871
#: pkg/contacts.go:135
msgctxt "input"
msgid "Name"
msgstr "Nombre"
#: pkg/products.go:169 pkg/products.go:290 pkg/quote.go:188 pkg/quote.go:608
#: pkg/expenses.go:202 pkg/expenses.go:361 pkg/invoices.go:189
#: pkg/invoices.go:603 pkg/invoices.go:1150 pkg/contacts.go:140
#: pkg/products.go:169 pkg/products.go:290 pkg/quote.go:174 pkg/quote.go:630
#: pkg/expenses.go:188 pkg/expenses.go:347 pkg/invoices.go:174
#: pkg/invoices.go:623 pkg/invoices.go:1170 pkg/contacts.go:140
#: pkg/contacts.go:325
msgctxt "input"
msgid "Tags"
msgstr "Etiquetes"
#: pkg/products.go:173 pkg/quote.go:192 pkg/expenses.go:365 pkg/invoices.go:193
#: pkg/products.go:173 pkg/quote.go:178 pkg/expenses.go:351 pkg/invoices.go:178
#: pkg/contacts.go:144
msgctxt "input"
msgid "Tags Condition"
msgstr "Condición de las etiquetas"
#: pkg/products.go:177 pkg/quote.go:196 pkg/expenses.go:369 pkg/invoices.go:197
#: pkg/products.go:177 pkg/quote.go:182 pkg/expenses.go:355 pkg/invoices.go:182
#: pkg/contacts.go:148
msgctxt "tag condition"
msgid "All"
msgstr "Todas"
#: pkg/products.go:178 pkg/expenses.go:370 pkg/invoices.go:198
#: pkg/products.go:178 pkg/expenses.go:356 pkg/invoices.go:183
#: pkg/contacts.go:149
msgid "Invoices must have all the specified labels."
msgstr "Las facturas deben tener todas las etiquetas."
#: pkg/products.go:182 pkg/quote.go:201 pkg/expenses.go:374 pkg/invoices.go:202
#: pkg/products.go:182 pkg/quote.go:187 pkg/expenses.go:360 pkg/invoices.go:187
#: pkg/contacts.go:153
msgctxt "tag condition"
msgid "Any"
msgstr "Cualquiera"
#: pkg/products.go:183 pkg/expenses.go:375 pkg/invoices.go:203
#: pkg/products.go:183 pkg/expenses.go:361 pkg/invoices.go:188
#: pkg/contacts.go:154
msgid "Invoices must have at least one of the specified labels."
msgstr "Las facturas deben tener como mínimo una de las etiquetas."
#: pkg/products.go:269 pkg/quote.go:815 pkg/invoices.go:865
#: pkg/products.go:269 pkg/quote.go:837 pkg/invoices.go:885
msgctxt "input"
msgid "Description"
msgstr "Descripción"
#: pkg/products.go:274 pkg/quote.go:819 pkg/invoices.go:869
#: pkg/products.go:274 pkg/quote.go:841 pkg/invoices.go:889
msgctxt "input"
msgid "Price"
msgstr "Precio"
#: pkg/products.go:284 pkg/quote.go:848 pkg/expenses.go:181 pkg/invoices.go:898
#: pkg/products.go:284 pkg/quote.go:870 pkg/expenses.go:167 pkg/invoices.go:918
msgctxt "input"
msgid "Taxes"
msgstr "Impuestos"
#: pkg/products.go:309 pkg/quote.go:897 pkg/profile.go:92 pkg/invoices.go:947
#: pkg/products.go:309 pkg/quote.go:919 pkg/profile.go:92 pkg/invoices.go:967
msgid "Name can not be empty."
msgstr "No podéis dejar el nombre en blanco."
#: pkg/products.go:310 pkg/quote.go:898 pkg/invoices.go:948
#: pkg/products.go:310 pkg/quote.go:920 pkg/invoices.go:968
msgid "Price can not be empty."
msgstr "No podéis dejar el precio en blanco."
#: pkg/products.go:311 pkg/quote.go:899 pkg/invoices.go:949
#: pkg/products.go:311 pkg/quote.go:921 pkg/invoices.go:969
msgid "Price must be a number greater than zero."
msgstr "El precio tiene que ser un número mayor a cero."
#: pkg/products.go:313 pkg/quote.go:907 pkg/expenses.go:227 pkg/expenses.go:232
#: pkg/invoices.go:957
#: pkg/products.go:313 pkg/quote.go:929 pkg/expenses.go:213 pkg/expenses.go:218
#: pkg/invoices.go:977
msgid "Selected tax is not valid."
msgstr "Habéis escogido un impuesto que no es válido."
#: pkg/products.go:314 pkg/quote.go:908 pkg/expenses.go:228 pkg/expenses.go:233
#: pkg/invoices.go:958
#: pkg/products.go:314 pkg/quote.go:930 pkg/expenses.go:214 pkg/expenses.go:219
#: pkg/invoices.go:978
msgid "You can only select a tax of each class."
msgstr "Solo podéis escoger un impuesto de cada clase."
@ -852,141 +856,140 @@ msgstr "No podéis dejar el nombre del método de pago en blanco."
msgid "Payment instructions can not be empty."
msgstr "No podéis dejar las instrucciones de pago en blanco."
#: pkg/quote.go:161 pkg/quote.go:586 pkg/expenses.go:340 pkg/invoices.go:162
#: pkg/invoices.go:586
#: pkg/quote.go:147 pkg/quote.go:608 pkg/invoices.go:147 pkg/invoices.go:606
msgctxt "input"
msgid "Customer"
msgstr "Cliente"
#: pkg/quote.go:162 pkg/expenses.go:341 pkg/invoices.go:163
#: pkg/quote.go:148 pkg/invoices.go:148
msgid "All customers"
msgstr "Todos los clientes"
#: pkg/quote.go:167 pkg/quote.go:580
#: pkg/quote.go:153 pkg/quote.go:602
msgctxt "input"
msgid "Quotation Status"
msgstr "Estado del presupuesto"
#: pkg/quote.go:168 pkg/invoices.go:169
#: pkg/quote.go:154 pkg/invoices.go:154
msgid "All status"
msgstr "Todos los estados"
#: pkg/quote.go:173
#: pkg/quote.go:159
msgctxt "input"
msgid "Quotation Number"
msgstr "Número de presupuesto"
#: pkg/quote.go:178 pkg/expenses.go:351 pkg/invoices.go:179
#: pkg/quote.go:164 pkg/expenses.go:337 pkg/invoices.go:164
msgctxt "input"
msgid "From Date"
msgstr "A partir de la fecha"
#: pkg/quote.go:183 pkg/expenses.go:356 pkg/invoices.go:184
#: pkg/quote.go:169 pkg/expenses.go:342 pkg/invoices.go:169
msgctxt "input"
msgid "To Date"
msgstr "Hasta la fecha"
#: pkg/quote.go:197
#: pkg/quote.go:183
msgid "Quotations must have all the specified labels."
msgstr "Los presupuestos deben tener todas las etiquetas."
#: pkg/quote.go:202
#: pkg/quote.go:188
msgid "Quotations must have at least one of the specified labels."
msgstr "Los presupuestos deben tener como mínimo una de las etiquetas."
#: pkg/quote.go:528
#: pkg/quote.go:550
msgid "quotations.zip"
msgstr "presupuestos.zip"
#: pkg/quote.go:534 pkg/quote.go:1063 pkg/quote.go:1071 pkg/invoices.go:535
#: pkg/invoices.go:1125 pkg/invoices.go:1133
#: pkg/quote.go:556 pkg/quote.go:1085 pkg/quote.go:1093 pkg/invoices.go:555
#: pkg/invoices.go:1145 pkg/invoices.go:1153
msgid "Invalid action"
msgstr "Acción inválida."
#: pkg/quote.go:587
#: pkg/quote.go:609
msgid "Select a customer to quote."
msgstr "Escoged un cliente a presupuestar."
#: pkg/quote.go:592
#: pkg/quote.go:614
msgctxt "input"
msgid "Quotation Date"
msgstr "Fecha del presupuesto"
#: pkg/quote.go:598
#: pkg/quote.go:620
msgctxt "input"
msgid "Terms and conditions"
msgstr "Condiciones de aceptación"
#: pkg/quote.go:603 pkg/invoices.go:598
#: pkg/quote.go:625 pkg/invoices.go:618
msgctxt "input"
msgid "Notes"
msgstr "Notas"
#: pkg/quote.go:612 pkg/invoices.go:608
#: pkg/quote.go:634 pkg/invoices.go:628
msgctxt "input"
msgid "Payment Method"
msgstr "Método de pago"
#: pkg/quote.go:613
#: pkg/quote.go:635
msgid "Select a payment method."
msgstr "Escoged un método e pago."
#: pkg/quote.go:649
#: pkg/quote.go:671
msgid "Selected quotation status is not valid."
msgstr "Habéis escogido un estado de presupuesto que no es válido."
#: pkg/quote.go:651 pkg/invoices.go:645
#: pkg/quote.go:673 pkg/invoices.go:665
msgid "Selected customer is not valid."
msgstr "Habéis escogido un cliente que no es válido."
#: pkg/quote.go:653
#: pkg/quote.go:675
msgid "Quotation date can not be empty."
msgstr "No podéis dejar la fecha del presupuesto en blanco."
#: pkg/quote.go:654
#: pkg/quote.go:676
msgid "Quotation date must be a valid date."
msgstr "La fecha de presupuesto debe ser válida."
#: pkg/quote.go:657 pkg/invoices.go:649
#: pkg/quote.go:679 pkg/invoices.go:669
msgid "Selected payment method is not valid."
msgstr "Habéis escogido un método de pago que no es válido."
#: pkg/quote.go:791 pkg/quote.go:796 pkg/invoices.go:841 pkg/invoices.go:846
#: pkg/quote.go:813 pkg/quote.go:818 pkg/invoices.go:861 pkg/invoices.go:866
msgctxt "input"
msgid "Id"
msgstr "Identificador"
#: pkg/quote.go:829 pkg/invoices.go:879
#: pkg/quote.go:851 pkg/invoices.go:899
msgctxt "input"
msgid "Quantity"
msgstr "Cantidad"
#: pkg/quote.go:838 pkg/invoices.go:888
#: pkg/quote.go:860 pkg/invoices.go:908
msgctxt "input"
msgid "Discount (%)"
msgstr "Descuento (%)"
#: pkg/quote.go:892
#: pkg/quote.go:914
msgid "Quotation product ID must be a number greater than zero."
msgstr "El ID de producto de presupuesto tiene que ser un número mayor a cero."
#: pkg/quote.go:895 pkg/invoices.go:945
#: pkg/quote.go:917 pkg/invoices.go:965
msgid "Product ID must be a positive number or zero."
msgstr "El ID de producto tiene que ser un número positivo o cero."
#: pkg/quote.go:901 pkg/invoices.go:951
#: pkg/quote.go:923 pkg/invoices.go:971
msgid "Quantity can not be empty."
msgstr "No podéis dejar la cantidad en blanco."
#: pkg/quote.go:902 pkg/invoices.go:952
#: pkg/quote.go:924 pkg/invoices.go:972
msgid "Quantity must be a number greater than zero."
msgstr "La cantidad tiene que ser un número mayor a cero."
#: pkg/quote.go:904 pkg/invoices.go:954
#: pkg/quote.go:926 pkg/invoices.go:974
msgid "Discount can not be empty."
msgstr "No podéis dejar el descuento en blanco."
#: pkg/quote.go:905 pkg/invoices.go:955
#: pkg/quote.go:927 pkg/invoices.go:975
msgid "Discount must be a percentage between 0 and 100."
msgstr "El descuento tiene que ser un porcentaje entre 0 y 100."
@ -1053,88 +1056,92 @@ msgctxt "period option"
msgid "Previous year"
msgstr "Año anterior"
#: pkg/expenses.go:129
#: pkg/expenses.go:115
msgid "Select a contact."
msgstr "Escoged un contacto"
#: pkg/expenses.go:164
#: pkg/expenses.go:150 pkg/expenses.go:326
msgctxt "input"
msgid "Contact"
msgstr "Contacto"
#: pkg/expenses.go:170
#: pkg/expenses.go:156
msgctxt "input"
msgid "Invoice number"
msgstr "Número de factura"
#: pkg/expenses.go:175 pkg/invoices.go:592
#: pkg/expenses.go:161 pkg/invoices.go:612
msgctxt "input"
msgid "Invoice Date"
msgstr "Fecha de factura"
#: pkg/expenses.go:187
#: pkg/expenses.go:173
msgctxt "input"
msgid "Amount"
msgstr "Importe"
#: pkg/expenses.go:197
#: pkg/expenses.go:183
msgctxt "input"
msgid "File"
msgstr "Archivo"
#: pkg/expenses.go:225
#: pkg/expenses.go:211
msgid "Selected contact is not valid."
msgstr "Habéis escogido un contacto que no es válido."
#: pkg/expenses.go:226 pkg/invoices.go:647
#: pkg/expenses.go:212 pkg/invoices.go:667
msgid "Invoice date must be a valid date."
msgstr "La fecha de factura debe ser válida."
#: pkg/expenses.go:229
#: pkg/expenses.go:215
msgid "Amount can not be empty."
msgstr "No podéis dejar el importe en blanco."
#: pkg/expenses.go:230
#: pkg/expenses.go:216
msgid "Amount must be a number greater than zero."
msgstr "El importe tiene que ser un número mayor a cero."
#: pkg/expenses.go:346 pkg/invoices.go:174
#: pkg/expenses.go:327
msgid "All contacts"
msgstr "Todos los contactos"
#: pkg/expenses.go:332 pkg/invoices.go:159
msgctxt "input"
msgid "Invoice Number"
msgstr "Número de factura"
#: pkg/invoices.go:168 pkg/invoices.go:580
#: pkg/invoices.go:153 pkg/invoices.go:600
msgctxt "input"
msgid "Invoice Status"
msgstr "Estado de la factura"
#: pkg/invoices.go:428
#: pkg/invoices.go:448
msgid "Select a customer to bill."
msgstr "Escoged un cliente a facturar."
#: pkg/invoices.go:529
#: pkg/invoices.go:549
msgid "invoices.zip"
msgstr "facturas.zip"
#: pkg/invoices.go:644
#: pkg/invoices.go:664
msgid "Selected invoice status is not valid."
msgstr "Habéis escogido un estado de factura que no es válido."
#: pkg/invoices.go:646
#: pkg/invoices.go:666
msgid "Invoice date can not be empty."
msgstr "No podéis dejar la fecha de la factura en blanco."
#: pkg/invoices.go:782
#: pkg/invoices.go:802
#, c-format
msgid "Re: quotation #%s of %s"
msgstr "Ref: presupuesto n.º %s del %s"
#: pkg/invoices.go:783
#: pkg/invoices.go:803
msgctxt "to_char"
msgid "MM/DD/YYYY"
msgstr "DD/MM/YYYY"
#: pkg/invoices.go:942
#: pkg/invoices.go:962
msgid "Invoice product ID must be a number greater than zero."
msgstr "El ID de producto de factura tiene que ser un número mayor a cero."

View File

@ -263,6 +263,10 @@ tbody tr:nth-child(even) {
background-color: var(--numerus--header--background-color);
}
tfoot th {
text-align: right;
}
div[role="alert"].error {
padding: 1.25em;
background-color: var(--numerus--color--red);

View File

@ -37,7 +37,7 @@
<table>
<thead>
<tr>
<th>{{( pgettext "Customer" "title" )}}</th>
<th>{{( pgettext "Contact" "title" )}}</th>
<th>{{( pgettext "Email" "title" )}}</th>
<th>{{( pgettext "Phone" "title" )}}</th>
<th>{{( pgettext "Tags" "title" )}}</th>

View File

@ -25,7 +25,7 @@
aria-labelledby="filters-toggle"
>
{{ with .Filters }}
{{ template "select-field" .Customer }}
{{ template "select-field" .Contact }}
{{ template "input-field" .FromDate }}
{{ template "input-field" .ToDate }}
{{ template "input-field" .InvoiceNumber }}
@ -99,5 +99,14 @@
</tr>
{{ end }}
</tbody>
{{ if .Expenses }}
<tfoot>
<tr>
<th scope="row" colspan="5">{{( gettext "Total" )}}</th>
<td class="numeric">{{ .TotalAmount|formatPrice }}</td>
<td colspan="2"></td>
</tr>
</tfoot>
{{ end }}
</table>
{{- end }}

View File

@ -138,5 +138,14 @@
</tr>
{{ end }}
</tbody>
{{ if .Invoices }}
<tfoot>
<tr>
<th scope="row" colspan="6">{{( gettext "Total" )}}</th>
<td class="numeric">{{ .TotalAmount|formatPrice }}</td>
<td colspan="2"></td>
</tr>
</tfoot>
{{ end }}
</table>
{{- end }}

View File

@ -146,5 +146,14 @@
</tr>
{{ end }}
</tbody>
{{ if .Quotes }}
<tfoot>
<tr>
<th scope="row" colspan="6">{{( gettext "Total" )}}</th>
<td class="numeric">{{ .TotalAmount|formatPrice }}</td>
<td colspan="2"></td>
</tr>
</tfoot>
{{ end }}
</table>
{{- end }}