Compare commits

..

No commits in common. "ee0b5d0bdcc18401a1805e18ab3b89c0957c9dc2" and "055e92fb23dc7ef4948da26864b07d5117357a7d" have entirely different histories.

12 changed files with 298 additions and 399 deletions

17
go.mod
View File

@ -1,22 +1,15 @@
module dev.tandem.ws/tandem/numerus module dev.tandem.ws/tandem/numerus
go 1.19 go 1.16
require ( require (
github.com/jackc/pgtype v1.10.0 github.com/jackc/pgx/v4 v4.17.2
github.com/jackc/pgx/v4 v4.15.0
github.com/julienschmidt/httprouter v1.3.0 github.com/julienschmidt/httprouter v1.3.0
github.com/leonelquinteros/gotext v1.5.0 github.com/leonelquinteros/gotext v1.5.1
golang.org/x/text v0.7.0 golang.org/x/text v0.3.8
) )
require ( require (
github.com/jackc/chunkreader/v2 v2.0.1 // indirect github.com/jackc/pgtype v1.12.0
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 golang.org/x/crypto v0.0.0-20220829220503-c86fa9a7ed90 // indirect
) )

38
go.sum
View File

@ -14,6 +14,7 @@ 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 h1:1SD/1F5pU8p29ybwgQSwpQk+mwdRrXCYuPhW6m+TnJw=
github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= 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/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 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.0/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk=
github.com/jackc/chunkreader/v2 v2.0.1 h1:i+RDz65UE+mmpjTfyz0MoVTnzeYxroil2G82ki7MGG8= github.com/jackc/chunkreader/v2 v2.0.1 h1:i+RDz65UE+mmpjTfyz0MoVTnzeYxroil2G82ki7MGG8=
@ -24,7 +25,6 @@ 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.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.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.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 h1:3L1XMNV2Zvca/8BYhzcRFS70Lr0WlDg16Di6SFGAbys=
github.com/jackc/pgconn v1.13.0/go.mod h1:AnowpAqO4CMIIJNZl2VJp+KrkAZciAkhEl0W0JIobpI= github.com/jackc/pgconn v1.13.0/go.mod h1:AnowpAqO4CMIIJNZl2VJp+KrkAZciAkhEl0W0JIobpI=
github.com/jackc/pgio v1.0.0 h1:g12B9UwVnzGhueNavwioyEEpAmqMe1E/BN9ES+8ovkE= github.com/jackc/pgio v1.0.0 h1:g12B9UwVnzGhueNavwioyEEpAmqMe1E/BN9ES+8ovkE=
@ -35,6 +35,7 @@ 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/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 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM=
github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg= 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 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.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= github.com/jackc/pgproto3/v2 v2.0.0-alpha1.0.20190609003834-432c2951c711/go.mod h1:uH0AWtUmuShn0bcesswc4aBTWGvw0cAxIJp+6OB//Wg=
@ -42,7 +43,6 @@ 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.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.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.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 h1:nwj7qwf0S+Q7ISFfBndqeLwSwxs+4DPsbRFjECT1Y4Y=
github.com/jackc/pgproto3/v2 v2.3.1/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= 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= github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b h1:C8S2+VttkHFdOOCXJe+YGfa4vHYwlt4Zx+IVXQ97jYg=
@ -51,18 +51,17 @@ 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-20190824184912-ab885b375b90/go.mod h1:KcahbBH1nCMSo2DXpzsoWOAfFkdEtEJpPbVLq8eE+mc=
github.com/jackc/pgtype v0.0.0-20190828014616-a8802b16cc59/go.mod h1:MWlu30kVJrUS8lot6TQqcg7mtthZ9T0EoIBFiJcmcyw= 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.8.1-0.20210724151600-32e20a603178/go.mod h1:C516IlIV9NKqfsMCXTdChteoXmwgUceqaLfjg2e3NlM=
github.com/jackc/pgtype v1.10.0 h1:ILnBWrRMSXGczYvmkYD6PsYyVFUNLTnIUJHHDLmqk38= github.com/jackc/pgtype v1.12.0 h1:Dlq8Qvcch7kiehm8wPGIW0W3KsCCHJnRacKW0UM8n5w=
github.com/jackc/pgtype v1.10.0/go.mod h1:LUMuVrfsFfdKGLw+AFFVv6KtHOFMwRgDDzBt76IqCA4= github.com/jackc/pgtype v1.12.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-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-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.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.12.1-0.20210724153913-640aa07df17c/go.mod h1:1QD0+tgSXP7iUjYm9C1NxKhny7lq6ee99u/z+IHFcgs=
github.com/jackc/pgx/v4 v4.15.0 h1:B7dTkXsdILD3MF987WGGCcg+tvLW6bZJdEcqVFeU//w= github.com/jackc/pgx/v4 v4.17.2 h1:0Ut0rpeKwvIVbMQ1KbMBU4h6wxehBI535LK6Flheh8E=
github.com/jackc/pgx/v4 v4.15.0/go.mod h1:D/zyOyXiaM1TmVWnOM18p0xdDtdakRBa0RsVGI3U3bw= github.com/jackc/pgx/v4 v4.17.2/go.mod h1:lcxIZN44yMIrWI78a5CpucdD14hX0SBDbNRvjDBItsw=
github.com/jackc/puddle v0.0.0-20190413234325-e4ced69a3a2b/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= 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 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.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 h1:eHK/5clGOatcjX3oWGBO/MpxpbHzSwud5EWTSCI+MX0=
github.com/jackc/puddle v1.3.0/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= github.com/jackc/puddle v1.3.0/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
github.com/julienschmidt/httprouter v1.3.0 h1:U0609e9tgbseu3rBINet9P48AI/D3oJs4dN7jwJOQ1U= github.com/julienschmidt/httprouter v1.3.0 h1:U0609e9tgbseu3rBINet9P48AI/D3oJs4dN7jwJOQ1U=
@ -74,8 +73,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.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw= 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/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/leonelquinteros/gotext v1.5.0 h1:ODY7LzLpZWWSJdAHnzhreOr6cwLXTAmc914FOauSkBM= github.com/leonelquinteros/gotext v1.5.1 h1:vmddRn3gHp67YFjZLZE2AZsgYMT4IBTJhua4yfe7/4Q=
github.com/leonelquinteros/gotext v1.5.0/go.mod h1:OCiUVHuhP9LGFBQ1oAmdtNCHJCiHiQA8lf4nAifHkr0= github.com/leonelquinteros/gotext v1.5.1/go.mod h1:/A4Y7BvIsf5JHO60E43ZQDVkV3qO+7eP8HjeqD6ChIA=
github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= 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.1.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
@ -112,6 +111,8 @@ 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.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 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= 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= 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.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= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
@ -133,19 +134,26 @@ 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-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-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-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-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 h1:Y/gsMcFOcR+6S6f3YeMKl5g+dZMEWqcz5Czj/GWYbkM=
golang.org/x/crypto v0.0.0-20220829220503-c86fa9a7ed90/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= 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/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.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.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-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-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-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-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-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-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-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-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-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@ -159,16 +167,20 @@ 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-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-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-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-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-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.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.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.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.4/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.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.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.7.0 h1:4BRB4x83lYWy72KwLD/qYDuTu7q9PjSagHvijDw7cLo= golang.org/x/text v0.3.8 h1:nAL+RVCQ9uMn3vJZbV+MRnydTJFPf8qqY42YiA6MrqY=
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 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-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190425163242-31fd60d6bfdc/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190425163242-31fd60d6bfdc/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
@ -176,8 +188,10 @@ 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-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-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-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.0.0-20200103221440-774c71fcf114/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200221224223-e1da425f72fd/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/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 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-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=

View File

@ -23,9 +23,8 @@ type ExpenseEntry struct {
} }
type expensesIndexPage struct { type expensesIndexPage struct {
Expenses []*ExpenseEntry Expenses []*ExpenseEntry
TotalAmount string Filters *expenseFilterForm
Filters *expenseFilterForm
} }
func IndexExpenses(w http.ResponseWriter, r *http.Request, _ httprouter.Params) { func IndexExpenses(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
@ -38,15 +37,42 @@ func IndexExpenses(w http.ResponseWriter, r *http.Request, _ httprouter.Params)
return return
} }
page := &expensesIndexPage{ page := &expensesIndexPage{
Expenses: mustCollectExpenseEntries(r.Context(), conn, company, filters), Expenses: mustCollectExpenseEntries(r.Context(), conn, company, filters),
TotalAmount: mustComputeExpensesTotalAmount(r.Context(), conn, filters), Filters: filters,
Filters: filters,
} }
mustRenderMainTemplate(w, r, "expenses/index.gohtml", page) mustRenderMainTemplate(w, r, "expenses/index.gohtml", page)
} }
func mustCollectExpenseEntries(ctx context.Context, conn *Conn, company *Company, filters *expenseFilterForm) []*ExpenseEntry { func mustCollectExpenseEntries(ctx context.Context, conn *Conn, company *Company, filters *expenseFilterForm) []*ExpenseEntry {
where, args := filters.BuildQuery(nil) 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)
}
}
rows := conn.MustQuery(ctx, fmt.Sprintf(` rows := conn.MustQuery(ctx, fmt.Sprintf(`
select expense.slug select expense.slug
, invoice_date , invoice_date
@ -61,7 +87,7 @@ func mustCollectExpenseEntries(ctx context.Context, conn *Conn, company *Company
join currency using (currency_code) join currency using (currency_code)
where (%s) where (%s)
order by invoice_date order by invoice_date
`, where), args...) `, strings.Join(where, ") AND (")), args...)
defer rows.Close() defer rows.Close()
var entries []*ExpenseEntry var entries []*ExpenseEntry
@ -78,18 +104,6 @@ func mustCollectExpenseEntries(ctx context.Context, conn *Conn, company *Company
return entries 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) { func ServeExpenseForm(w http.ResponseWriter, r *http.Request, params httprouter.Params) {
locale := getLocale(r) locale := getLocale(r)
conn := getConn(r) conn := getConn(r)
@ -309,7 +323,7 @@ func HandleUpdateExpense(w http.ResponseWriter, r *http.Request, params httprout
type expenseFilterForm struct { type expenseFilterForm struct {
locale *Locale locale *Locale
company *Company company *Company
Contact *SelectField Customer *SelectField
InvoiceNumber *InputField InvoiceNumber *InputField
FromDate *InputField FromDate *InputField
ToDate *InputField ToDate *InputField
@ -321,10 +335,10 @@ func newExpenseFilterForm(ctx context.Context, conn *Conn, locale *Locale, compa
return &expenseFilterForm{ return &expenseFilterForm{
locale: locale, locale: locale,
company: company, company: company,
Contact: &SelectField{ Customer: &SelectField{
Name: "contact", Name: "customer",
Label: pgettext("input", "Contact", locale), Label: pgettext("input", "Customer", locale),
EmptyLabel: gettext("All contacts", locale), EmptyLabel: gettext("All customers", locale),
Options: mustGetContactOptions(ctx, conn, company), Options: mustGetContactOptions(ctx, conn, company),
}, },
InvoiceNumber: &InputField{ InvoiceNumber: &InputField{
@ -368,7 +382,7 @@ func (form *expenseFilterForm) Parse(r *http.Request) error {
if err := r.ParseForm(); err != nil { if err := r.ParseForm(); err != nil {
return err return err
} }
form.Contact.FillValue(r) form.Customer.FillValue(r)
form.InvoiceNumber.FillValue(r) form.InvoiceNumber.FillValue(r)
form.FromDate.FillValue(r) form.FromDate.FillValue(r)
form.ToDate.FillValue(r) form.ToDate.FillValue(r)
@ -377,41 +391,6 @@ func (form *expenseFilterForm) Parse(r *http.Request) error {
return nil 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) { func ServeEditExpenseTags(w http.ResponseWriter, r *http.Request, params httprouter.Params) {
conn := getConn(r) conn := getConn(r)
locale := getLocale(r) locale := getLocale(r)

View File

@ -35,7 +35,6 @@ type InvoiceEntry struct {
type InvoicesIndexPage struct { type InvoicesIndexPage struct {
Invoices []*InvoiceEntry Invoices []*InvoiceEntry
TotalAmount string
Filters *invoiceFilterForm Filters *invoiceFilterForm
InvoiceStatuses map[string]string InvoiceStatuses map[string]string
} }
@ -50,16 +49,44 @@ func IndexInvoices(w http.ResponseWriter, r *http.Request, _ httprouter.Params)
return return
} }
page := &InvoicesIndexPage{ page := &InvoicesIndexPage{
Invoices: mustCollectInvoiceEntries(r.Context(), conn, locale, filters), Invoices: mustCollectInvoiceEntries(r.Context(), conn, company, locale, filters),
TotalAmount: mustComputeInvoicesTotalAmount(r.Context(), conn, filters),
Filters: filters, Filters: filters,
InvoiceStatuses: mustCollectInvoiceStatuses(r.Context(), conn, locale), InvoiceStatuses: mustCollectInvoiceStatuses(r.Context(), conn, locale),
} }
mustRenderMainTemplate(w, r, "invoices/index.gohtml", page) mustRenderMainTemplate(w, r, "invoices/index.gohtml", page)
} }
func mustCollectInvoiceEntries(ctx context.Context, conn *Conn, locale *Locale, filters *invoiceFilterForm) []*InvoiceEntry { func mustCollectInvoiceEntries(ctx context.Context, conn *Conn, company *Company, locale *Locale, filters *invoiceFilterForm) []*InvoiceEntry {
where, args := filters.BuildQuery([]interface{}{locale.Language.String()}) 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)
}
}
rows := conn.MustQuery(ctx, fmt.Sprintf(` rows := conn.MustQuery(ctx, fmt.Sprintf(`
select invoice.slug select invoice.slug
, invoice_date , invoice_date
@ -77,7 +104,7 @@ func mustCollectInvoiceEntries(ctx context.Context, conn *Conn, locale *Locale,
where (%s) where (%s)
order by invoice_date desc order by invoice_date desc
, invoice_number desc , invoice_number desc
`, where), args...) `, strings.Join(where, ") AND (")), args...)
defer rows.Close() defer rows.Close()
var entries []*InvoiceEntry var entries []*InvoiceEntry
@ -95,18 +122,6 @@ func mustCollectInvoiceEntries(ctx context.Context, conn *Conn, locale *Locale,
return entries 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 { 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()) 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() defer rows.Close()
@ -205,41 +220,6 @@ func (form *invoiceFilterForm) Parse(r *http.Request) error {
return nil 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) { func ServeInvoice(w http.ResponseWriter, r *http.Request, params httprouter.Params) {
conn := getConn(r) conn := getConn(r)
company := mustGetCompany(r) company := mustGetCompany(r)

View File

@ -33,7 +33,6 @@ type QuoteEntry struct {
type QuotesIndexPage struct { type QuotesIndexPage struct {
Quotes []*QuoteEntry Quotes []*QuoteEntry
TotalAmount string
Filters *quoteFilterForm Filters *quoteFilterForm
QuoteStatuses map[string]string QuoteStatuses map[string]string
} }
@ -48,16 +47,44 @@ func IndexQuotes(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
return return
} }
page := &QuotesIndexPage{ page := &QuotesIndexPage{
Quotes: mustCollectQuoteEntries(r.Context(), conn, locale, filters), Quotes: mustCollectQuoteEntries(r.Context(), conn, company, locale, filters),
TotalAmount: mustComputeQuotesTotalAmount(r.Context(), conn, filters),
Filters: filters, Filters: filters,
QuoteStatuses: mustCollectQuoteStatuses(r.Context(), conn, locale), QuoteStatuses: mustCollectQuoteStatuses(r.Context(), conn, locale),
} }
mustRenderMainTemplate(w, r, "quotes/index.gohtml", page) mustRenderMainTemplate(w, r, "quotes/index.gohtml", page)
} }
func mustCollectQuoteEntries(ctx context.Context, conn *Conn, locale *Locale, filters *quoteFilterForm) []*QuoteEntry { func mustCollectQuoteEntries(ctx context.Context, conn *Conn, company *Company, locale *Locale, filters *quoteFilterForm) []*QuoteEntry {
where, args := filters.BuildQuery([]interface{}{locale.Language.String()}) 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)
}
}
rows := conn.MustQuery(ctx, fmt.Sprintf(` rows := conn.MustQuery(ctx, fmt.Sprintf(`
select quote.slug select quote.slug
, quote_date , quote_date
@ -76,7 +103,7 @@ func mustCollectQuoteEntries(ctx context.Context, conn *Conn, locale *Locale, fi
where (%s) where (%s)
order by quote_date desc order by quote_date desc
, quote_number desc , quote_number desc
`, where), args...) `, strings.Join(where, ") AND (")), args...)
defer rows.Close() defer rows.Close()
var entries []*QuoteEntry var entries []*QuoteEntry
@ -94,19 +121,6 @@ func mustCollectQuoteEntries(ctx context.Context, conn *Conn, locale *Locale, fi
return entries 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 { 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()) 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() defer rows.Close()
@ -205,42 +219,6 @@ func (form *quoteFilterForm) Parse(r *http.Request) error {
return nil 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) { func ServeQuote(w http.ResponseWriter, r *http.Request, params httprouter.Params) {
conn := getConn(r) conn := getConn(r)
company := mustGetCompany(r) company := mustGetCompany(r)

163
po/ca.po
View File

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

View File

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

View File

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

View File

@ -25,7 +25,7 @@
aria-labelledby="filters-toggle" aria-labelledby="filters-toggle"
> >
{{ with .Filters }} {{ with .Filters }}
{{ template "select-field" .Contact }} {{ template "select-field" .Customer }}
{{ template "input-field" .FromDate }} {{ template "input-field" .FromDate }}
{{ template "input-field" .ToDate }} {{ template "input-field" .ToDate }}
{{ template "input-field" .InvoiceNumber }} {{ template "input-field" .InvoiceNumber }}
@ -99,14 +99,5 @@
</tr> </tr>
{{ end }} {{ end }}
</tbody> </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> </table>
{{- end }} {{- end }}

View File

@ -138,14 +138,5 @@
</tr> </tr>
{{ end }} {{ end }}
</tbody> </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> </table>
{{- end }} {{- end }}

View File

@ -103,9 +103,9 @@
</td> </td>
<td class="numeric">{{ .Total|formatPrice }}</td> <td class="numeric">{{ .Total|formatPrice }}</td>
<td class="quote-download"><a href="{{ companyURI "/quotes/"}}{{ .Slug }}.pdf" <td class="quote-download"><a href="{{ companyURI "/quotes/"}}{{ .Slug }}.pdf"
download="{{ .Number}}.pdf" download="{{ .Number}}.pdf"
title="{{( pgettext "Download quotation" "action" )}}" title="{{( pgettext "Download quotation" "action" )}}"
aria-label="{{( pgettext "Download quotation" "action" )}}"><i aria-label="{{( pgettext "Download quotation" "action" )}}"><i
class="ri-download-line"></i></a></td> class="ri-download-line"></i></a></td>
<td class="actions"> <td class="actions">
<details class="menu"> <details class="menu">
@ -146,14 +146,5 @@
</tr> </tr>
{{ end }} {{ end }}
</tbody> </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> </table>
{{- end }} {{- end }}