Skip to content
This repository was archived by the owner on Jun 12, 2024. It is now read-only.

Commit 9361997

Browse files
authored
feat(reporting): bill of materials (#275)
* new reporting service * API route * code gen * get tsv export from tools page * fix naming
1 parent 2e96d8c commit 9361997

File tree

16 files changed

+291
-91
lines changed

16 files changed

+291
-91
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
package v1
2+
3+
import (
4+
"net/http"
5+
6+
"github.com/hay-kot/homebox/backend/internal/core/services"
7+
"github.com/hay-kot/homebox/backend/pkgs/server"
8+
)
9+
10+
// HandleBillOfMaterialsExport godoc
11+
//
12+
// @Summary Generates a Bill of Materials CSV
13+
// @Tags Reporting
14+
// @Produce json
15+
// @Success 200 {string} string "text/csv"
16+
// @Router /v1/reporting/bill-of-materials [GET]
17+
// @Security Bearer
18+
func (ctrl *V1Controller) HandleBillOfMaterialsExport() server.HandlerFunc {
19+
return func(w http.ResponseWriter, r *http.Request) error {
20+
actor := services.UseUserCtx(r.Context())
21+
22+
csv, err := ctrl.svc.Reporting.BillOfMaterialsTSV(r.Context(), actor.GroupID)
23+
if err != nil {
24+
return err
25+
}
26+
27+
w.Header().Set("Content-Type", "text/csv")
28+
w.Header().Set("Content-Disposition", "attachment; filename=bom.csv")
29+
_, err = w.Write(csv)
30+
return err
31+
}
32+
}

backend/app/api/routes.go

+3
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,9 @@ func (a *app) mountRoutes(repos *repo.AllRepos) {
136136
a.mwAuthToken, a.mwRoles(RoleModeOr, authroles.RoleUser.String(), authroles.RoleAttachments.String()),
137137
)
138138

139+
// Reporting Services
140+
a.server.Get(v1Base("/reporting/bill-of-materials"), v1Ctrl.HandleBillOfMaterialsExport(), userMW...)
141+
139142
a.server.NotFound(notFoundHandler())
140143
}
141144

backend/app/api/static/docs/docs.go

+24
Original file line numberDiff line numberDiff line change
@@ -1303,6 +1303,30 @@ const docTemplate = `{
13031303
}
13041304
}
13051305
},
1306+
"/v1/reporting/bill-of-materials": {
1307+
"get": {
1308+
"security": [
1309+
{
1310+
"Bearer": []
1311+
}
1312+
],
1313+
"produces": [
1314+
"application/json"
1315+
],
1316+
"tags": [
1317+
"Reporting"
1318+
],
1319+
"summary": "Generates a Bill of Materials CSV",
1320+
"responses": {
1321+
"200": {
1322+
"description": "text/csv",
1323+
"schema": {
1324+
"type": "string"
1325+
}
1326+
}
1327+
}
1328+
}
1329+
},
13061330
"/v1/status": {
13071331
"get": {
13081332
"produces": [

backend/app/api/static/docs/swagger.json

+24
Original file line numberDiff line numberDiff line change
@@ -1295,6 +1295,30 @@
12951295
}
12961296
}
12971297
},
1298+
"/v1/reporting/bill-of-materials": {
1299+
"get": {
1300+
"security": [
1301+
{
1302+
"Bearer": []
1303+
}
1304+
],
1305+
"produces": [
1306+
"application/json"
1307+
],
1308+
"tags": [
1309+
"Reporting"
1310+
],
1311+
"summary": "Generates a Bill of Materials CSV",
1312+
"responses": {
1313+
"200": {
1314+
"description": "text/csv",
1315+
"schema": {
1316+
"type": "string"
1317+
}
1318+
}
1319+
}
1320+
}
1321+
},
12981322
"/v1/status": {
12991323
"get": {
13001324
"produces": [

backend/app/api/static/docs/swagger.yaml

+14
Original file line numberDiff line numberDiff line change
@@ -1408,6 +1408,20 @@ paths:
14081408
summary: Encode data into QRCode
14091409
tags:
14101410
- Items
1411+
/v1/reporting/bill-of-materials:
1412+
get:
1413+
produces:
1414+
- application/json
1415+
responses:
1416+
"200":
1417+
description: text/csv
1418+
schema:
1419+
type: string
1420+
security:
1421+
- Bearer: []
1422+
summary: Generates a Bill of Materials CSV
1423+
tags:
1424+
- Reporting
14111425
/v1/status:
14121426
get:
14131427
produces:

backend/go.mod

+1
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ require (
88
github.com/ardanlabs/conf/v3 v3.1.3
99
github.com/go-chi/chi/v5 v5.0.8
1010
github.com/go-playground/validator/v10 v10.11.2
11+
github.com/gocarina/gocsv v0.0.0-20230123225133-763e25b40669
1112
github.com/google/uuid v1.3.0
1213
github.com/mattn/go-sqlite3 v1.14.16
1314
github.com/rs/zerolog v1.29.0

backend/go.sum

+3-34
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,5 @@
1-
ariga.io/atlas v0.9.0 h1:q0JMtqyA3X1YWtPcn+E/kVPwLDslb+jAC8Ejl/vW6d0=
2-
ariga.io/atlas v0.9.0/go.mod h1:T230JFcENj4ZZzMkZrXFDSkv+2kXkUgpJ5FQQ5hMcKU=
31
ariga.io/atlas v0.9.1-0.20230119145809-92243f7c55cb h1:mbsFtavDqGdYwdDpP50LGOOZ2hgyGoJcZeOpbgKMyu4=
42
ariga.io/atlas v0.9.1-0.20230119145809-92243f7c55cb/go.mod h1:T230JFcENj4ZZzMkZrXFDSkv+2kXkUgpJ5FQQ5hMcKU=
5-
entgo.io/ent v0.11.5 h1:V2qhG91C4PMQTa82Q4StoESMQ4dzkMNeStCzszxi0jQ=
6-
entgo.io/ent v0.11.5/go.mod h1:u7eKwNWAo/VlHIKxgwbmsFy3J7cKDxwi3jyF5TW/okY=
73
entgo.io/ent v0.11.7 h1:V+wKFh0jhAbY/FoU+PPbdMOf2Ma5vh07R/IdF+N/nFg=
84
entgo.io/ent v0.11.7/go.mod h1:ericBi6Q8l3wBH1wEIDfKxw7rcQEuRPyBfbIzjtxJ18=
95
github.com/DATA-DOG/go-sqlmock v1.5.0 h1:Shsta01QNfFxHCfpW6YH2STWB0MudeXXEWMr20OEh60=
@@ -37,21 +33,16 @@ github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh
3733
github.com/go-openapi/swag v0.19.15/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ=
3834
github.com/go-openapi/swag v0.22.3 h1:yMBqmnQ0gyZvEb/+KzuWZOXgllrXT4SADYbvDaXHv/g=
3935
github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14=
40-
github.com/go-playground/assert/v2 v2.0.1 h1:MsBgLAaY856+nPRTKrp3/OZK38U/wa0CcBYNjji3q3A=
41-
github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
42-
github.com/go-playground/locales v0.14.0 h1:u50s323jtVGugKlcYeyzC0etD1HifMjqmJqb8WugfUU=
43-
github.com/go-playground/locales v0.14.0/go.mod h1:sawfccIbzZTqEDETgFXqTho0QybSa7l++s0DH+LDiLs=
36+
github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s=
4437
github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA=
4538
github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
46-
github.com/go-playground/universal-translator v0.18.0 h1:82dyy6p4OuJq4/CByFNOn/jYrnRPArHwAcmLoJZxyho=
47-
github.com/go-playground/universal-translator v0.18.0/go.mod h1:UvRDBj+xPUEGrFYl+lu/H90nyDXpg0fqeB/AQUGNTVA=
4839
github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=
4940
github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
50-
github.com/go-playground/validator/v10 v10.11.1 h1:prmOlTVv+YjZjmRmNSF3VmspqJIxJWXmqUsHwfTRRkQ=
51-
github.com/go-playground/validator/v10 v10.11.1/go.mod h1:i+3WkQ1FvaUjjxh1kSvIA4dMGDBiPU55YFDl0WbKdWU=
5241
github.com/go-playground/validator/v10 v10.11.2 h1:q3SHpufmypg+erIExEKUmsgmhDTyhcJ38oeKGACXohU=
5342
github.com/go-playground/validator/v10 v10.11.2/go.mod h1:NieE624vt4SCTJtD87arVLvdmjPAeV8BQlHtMnw9D7s=
5443
github.com/go-test/deep v1.0.3 h1:ZrJSEWsXzPOxaZnFteGEfooLba+ju3FYIbOrS+rQd68=
44+
github.com/gocarina/gocsv v0.0.0-20230123225133-763e25b40669 h1:MvZzCA/mduVWoBSVKJeMdv+AqXQmZZ8i6p8889ejt/Y=
45+
github.com/gocarina/gocsv v0.0.0-20230123225133-763e25b40669/go.mod h1:5YoVOkjYAQumqlV356Hj3xeYh4BdZuLE0/nRkf2NKkI=
5546
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
5647
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 h1:DACJavvAHhabrF08vX0COfcOBJRhZ8lUbR+ZWIs0Y5g=
5748
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k=
@@ -65,9 +56,7 @@ github.com/hashicorp/hcl/v2 v2.15.0/go.mod h1:JRmR89jycNkrrqnMmvPDMd56n1rQJ2Q6Ko
6556
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
6657
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
6758
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
68-
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
6959
github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0=
70-
github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk=
7160
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
7261
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
7362
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
@@ -94,14 +83,11 @@ github.com/mitchellh/go-wordwrap v1.0.1 h1:TLuKupo69TCn6TQSyGxwI1EblZZEsQ0vMlAFQ
9483
github.com/mitchellh/go-wordwrap v1.0.1/go.mod h1:R62XHJLzvMFRBbcrT7m7WgmE1eOyTSsCt+hzestvNj0=
9584
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
9685
github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec=
97-
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
9886
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
9987
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
10088
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
10189
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
102-
github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
10390
github.com/rogpeppe/go-internal v1.8.0 h1:FCbCCtXNOY3UtUuHUYaghJg4y7Fd14rXifAYUAtL9R8=
104-
github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE=
10591
github.com/rs/xid v1.4.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
10692
github.com/rs/zerolog v1.29.0 h1:Zes4hju04hjbvkVkOhdl2HpZa+0PmVwigmo8XoORE5w=
10793
github.com/rs/zerolog v1.29.0/go.mod h1:NILgTygv/Uej1ra5XxGf82ZFSLk58MFGAUS2o6usyD0=
@@ -113,7 +99,6 @@ github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSS
11399
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
114100
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
115101
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
116-
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
117102
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
118103
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
119104
github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
@@ -135,9 +120,6 @@ github.com/zclconf/go-cty v1.12.1 h1:PcupnljUm9EIvbgSHQnHhUr3fO6oFmkOrvs2BAFNXXY
135120
github.com/zclconf/go-cty v1.12.1/go.mod h1:s9IfD1LK5ccNMSWCVFCE2rJfHiZgi7JijgeWIMfhLvA=
136121
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
137122
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
138-
golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
139-
golang.org/x/crypto v0.5.0 h1:U/0M97KRkSFvyD/3FSmdP5W5swImpNgle/EHFhOsQPE=
140-
golang.org/x/crypto v0.5.0/go.mod h1:NK/OQwhpMQP3MwtdjgLlYHnH9ebylxKWv3e0fK+mkQU=
141123
golang.org/x/crypto v0.6.0 h1:qfktjS5LUO+fFKeJXZ+ikTRijMmljikvG68fpMMruSc=
142124
golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58=
143125
golang.org/x/image v0.0.0-20200927104501-e162460cd6b5 h1:QelT11PB4FXiDEXucrfNckHoFxwt8USGY1ajP1ZF5lM=
@@ -147,40 +129,30 @@ golang.org/x/mod v0.7.0 h1:LapD9S96VoQRhi/GrNTqeBJFrUjs5UHCAtTlgwA5oZA=
147129
golang.org/x/mod v0.7.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
148130
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
149131
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
150-
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
151132
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
152133
golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY=
153-
golang.org/x/net v0.5.0 h1:GyT4nK/YDHSqa1c4753ouYCDajOYKTja9Xb/OHtgvSw=
154-
golang.org/x/net v0.5.0/go.mod h1:DivGGAXEgPSlEBzxGzZI+ZLohi+xUj054jfeKui00ws=
155134
golang.org/x/net v0.6.0 h1:L4ZwwTvKW9gr0ZMS1yrHD9GZhIuVjOBBnaKH+SPQK0Q=
156135
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
157136
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
158137
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
159138
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
160139
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
161-
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
162140
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
163141
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
164-
golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
165142
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
166143
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
167144
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
168145
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
169146
golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
170-
golang.org/x/sys v0.4.0 h1:Zr2JFtRQNX3BCZ8YtxRE9hNJYC8J6I1MVbMg6owUp18=
171-
golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
172147
golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU=
173148
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
174149
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
175150
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
176151
golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc=
177152
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
178153
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
179-
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
180154
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
181155
golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
182-
golang.org/x/text v0.6.0 h1:3XmdazWV+ubf7QgHSTWeykHOci5oeekaGJBLkrkaw4k=
183-
golang.org/x/text v0.6.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
184156
golang.org/x/text v0.7.0 h1:4BRB4x83lYWy72KwLD/qYDuTu7q9PjSagHvijDw7cLo=
185157
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
186158
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
@@ -193,13 +165,10 @@ gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8
193165
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
194166
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
195167
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
196-
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
197-
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
198168
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
199169
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
200170
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
201171
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
202172
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
203-
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
204173
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
205174
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

backend/internal/core/services/all.go

+11-4
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,16 @@
11
package services
22

3-
import "github.com/hay-kot/homebox/backend/internal/data/repo"
3+
import (
4+
"github.com/hay-kot/homebox/backend/internal/core/services/reporting"
5+
"github.com/hay-kot/homebox/backend/internal/data/repo"
6+
"github.com/rs/zerolog/log"
7+
)
48

59
type AllServices struct {
6-
User *UserService
7-
Group *GroupService
8-
Items *ItemService
10+
User *UserService
11+
Group *GroupService
12+
Items *ItemService
13+
Reporting *reporting.ReportingService
914
}
1015

1116
type OptionsFunc func(*options)
@@ -40,5 +45,7 @@ func New(repos *repo.AllRepos, opts ...OptionsFunc) *AllServices {
4045
repo: repos,
4146
autoIncrementAssetID: options.autoIncrementAssetID,
4247
},
48+
// TODO: don't use global logger
49+
Reporting: reporting.NewReportingService(repos, &log.Logger),
4350
}
4451
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
package reporting
2+
3+
import (
4+
"context"
5+
"encoding/csv"
6+
"io"
7+
"time"
8+
9+
"github.com/gocarina/gocsv"
10+
"github.com/google/uuid"
11+
"github.com/hay-kot/homebox/backend/internal/data/repo"
12+
"github.com/rs/zerolog"
13+
)
14+
15+
type ReportingService struct {
16+
repos *repo.AllRepos
17+
l *zerolog.Logger
18+
}
19+
20+
func NewReportingService(repos *repo.AllRepos, l *zerolog.Logger) *ReportingService {
21+
gocsv.SetCSVWriter(func(out io.Writer) *gocsv.SafeCSVWriter {
22+
writer := csv.NewWriter(out)
23+
writer.Comma = '\t'
24+
return gocsv.NewSafeCSVWriter(writer)
25+
})
26+
27+
return &ReportingService{
28+
repos: repos,
29+
l: l,
30+
}
31+
}
32+
33+
// =================================================================================================
34+
35+
// NullableTime is a custom type that implements the MarshalCSV interface
36+
// to allow for nullable time.Time fields in the CSV output to be empty
37+
// and not "0001-01-01". It also overrides the default CSV output format
38+
type NullableTime time.Time
39+
40+
func (t NullableTime) MarshalCSV() (string, error) {
41+
if time.Time(t).IsZero() {
42+
return "", nil
43+
}
44+
// YYYY-MM-DD
45+
return time.Time(t).Format("2006-01-02"), nil
46+
}
47+
48+
type BillOfMaterialsEntry struct {
49+
PurchaseDate NullableTime `csv:"Purchase Date"`
50+
Name string `csv:"Name"`
51+
Description string `csv:"Description"`
52+
Manufacturer string `csv:"Manufacturer"`
53+
SerialNumber string `csv:"Serial Number"`
54+
ModelNumber string `csv:"Model Number"`
55+
Quantity int `csv:"Quantity"`
56+
Price float64 `csv:"Price"`
57+
TotalPrice float64 `csv:"Total Price"`
58+
}
59+
60+
// BillOfMaterialsTSV returns a byte slice of the Bill of Materials for a given GID in TSV format
61+
// See BillOfMaterialsEntry for the format of the output
62+
func (rs *ReportingService) BillOfMaterialsTSV(ctx context.Context, GID uuid.UUID) ([]byte, error) {
63+
entities, err := rs.repos.Items.GetAll(ctx, GID)
64+
if err != nil {
65+
rs.l.Debug().Err(err).Msg("failed to get all items for BOM Csv Reporting")
66+
return nil, err
67+
}
68+
69+
bomEntries := make([]BillOfMaterialsEntry, len(entities))
70+
for i, entity := range entities {
71+
bomEntries[i] = BillOfMaterialsEntry{
72+
PurchaseDate: NullableTime(entity.PurchaseTime),
73+
Name: entity.Name,
74+
Description: entity.Description,
75+
Manufacturer: entity.Manufacturer,
76+
SerialNumber: entity.SerialNumber,
77+
ModelNumber: entity.ModelNumber,
78+
Quantity: entity.Quantity,
79+
Price: entity.PurchasePrice,
80+
TotalPrice: entity.PurchasePrice * float64(entity.Quantity),
81+
}
82+
}
83+
84+
return gocsv.MarshalBytes(&bomEntries)
85+
}

backend/internal/core/services/service_items_csv_test.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,10 @@ import (
1212
"github.com/stretchr/testify/assert"
1313
)
1414

15-
//go:embed testdata/import.csv
15+
//go:embed .testdata/import.csv
1616
var CSVData_Comma []byte
1717

18-
//go:embed testdata/import.tsv
18+
//go:embed .testdata/import.tsv
1919
var CSVData_Tab []byte
2020

2121
func loadcsv() [][]string {

0 commit comments

Comments
 (0)