company facts simple read out of xls works

This commit is contained in:
Andreas Schröpfer
2021-02-28 08:33:00 +01:00
parent e0faa1fc7c
commit 90af0db862
11 changed files with 197 additions and 170 deletions

View File

@@ -1,56 +1,23 @@
package main package main
import ( import (
"bytes"
_ "embed" _ "embed"
"fmt" "fmt"
"log" "log"
"strconv" "os"
"git.ecogood.org/andreas.schroepfer/excelConverter/pkg/ecalc"
"git.ecogood.org/andreas.schroepfer/excelConverter/pkg/loader" "git.ecogood.org/andreas.schroepfer/excelConverter/pkg/loader"
"git.ecogood.org/andreas.schroepfer/excelConverter/pkg/set"
excelize "github.com/360EntSecGroup-Skylar/excelize/v2"
) )
//go:embed default.json //go:embed default.json
var defaultConf []byte var defaultConf []byte
func main() { func main() {
buf := bytes.NewBuffer(defaultConf) xf, err := os.Open("../../test/gwb-rechner_5_0_4_vollbilanz.xlsx")
conf := &loader.Conf{}
err := conf.DecodeJSON(buf)
//fmt.Println(err, conf)
eBalance := ecalc.Ecalc{
CompanyFacts: ecalc.CompanyFacts{},
}
xFile, err := excelize.OpenFile("../../test/gwb-rechner_5_0_4_vollbilanz.xlsx")
fmt.Println("openFile err :", err)
//sheets := make(map[int])
for _, v := range conf.Values {
cellValue, err := xFile.GetCellValue(
xFile.GetSheetName(v.Sheet),
v.Cell,
)
if err != nil { if err != nil {
log.Println("error", err) log.Fatal("cannot open file:", err)
} }
var inValue interface{} defer xf.Close()
switch v.Struct { eBalance, err := loader.XLSX(xf, nil)
case "CompanyFacts": fmt.Printf("%s\n%#v", err, eBalance.CompanyFacts.IndustrySectors)
switch v.Type {
case "int":
inValue, err = strconv.Atoi(cellValue)
if err != nil {
fmt.Println(xFile.GetSheetName(v.Sheet))
fmt.Println("err ATOI", err)
}
default:
inValue = cellValue
}
set.Field(&eBalance.CompanyFacts, v.Field, inValue)
}
}
fmt.Printf("%#v", eBalance)
} }

View File

@@ -1,14 +0,0 @@
package main
import (
"fmt"
xlsx "github.com/tealeg/xlsx/v3"
)
func main() {
xls, err := xlsx.OpenFile("../../test/gwb-rechner_5_0_4_vollbilanz.xlsx")
fmt.Println("OpenFile err:", err)
sl, err := xls.ToSlice()
fmt.Printf("err: %v\n\n%#v", err, sl[1])
}

View File

@@ -1,43 +0,0 @@
{
"title": "",
"version": "",
"values": [
{
"sheet": 0,
"cell": "",
"type": "",
"struct": "",
"field": "",
"default": ""
}
],
"areas": [
{
"sheet": 0,
"start_row": 0,
"end_row": 0,
"struct": "",
"cols": [
{
"col": "",
"field": "",
"type": "",
"default": ""
}
]
}
],
"rating": {
"sheet": 0,
"start_row": 0,
"end_row": 0,
"points_col": "",
"max_points_col": "",
"id_col": "",
"short_name_col": "",
"name_col": "",
"estimations_col": "",
"weight_col": "",
"selected_by_user_col": ""
}
}

View File

@@ -1,28 +0,0 @@
package main
import (
"fmt"
"os"
"git.ecogood.org/andreas.schroepfer/excelConverter/pkg/loader"
excelize "github.com/360EntSecGroup-Skylar/excelize/v2"
)
func main() {
xFile, err := excelize.OpenFile("../../test/gwb-rechner_5_0_4_vollbilanz.xlsx")
fmt.Println("openFile err :", err)
sheets := xFile.GetSheetMap()
rows, _ := xFile.GetRows(sheets[4])
fmt.Printf("%#v", rows)
c := loader.Conf{}
c.Values = append(c.Values, loader.Value{})
c.Areas = append(c.Areas, loader.Area{
Cols: []loader.AreaCol{
loader.AreaCol{},
},
})
fd, err := os.OpenFile("conf.json", os.O_CREATE, 0777)
fmt.Println(err)
defer fd.Close()
c.EncodeJSON(fd)
}

View File

@@ -24,7 +24,7 @@ type CompanyFacts struct {
NumberOfEmployees int `json:"numberOfEmployees,omitempty"` NumberOfEmployees int `json:"numberOfEmployees,omitempty"`
HasCanteen bool `json:"hasCanteen,omitempty"` HasCanteen bool `json:"hasCanteen,omitempty"`
IsB2B bool `json:"isB2B,omitempty"` IsB2B bool `json:"isB2B,omitempty"`
AverageJourneyToWorkForStaffInKm float32 `json:"averageJourneyToWorkForStaffInKm,omitempty"` AverageJourneyToWorkForStaffInKm float64 `json:"averageJourneyToWorkForStaffInKm,omitempty"`
Rating Rating `json:"rating,omitempty"` Rating Rating `json:"rating,omitempty"`
} }
@@ -38,7 +38,7 @@ type SupplyFraction struct {
type EmployeesFraction struct { type EmployeesFraction struct {
ID int `json:"id,omitempty"` ID int `json:"id,omitempty"`
CountryCode string `json:"countryCode,omitempty"` CountryCode string `json:"countryCode,omitempty"`
Percentage float32 `json:"percentage,omitempty"` Percentage float64 `json:"percentage,omitempty"`
} }
type IndustrySector struct { type IndustrySector struct {
@@ -54,24 +54,24 @@ type Rating struct {
type Topic struct { type Topic struct {
Points int `json:"points,omitempty"` Points int `json:"points,omitempty"`
MaxPoints float32 `json:"maxPoints,omitempty"` MaxPoints float64 `json:"maxPoints,omitempty"`
ID int `json:"id,omitempty"` ID int `json:"id,omitempty"`
ShortName string `json:"shortName,omitempty"` ShortName string `json:"shortName,omitempty"`
Name string `json:"name,omitempty"` Name string `json:"name,omitempty"`
Estimations int `json:"estimations,omitempty"` Estimations int `json:"estimations,omitempty"`
Weight float32 `json:"weight,omitempty"` Weight float64 `json:"weight,omitempty"`
IsWeightSelectedByUser bool `json:"isWeightSelectedByUser,omitempty"` IsWeightSelectedByUser bool `json:"isWeightSelectedByUser,omitempty"`
Aspects []Aspect `json:"aspects,omitempty"` Aspects []Aspect `json:"aspects,omitempty"`
} }
type Aspect struct { type Aspect struct {
Points int `json:"points,omitempty"` Points int `json:"points,omitempty"`
MaxPoints float32 `json:"maxPoints,omitempty"` MaxPoints float64 `json:"maxPoints,omitempty"`
ID int `json:"id,omitempty"` ID int `json:"id,omitempty"`
ShortName string `json:"shortName,omitempty"` ShortName string `json:"shortName,omitempty"`
Name string `json:"name,omitempty"` Name string `json:"name,omitempty"`
Estimations int `json:"estimations,omitempty"` Estimations int `json:"estimations,omitempty"`
Weight float32 `json:"weight,omitempty"` Weight float64 `json:"weight,omitempty"`
IsWeightSelectedByUser bool `json:"isWeightSelectedByUser,omitempty"` IsWeightSelectedByUser bool `json:"isWeightSelectedByUser,omitempty"`
Aspects []Aspect `json:"aspects,omitempty"` Aspects []Aspect `json:"aspects,omitempty"`
IsPositive bool `json:"isPositive,omitempty"` IsPositive bool `json:"isPositive,omitempty"`

View File

@@ -1,10 +1,28 @@
package loader package loader
import ( import (
"bytes"
_ "embed"
"encoding/json" "encoding/json"
"io" "io"
"log"
) )
//go:embed conf/default.json
var defaultConf []byte
// DefaultConf loads the defaultConf of the package. The base
// is the default.json inside the package definition.
func DefaultConf() *Conf {
buf := bytes.NewBuffer(defaultConf)
conf := &Conf{}
err := conf.DecodeJSON(buf)
if err != nil {
log.Println("cannot decode default conf: ", err)
}
return conf
}
// Conf configures the mapping from the excel version // Conf configures the mapping from the excel version
// to the eCalc structure // to the eCalc structure
type Conf struct { type Conf struct {
@@ -15,6 +33,20 @@ type Conf struct {
Rating Rating `json:"rating"` Rating Rating `json:"rating"`
} }
// EncodeJSON writes the JSON of the conf into the Writer
func (c Conf) EncodeJSON(w io.Writer) error {
enc := json.NewEncoder(w)
enc.SetIndent("", " ")
return enc.Encode(c)
}
// DecodeJSON writes the configuration from the reader into
// the pointer of the conf
func (c *Conf) DecodeJSON(r io.Reader) error {
dec := json.NewDecoder(r)
return dec.Decode(c)
}
// Value defines a single value inside the excel workbook // Value defines a single value inside the excel workbook
type Value struct { type Value struct {
Sheet int `json:"sheet"` Sheet int `json:"sheet"`
@@ -61,17 +93,3 @@ type Rating struct {
WeightCol string `json:"weight_col"` WeightCol string `json:"weight_col"`
SelectedByUserCol string `json:"selected_by_user_col"` SelectedByUserCol string `json:"selected_by_user_col"`
} }
// EncodeJSON writes the JSON of the conf into the Writer
func (c Conf) EncodeJSON(w io.Writer) error {
enc := json.NewEncoder(w)
enc.SetIndent("", " ")
return enc.Encode(c)
}
// DecodeJSON writes the configuration from the reader into
// the pointer of the conf
func (c *Conf) DecodeJSON(r io.Reader) error {
dec := json.NewDecoder(r)
return dec.Decode(c)
}

View File

@@ -3,7 +3,7 @@
"version": "5.04", "version": "5.04",
"values": [ "values": [
{ {
"sheet": 3, "sheet": 2,
"cell": "C7", "cell": "C7",
"type": "int", "type": "int",
"struct": "CompanyFacts", "struct": "CompanyFacts",
@@ -11,7 +11,7 @@
"default": "" "default": ""
}, },
{ {
"sheet": 3, "sheet": 2,
"cell": "C27", "cell": "C27",
"type": "int", "type": "int",
"struct": "CompanyFacts", "struct": "CompanyFacts",
@@ -19,7 +19,7 @@
"default": "" "default": ""
}, },
{ {
"sheet": 3, "sheet": 2,
"cell": "C18", "cell": "C18",
"type": "int", "type": "int",
"struct": "CompanyFacts", "struct": "CompanyFacts",
@@ -27,7 +27,7 @@
"default": "" "default": ""
}, },
{ {
"sheet": 3, "sheet": 2,
"cell": "C19", "cell": "C19",
"type": "int", "type": "int",
"struct": "CompanyFacts", "struct": "CompanyFacts",
@@ -35,7 +35,7 @@
"default": "" "default": ""
}, },
{ {
"sheet": 3, "sheet": 2,
"cell": "C20", "cell": "C20",
"type": "int", "type": "int",
"struct": "CompanyFacts", "struct": "CompanyFacts",
@@ -43,7 +43,7 @@
"default": "" "default": ""
}, },
{ {
"sheet": 3, "sheet": 2,
"cell": "C22", "cell": "C22",
"type": "int", "type": "int",
"struct": "CompanyFacts", "struct": "CompanyFacts",
@@ -51,7 +51,7 @@
"default": "" "default": ""
}, },
{ {
"sheet": 3, "sheet": 2,
"cell": "C37", "cell": "C37",
"type": "int", "type": "int",
"struct": "CompanyFacts", "struct": "CompanyFacts",
@@ -59,7 +59,7 @@
"default": "" "default": ""
}, },
{ {
"sheet": 3, "sheet": 2,
"cell": "C21", "cell": "C21",
"type": "int", "type": "int",
"struct": "CompanyFacts", "struct": "CompanyFacts",
@@ -67,7 +67,7 @@
"default": "" "default": ""
}, },
{ {
"sheet": 3, "sheet": 2,
"cell": "C23", "cell": "C23",
"type": "int", "type": "int",
"struct": "CompanyFacts", "struct": "CompanyFacts",
@@ -75,7 +75,7 @@
"default": "" "default": ""
}, },
{ {
"sheet": 3, "sheet": 2,
"cell": "C26", "cell": "C26",
"type": "int", "type": "int",
"struct": "CompanyFacts", "struct": "CompanyFacts",
@@ -83,7 +83,7 @@
"default": "" "default": ""
}, },
{ {
"sheet": 3, "sheet": 2,
"cell": "C24", "cell": "C24",
"type": "bool", "type": "bool",
"struct": "CompanyFacts", "struct": "CompanyFacts",
@@ -91,7 +91,7 @@
"default": "" "default": ""
}, },
{ {
"sheet": 3, "sheet": 2,
"cell": "C38", "cell": "C38",
"type": "bool", "type": "bool",
"struct": "CompanyFacts", "struct": "CompanyFacts",
@@ -99,7 +99,7 @@
"default": "" "default": ""
}, },
{ {
"sheet": 3, "sheet": 2,
"cell": "C33", "cell": "C33",
"type": "int", "type": "int",
"struct": "CompanyFacts", "struct": "CompanyFacts",
@@ -109,7 +109,7 @@
], ],
"areas": [ "areas": [
{ {
"sheet": "3", "sheet": 2,
"start_row": 10, "start_row": 10,
"end_row": 14, "end_row": 14,
"struct": "SupplyFraction", "struct": "SupplyFraction",
@@ -135,7 +135,7 @@
] ]
}, },
{ {
"sheet": "3", "sheet": 2,
"start_row": 30, "start_row": 30,
"end_row": 32, "end_row": 32,
"struct": "EmployeesFraction", "struct": "EmployeesFraction",
@@ -149,13 +149,13 @@
{ {
"col": "D", "col": "D",
"field": "Percentage", "field": "Percentage",
"type": "float32", "type": "float64",
"default": "" "default": ""
} }
] ]
}, },
{ {
"sheet": "3", "sheet": 2,
"start_row": 41, "start_row": 41,
"end_row": 43, "end_row": 43,
"struct": "IndustrySector", "struct": "IndustrySector",
@@ -182,7 +182,7 @@
} }
], ],
"rating": { "rating": {
"sheet": 4, "sheet": 3,
"start_row": 9, "start_row": 9,
"end_row": 93, "end_row": 93,
"points_col": "I", "points_col": "I",

99
pkg/loader/loader.go Normal file
View File

@@ -0,0 +1,99 @@
package loader
import (
"fmt"
"io"
"git.ecogood.org/andreas.schroepfer/excelConverter/pkg/ecalc"
"git.ecogood.org/andreas.schroepfer/excelConverter/pkg/set"
"github.com/360EntSecGroup-Skylar/excelize/v2"
)
// XLSX reads the data out of the reader. If conf is nil
// the default configuration is used.
func XLSX(r io.Reader, conf *Conf) (*ecalc.Ecalc, error) {
eBalance := &ecalc.Ecalc{}
var errs []error
if conf == nil {
conf = DefaultConf()
}
xFile, err := excelize.OpenReader(r)
if err != nil {
return nil, fmt.Errorf("XLSX.OpenReader: %w", err)
}
for _, v := range conf.Values {
cellValue, err := xFile.GetCellValue(
xFile.GetSheetName(v.Sheet),
v.Cell,
)
if err != nil {
errs = append(errs, err)
}
switch v.Struct {
case "CompanyFacts":
set.Field(&eBalance.CompanyFacts, v.Field, cellValue)
}
}
for _, a := range conf.Areas {
switch a.Struct {
case "SupplyFraction":
for r := a.StartRow; r <= a.EndRow; r++ {
sf := ecalc.SupplyFraction{}
for _, c := range a.Cols {
cellValue, err := xFile.GetCellValue(
xFile.GetSheetName(a.Sheet),
fmt.Sprintf("%s%d", c.Col, r),
)
if err != nil {
errs = append(errs, err)
}
set.Field(&sf, c.Field, cellValue)
}
eBalance.CompanyFacts.SupplyFractions =
append(
eBalance.CompanyFacts.SupplyFractions,
sf)
}
case "EmployeesFraction":
for r := a.StartRow; r <= a.EndRow; r++ {
ef := ecalc.EmployeesFraction{}
for _, c := range a.Cols {
cellValue, err := xFile.GetCellValue(
xFile.GetSheetName(a.Sheet),
fmt.Sprintf("%s%d", c.Col, r),
)
if err != nil {
errs = append(errs, err)
}
set.Field(&ef, c.Field, cellValue)
}
eBalance.CompanyFacts.EmployeesFractions =
append(
eBalance.CompanyFacts.EmployeesFractions,
ef)
}
case "IndustrySector":
for r := a.StartRow; r <= a.EndRow; r++ {
is := ecalc.IndustrySector{}
for _, c := range a.Cols {
cellValue, err := xFile.GetCellValue(
xFile.GetSheetName(a.Sheet),
fmt.Sprintf("%s%d", c.Col, r),
)
if err != nil {
errs = append(errs, err)
}
set.Field(&is, c.Field, cellValue)
}
eBalance.CompanyFacts.IndustrySectors =
append(
eBalance.CompanyFacts.IndustrySectors,
is)
}
}
}
// TODO: error handling of errs
return eBalance, nil
}

View File

@@ -3,16 +3,37 @@ package set
import ( import (
"errors" "errors"
"reflect" "reflect"
"strconv"
) )
func Field(dst interface{}, fieldName string, value interface{}) error { var (
ErrTypeConvert = errors.New("cannot convert input")
)
func Field(dst interface{}, fieldName string, value string) error {
valDst := reflect.ValueOf(dst).Elem() valDst := reflect.ValueOf(dst).Elem()
dstField := valDst.FieldByName(fieldName) dstField := valDst.FieldByName(fieldName)
val := reflect.ValueOf(value) val := reflect.ValueOf(value)
if dstField.Kind() != val.Kind() { if dstField.Kind() != val.Kind() {
return errors.New("value-Type does not match to field") // try to convert
switch dstField.Kind() {
case reflect.Int:
d, err := strconv.Atoi(value)
if err != nil {
return ErrTypeConvert
}
val = reflect.ValueOf(d)
case reflect.Float64:
f, err := strconv.ParseFloat(value, 64)
if err != nil {
return ErrTypeConvert
}
val = reflect.ValueOf(f)
default:
return ErrTypeConvert
}
} }
dstField.Set(val) dstField.Set(val)

View File

@@ -6,6 +6,7 @@ func TestField(t *testing.T) {
input := struct { input := struct {
MyString string MyString string
MyInt int MyInt int
MyFloat float64
MyBool bool MyBool bool
}{} }{}
value := "abc" value := "abc"
@@ -13,15 +14,21 @@ func TestField(t *testing.T) {
if input.MyString != value { if input.MyString != value {
t.Errorf("got: %s; want: %s", input.MyString, value) t.Errorf("got: %s; want: %s", input.MyString, value)
} }
vInt := 2 err := Field(&input, "MyFloat", "3.14")
Field(&input, "MyInt", vInt) if err != nil {
if input.MyInt != vInt { t.Error("expect no error, when can be converted")
t.Errorf("MyInt: %d, want: %d", input.MyInt, vInt)
} }
err := Field(&input, "MyInt", "vInt") if input.MyFloat != 3.14 {
t.Errorf("MyFloat is not 3.14. Got: %#v", input.MyFloat)
}
err = Field(&input, "MyInt", "vInt")
if err == nil { if err == nil {
t.Error("expect error, when wrong value-Type") t.Error("expect error, when wrong value-Type")
} }
err = Field(&input, "MyInt", "3")
if err != nil {
t.Error("expect no error, when can be converted")
}
err = Field(&input, "NoField", "jjj") err = Field(&input, "NoField", "jjj")
if err == nil { if err == nil {
t.Error("expect error, when field not exists") t.Error("expect error, when field not exists")