handle dimension
This commit is contained in:
@ -1,5 +1,11 @@
|
|||||||
namespace internal.encoding.fbs;
|
namespace internal.encoding.fbs;
|
||||||
|
|
||||||
|
struct Dimensions {
|
||||||
|
width:float;
|
||||||
|
height:float;
|
||||||
|
length:float;
|
||||||
|
}
|
||||||
|
|
||||||
table GoodItem {
|
table GoodItem {
|
||||||
sku:string;
|
sku:string;
|
||||||
photo:string;
|
photo:string;
|
||||||
@ -14,6 +20,7 @@ table GoodItem {
|
|||||||
tariff:float;
|
tariff:float;
|
||||||
cart:long;
|
cart:long;
|
||||||
stock:short;
|
stock:short;
|
||||||
|
sizes:Dimensions;
|
||||||
parameters:string;
|
parameters:string;
|
||||||
created_at:long;
|
created_at:long;
|
||||||
}
|
}
|
||||||
|
|||||||
71
cmd/cli/dimensiondispatcher.go
Normal file
71
cmd/cli/dimensiondispatcher.go
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"git.loyso.art/frx/eway/internal/entity"
|
||||||
|
"git.loyso.art/frx/eway/internal/matcher"
|
||||||
|
"github.com/rs/zerolog"
|
||||||
|
)
|
||||||
|
|
||||||
|
type dimensionDispatcher struct {
|
||||||
|
heigth matcher.Unit
|
||||||
|
width matcher.Unit
|
||||||
|
length matcher.Unit
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d dimensionDispatcher) isDimensionParam(value string) bool {
|
||||||
|
return d.heigth.Match(value) || d.width.Match(value) || d.length.Match(value)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d dimensionDispatcher) dispatch(ctx context.Context, value, key string, in *entity.GoodsItemSize) {
|
||||||
|
if !d.isDimensionParam(value) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if strings.Contains(value, "/") {
|
||||||
|
dimensionValues := strings.Split(value, "/")
|
||||||
|
for _, dv := range dimensionValues {
|
||||||
|
d.dispatch(ctx, dv, key, in)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
out, err := entity.ParseDimention(key, entity.DimensionLocalRU)
|
||||||
|
if err != nil {
|
||||||
|
zerolog.Ctx(ctx).Warn().Err(err).Msg("unable to parse key, skipping")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
out = out.AdjustTo(entity.DimensionKindCentimeter)
|
||||||
|
|
||||||
|
switch {
|
||||||
|
case d.heigth.Match(value):
|
||||||
|
in.Height = out
|
||||||
|
case d.width.Match(value):
|
||||||
|
in.Width = out
|
||||||
|
case d.width.Match(value):
|
||||||
|
in.Length = out
|
||||||
|
default:
|
||||||
|
zerolog.Ctx(ctx).Error().Str("key", key).Msg("unable to find proper matcher")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func makeDefaultDimensionDispatcher() dimensionDispatcher {
|
||||||
|
h := matcher.NewRadix(matcher.RadixCaseInsensitive())
|
||||||
|
h.Register("Высота")
|
||||||
|
h.Register("Высота/*")
|
||||||
|
w := matcher.NewRadix(matcher.RadixCaseInsensitive())
|
||||||
|
w.Register("Ширина")
|
||||||
|
w.Register("Ширина/*")
|
||||||
|
l := matcher.NewRadix(matcher.RadixCaseInsensitive())
|
||||||
|
l.Register("Длина")
|
||||||
|
l.Register("Длина/*")
|
||||||
|
l.Register("Общ. длина")
|
||||||
|
|
||||||
|
return dimensionDispatcher{
|
||||||
|
heigth: h,
|
||||||
|
width: w,
|
||||||
|
length: l,
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -34,6 +34,8 @@ import (
|
|||||||
"github.com/urfave/cli/v3"
|
"github.com/urfave/cli/v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type empty entity.Empty
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
ctx, cancel := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM)
|
ctx, cancel := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM)
|
||||||
defer func() {
|
defer func() {
|
||||||
@ -506,14 +508,14 @@ func viewItemsUniqueParamsAction(ctx context.Context, c *cli.Command) error {
|
|||||||
return fmt.Errorf("getting repository: %w", err)
|
return fmt.Errorf("getting repository: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
knownParams := map[string]struct{}{}
|
knownParams := map[string]empty{}
|
||||||
iter, err := repository.GoodsItem().ListIter(ctx, 1)
|
iter, err := repository.GoodsItem().ListIter(ctx, 1)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("getting list iter: %w", err)
|
return fmt.Errorf("getting list iter: %w", err)
|
||||||
}
|
}
|
||||||
for item := range iter {
|
for item := range iter {
|
||||||
for k := range item.Parameters {
|
for k := range item.Parameters {
|
||||||
knownParams[k] = struct{}{}
|
knownParams[k] = empty{}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -595,8 +597,8 @@ func viewItemsParamsKnownValuesAction(ctx context.Context, c *cli.Command) error
|
|||||||
m.RegisterRegexp(regexp)
|
m.RegisterRegexp(regexp)
|
||||||
}
|
}
|
||||||
|
|
||||||
requestedValues := make(map[string]map[string]struct{}, len(params))
|
requestedValues := make(map[string]map[string]empty, len(params))
|
||||||
requestedValuesByPattern := make(map[string]map[string]struct{}, len(params))
|
requestedValuesByPattern := make(map[string]map[string]empty, len(params))
|
||||||
iter := getItemsIter(ctx, repository.GoodsItem())
|
iter := getItemsIter(ctx, repository.GoodsItem())
|
||||||
for iter.Next() {
|
for iter.Next() {
|
||||||
item := iter.Get()
|
item := iter.Get()
|
||||||
@ -608,16 +610,16 @@ func viewItemsParamsKnownValuesAction(ctx context.Context, c *cli.Command) error
|
|||||||
|
|
||||||
values, ok := requestedValues[k]
|
values, ok := requestedValues[k]
|
||||||
if !ok {
|
if !ok {
|
||||||
values = make(map[string]struct{})
|
values = make(map[string]empty)
|
||||||
}
|
}
|
||||||
values[v] = struct{}{}
|
values[v] = empty{}
|
||||||
requestedValues[k] = values
|
requestedValues[k] = values
|
||||||
|
|
||||||
values, ok = requestedValuesByPattern[matchedPattern]
|
values, ok = requestedValuesByPattern[matchedPattern]
|
||||||
if !ok {
|
if !ok {
|
||||||
values = map[string]struct{}{}
|
values = map[string]empty{}
|
||||||
}
|
}
|
||||||
values[v] = struct{}{}
|
values[v] = empty{}
|
||||||
requestedValuesByPattern[matchedPattern] = values
|
requestedValuesByPattern[matchedPattern] = values
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -657,7 +659,7 @@ func viewItemsCountAction(ctx context.Context, c *cli.Command) error {
|
|||||||
|
|
||||||
filters := c.StringSlice("param-key-match")
|
filters := c.StringSlice("param-key-match")
|
||||||
m := matcher.NewRadix()
|
m := matcher.NewRadix()
|
||||||
patternMapped := make(map[string]struct{}, len(filters))
|
patternMapped := make(map[string]empty, len(filters))
|
||||||
if len(filters) == 0 {
|
if len(filters) == 0 {
|
||||||
m.Register("*")
|
m.Register("*")
|
||||||
} else {
|
} else {
|
||||||
@ -665,7 +667,7 @@ func viewItemsCountAction(ctx context.Context, c *cli.Command) error {
|
|||||||
m.Register(f)
|
m.Register(f)
|
||||||
}
|
}
|
||||||
for _, pattern := range m.Patterns() {
|
for _, pattern := range m.Patterns() {
|
||||||
patternMapped[pattern] = struct{}{}
|
patternMapped[pattern] = empty{}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -675,7 +677,7 @@ func viewItemsCountAction(ctx context.Context, c *cli.Command) error {
|
|||||||
return fmt.Errorf("getting items: %w", err)
|
return fmt.Errorf("getting items: %w", err)
|
||||||
}
|
}
|
||||||
for _, item := range items {
|
for _, item := range items {
|
||||||
seenPatterns := map[string]struct{}{}
|
seenPatterns := map[string]empty{}
|
||||||
|
|
||||||
for k := range item.Parameters {
|
for k := range item.Parameters {
|
||||||
pattern := m.MatchByPattern(k)
|
pattern := m.MatchByPattern(k)
|
||||||
@ -685,7 +687,7 @@ func viewItemsCountAction(ctx context.Context, c *cli.Command) error {
|
|||||||
if _, ok := seenPatterns[pattern]; ok {
|
if _, ok := seenPatterns[pattern]; ok {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
seenPatterns[pattern] = struct{}{}
|
seenPatterns[pattern] = empty{}
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(seenPatterns) == len(patternMapped) {
|
if len(seenPatterns) == len(patternMapped) {
|
||||||
@ -794,14 +796,14 @@ func importFromFileAction(ctx context.Context, c *cli.Command) error {
|
|||||||
failedToInsert int
|
failedToInsert int
|
||||||
)
|
)
|
||||||
|
|
||||||
seenCategories := make(map[string]struct{})
|
seenCategories := make(map[string]empty)
|
||||||
categories, err := r.Category().List(ctx)
|
categories, err := r.Category().List(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("listing categories: %w", err)
|
return fmt.Errorf("listing categories: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, category := range categories {
|
for _, category := range categories {
|
||||||
seenCategories[category.Name] = struct{}{}
|
seenCategories[category.Name] = empty{}
|
||||||
}
|
}
|
||||||
|
|
||||||
bfile := bufio.NewReader(productsFile)
|
bfile := bufio.NewReader(productsFile)
|
||||||
@ -841,7 +843,7 @@ func importFromFileAction(ctx context.Context, c *cli.Command) error {
|
|||||||
return fmt.Errorf("unable to create new category: %w", err)
|
return fmt.Errorf("unable to create new category: %w", err)
|
||||||
}
|
}
|
||||||
log.Debug().Any("category", goodsItem.Type).Msg("inserted new category")
|
log.Debug().Any("category", goodsItem.Type).Msg("inserted new category")
|
||||||
seenCategories[goodsItem.Type] = struct{}{}
|
seenCategories[goodsItem.Type] = empty{}
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Debug().Int("count", len(goodsItems)).Int("failed", failedToInsert).Msg("preparing to upload")
|
log.Debug().Int("count", len(goodsItems)).Int("failed", failedToInsert).Msg("preparing to upload")
|
||||||
@ -1137,16 +1139,16 @@ func parseEwayDumpAction(ctx context.Context, cmd *cli.Command) error {
|
|||||||
goodsItems := make([]entity.GoodsItem, 0, batchSize)
|
goodsItems := make([]entity.GoodsItem, 0, batchSize)
|
||||||
productIDs := make([]int, 0, batchSize)
|
productIDs := make([]int, 0, batchSize)
|
||||||
|
|
||||||
knownCategories := make(map[string]struct{})
|
knownCategories := make(map[string]empty)
|
||||||
err = entity.IterWithErr(repository.Category().List(ctx)).Do(func(c entity.Category) error {
|
err = entity.IterWithErr(repository.Category().List(ctx)).Do(func(c entity.Category) error {
|
||||||
knownCategories[c.Name] = struct{}{}
|
knownCategories[c.Name] = empty{}
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("filling known categories: %w", err)
|
return fmt.Errorf("filling known categories: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
itemsUpdated := make(map[string]struct{}, len(seenItems))
|
itemsUpdated := make(map[string]empty, len(seenItems))
|
||||||
stats := struct {
|
stats := struct {
|
||||||
fetchedInfo int
|
fetchedInfo int
|
||||||
handledAll int
|
handledAll int
|
||||||
@ -1154,6 +1156,8 @@ func parseEwayDumpAction(ctx context.Context, cmd *cli.Command) error {
|
|||||||
skippedItem int
|
skippedItem int
|
||||||
}{}
|
}{}
|
||||||
|
|
||||||
|
dimensionDispatcher := makeDefaultDimensionDispatcher()
|
||||||
|
|
||||||
startFrom := time.Now()
|
startFrom := time.Now()
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
@ -1190,7 +1194,7 @@ func parseEwayDumpAction(ctx context.Context, cmd *cli.Command) error {
|
|||||||
if time.Since(seenItem.CreatedAt) < time.Hour*24 {
|
if time.Since(seenItem.CreatedAt) < time.Hour*24 {
|
||||||
logger.Debug().Str("sku", item.SKU).Msg("skipping item because it's too fresh")
|
logger.Debug().Str("sku", item.SKU).Msg("skipping item because it's too fresh")
|
||||||
stats.skippedItem++
|
stats.skippedItem++
|
||||||
itemsUpdated[item.SKU] = struct{}{}
|
itemsUpdated[item.SKU] = empty{}
|
||||||
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@ -1213,7 +1217,11 @@ func parseEwayDumpAction(ctx context.Context, cmd *cli.Command) error {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
itemsUpdated[goodsItem.Articul] = struct{}{}
|
for key, value := range goodsItem.Parameters {
|
||||||
|
dimensionDispatcher.dispatch(ctx, key, value, &goodsItem.Sizes)
|
||||||
|
}
|
||||||
|
|
||||||
|
itemsUpdated[goodsItem.Articul] = empty{}
|
||||||
stats.handledAll++
|
stats.handledAll++
|
||||||
|
|
||||||
goodsItems = append(goodsItems, goodsItem)
|
goodsItems = append(goodsItems, goodsItem)
|
||||||
@ -1235,7 +1243,7 @@ func parseEwayDumpAction(ctx context.Context, cmd *cli.Command) error {
|
|||||||
Int64("id", category.ID).
|
Int64("id", category.ID).
|
||||||
Msg("created new category")
|
Msg("created new category")
|
||||||
|
|
||||||
knownCategories[goodsItem.Type] = struct{}{}
|
knownCategories[goodsItem.Type] = empty{}
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = repository.GoodsItem().UpsertMany(ctx, goodsItems...)
|
_, err = repository.GoodsItem().UpsertMany(ctx, goodsItems...)
|
||||||
|
|||||||
5
go.mod
5
go.mod
@ -13,12 +13,14 @@ require (
|
|||||||
github.com/rodaine/table v1.1.1
|
github.com/rodaine/table v1.1.1
|
||||||
github.com/rs/zerolog v1.31.0
|
github.com/rs/zerolog v1.31.0
|
||||||
github.com/samber/do v1.6.0
|
github.com/samber/do v1.6.0
|
||||||
|
github.com/stretchr/testify v1.8.4
|
||||||
github.com/urfave/cli/v3 v3.0.0-alpha8
|
github.com/urfave/cli/v3 v3.0.0-alpha8
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/andybalholm/cascadia v1.3.1 // indirect
|
github.com/andybalholm/cascadia v1.3.1 // indirect
|
||||||
github.com/cespare/xxhash/v2 v2.2.0 // indirect
|
github.com/cespare/xxhash/v2 v2.2.0 // indirect
|
||||||
|
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||||
github.com/dustin/go-humanize v1.0.0 // indirect
|
github.com/dustin/go-humanize v1.0.0 // indirect
|
||||||
github.com/gogo/protobuf v1.3.2 // indirect
|
github.com/gogo/protobuf v1.3.2 // indirect
|
||||||
github.com/golang/glog v1.0.0 // indirect
|
github.com/golang/glog v1.0.0 // indirect
|
||||||
@ -26,12 +28,15 @@ require (
|
|||||||
github.com/golang/protobuf v1.5.2 // indirect
|
github.com/golang/protobuf v1.5.2 // indirect
|
||||||
github.com/golang/snappy v0.0.3 // indirect
|
github.com/golang/snappy v0.0.3 // indirect
|
||||||
github.com/klauspost/compress v1.12.3 // indirect
|
github.com/klauspost/compress v1.12.3 // indirect
|
||||||
|
github.com/kr/text v0.2.0 // indirect
|
||||||
github.com/mattn/go-colorable v0.1.13 // indirect
|
github.com/mattn/go-colorable v0.1.13 // indirect
|
||||||
github.com/mattn/go-isatty v0.0.19 // indirect
|
github.com/mattn/go-isatty v0.0.19 // indirect
|
||||||
github.com/pkg/errors v0.9.1 // indirect
|
github.com/pkg/errors v0.9.1 // indirect
|
||||||
|
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||||
github.com/xrash/smetrics v0.0.0-20231213231151-1d8dd44e695e // indirect
|
github.com/xrash/smetrics v0.0.0-20231213231151-1d8dd44e695e // indirect
|
||||||
go.opencensus.io v0.22.5 // indirect
|
go.opencensus.io v0.22.5 // indirect
|
||||||
golang.org/x/net v0.17.0 // indirect
|
golang.org/x/net v0.17.0 // indirect
|
||||||
golang.org/x/sys v0.13.0 // indirect
|
golang.org/x/sys v0.13.0 // indirect
|
||||||
google.golang.org/protobuf v1.28.1 // indirect
|
google.golang.org/protobuf v1.28.1 // indirect
|
||||||
|
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||||
)
|
)
|
||||||
|
|||||||
7
go.sum
7
go.sum
@ -13,6 +13,7 @@ github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj
|
|||||||
github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||||
github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
|
github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
|
||||||
|
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
@ -53,6 +54,10 @@ github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI
|
|||||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||||
github.com/klauspost/compress v1.12.3 h1:G5AfA94pHPysR56qqrkO2pxEexdDzrpFJ6yt/VqWxVU=
|
github.com/klauspost/compress v1.12.3 h1:G5AfA94pHPysR56qqrkO2pxEexdDzrpFJ6yt/VqWxVU=
|
||||||
github.com/klauspost/compress v1.12.3/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg=
|
github.com/klauspost/compress v1.12.3/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg=
|
||||||
|
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
|
||||||
|
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||||
|
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||||
|
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||||
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
|
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
|
||||||
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
|
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
|
||||||
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
|
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
|
||||||
@ -184,6 +189,8 @@ google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQ
|
|||||||
google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w=
|
google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w=
|
||||||
google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
|
||||||
|
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||||
|
|||||||
49
internal/encoding/fbs/Dimensions.go
Normal file
49
internal/encoding/fbs/Dimensions.go
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
// Code generated by the FlatBuffers compiler. DO NOT EDIT.
|
||||||
|
|
||||||
|
package fbs
|
||||||
|
|
||||||
|
import (
|
||||||
|
flatbuffers "github.com/google/flatbuffers/go"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Dimensions struct {
|
||||||
|
_tab flatbuffers.Struct
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rcv *Dimensions) Init(buf []byte, i flatbuffers.UOffsetT) {
|
||||||
|
rcv._tab.Bytes = buf
|
||||||
|
rcv._tab.Pos = i
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rcv *Dimensions) Table() flatbuffers.Table {
|
||||||
|
return rcv._tab.Table
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rcv *Dimensions) Width() float32 {
|
||||||
|
return rcv._tab.GetFloat32(rcv._tab.Pos + flatbuffers.UOffsetT(0))
|
||||||
|
}
|
||||||
|
func (rcv *Dimensions) MutateWidth(n float32) bool {
|
||||||
|
return rcv._tab.MutateFloat32(rcv._tab.Pos+flatbuffers.UOffsetT(0), n)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rcv *Dimensions) Height() float32 {
|
||||||
|
return rcv._tab.GetFloat32(rcv._tab.Pos + flatbuffers.UOffsetT(4))
|
||||||
|
}
|
||||||
|
func (rcv *Dimensions) MutateHeight(n float32) bool {
|
||||||
|
return rcv._tab.MutateFloat32(rcv._tab.Pos+flatbuffers.UOffsetT(4), n)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rcv *Dimensions) Length() float32 {
|
||||||
|
return rcv._tab.GetFloat32(rcv._tab.Pos + flatbuffers.UOffsetT(8))
|
||||||
|
}
|
||||||
|
func (rcv *Dimensions) MutateLength(n float32) bool {
|
||||||
|
return rcv._tab.MutateFloat32(rcv._tab.Pos+flatbuffers.UOffsetT(8), n)
|
||||||
|
}
|
||||||
|
|
||||||
|
func CreateDimensions(builder *flatbuffers.Builder, width float32, height float32, length float32) flatbuffers.UOffsetT {
|
||||||
|
builder.Prep(4, 12)
|
||||||
|
builder.PrependFloat32(length)
|
||||||
|
builder.PrependFloat32(height)
|
||||||
|
builder.PrependFloat32(width)
|
||||||
|
return builder.Offset()
|
||||||
|
}
|
||||||
@ -169,8 +169,21 @@ func (rcv *GoodItem) MutateStock(n int16) bool {
|
|||||||
return rcv._tab.MutateInt16Slot(28, n)
|
return rcv._tab.MutateInt16Slot(28, n)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (rcv *GoodItem) Parameters() []byte {
|
func (rcv *GoodItem) Sizes(obj *Dimensions) *Dimensions {
|
||||||
o := flatbuffers.UOffsetT(rcv._tab.Offset(30))
|
o := flatbuffers.UOffsetT(rcv._tab.Offset(30))
|
||||||
|
if o != 0 {
|
||||||
|
x := o + rcv._tab.Pos
|
||||||
|
if obj == nil {
|
||||||
|
obj = new(Dimensions)
|
||||||
|
}
|
||||||
|
obj.Init(rcv._tab.Bytes, x)
|
||||||
|
return obj
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rcv *GoodItem) Parameters() []byte {
|
||||||
|
o := flatbuffers.UOffsetT(rcv._tab.Offset(32))
|
||||||
if o != 0 {
|
if o != 0 {
|
||||||
return rcv._tab.ByteVector(o + rcv._tab.Pos)
|
return rcv._tab.ByteVector(o + rcv._tab.Pos)
|
||||||
}
|
}
|
||||||
@ -178,7 +191,7 @@ func (rcv *GoodItem) Parameters() []byte {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (rcv *GoodItem) CreatedAt() int64 {
|
func (rcv *GoodItem) CreatedAt() int64 {
|
||||||
o := flatbuffers.UOffsetT(rcv._tab.Offset(32))
|
o := flatbuffers.UOffsetT(rcv._tab.Offset(34))
|
||||||
if o != 0 {
|
if o != 0 {
|
||||||
return rcv._tab.GetInt64(o + rcv._tab.Pos)
|
return rcv._tab.GetInt64(o + rcv._tab.Pos)
|
||||||
}
|
}
|
||||||
@ -186,11 +199,11 @@ func (rcv *GoodItem) CreatedAt() int64 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (rcv *GoodItem) MutateCreatedAt(n int64) bool {
|
func (rcv *GoodItem) MutateCreatedAt(n int64) bool {
|
||||||
return rcv._tab.MutateInt64Slot(32, n)
|
return rcv._tab.MutateInt64Slot(34, n)
|
||||||
}
|
}
|
||||||
|
|
||||||
func GoodItemStart(builder *flatbuffers.Builder) {
|
func GoodItemStart(builder *flatbuffers.Builder) {
|
||||||
builder.StartObject(15)
|
builder.StartObject(16)
|
||||||
}
|
}
|
||||||
func GoodItemAddSku(builder *flatbuffers.Builder, sku flatbuffers.UOffsetT) {
|
func GoodItemAddSku(builder *flatbuffers.Builder, sku flatbuffers.UOffsetT) {
|
||||||
builder.PrependUOffsetTSlot(0, flatbuffers.UOffsetT(sku), 0)
|
builder.PrependUOffsetTSlot(0, flatbuffers.UOffsetT(sku), 0)
|
||||||
@ -231,11 +244,14 @@ func GoodItemAddCart(builder *flatbuffers.Builder, cart int64) {
|
|||||||
func GoodItemAddStock(builder *flatbuffers.Builder, stock int16) {
|
func GoodItemAddStock(builder *flatbuffers.Builder, stock int16) {
|
||||||
builder.PrependInt16Slot(12, stock, 0)
|
builder.PrependInt16Slot(12, stock, 0)
|
||||||
}
|
}
|
||||||
|
func GoodItemAddSizes(builder *flatbuffers.Builder, sizes flatbuffers.UOffsetT) {
|
||||||
|
builder.PrependStructSlot(13, flatbuffers.UOffsetT(sizes), 0)
|
||||||
|
}
|
||||||
func GoodItemAddParameters(builder *flatbuffers.Builder, parameters flatbuffers.UOffsetT) {
|
func GoodItemAddParameters(builder *flatbuffers.Builder, parameters flatbuffers.UOffsetT) {
|
||||||
builder.PrependUOffsetTSlot(13, flatbuffers.UOffsetT(parameters), 0)
|
builder.PrependUOffsetTSlot(14, flatbuffers.UOffsetT(parameters), 0)
|
||||||
}
|
}
|
||||||
func GoodItemAddCreatedAt(builder *flatbuffers.Builder, createdAt int64) {
|
func GoodItemAddCreatedAt(builder *flatbuffers.Builder, createdAt int64) {
|
||||||
builder.PrependInt64Slot(14, createdAt, 0)
|
builder.PrependInt64Slot(15, createdAt, 0)
|
||||||
}
|
}
|
||||||
func GoodItemEnd(builder *flatbuffers.Builder) flatbuffers.UOffsetT {
|
func GoodItemEnd(builder *flatbuffers.Builder) flatbuffers.UOffsetT {
|
||||||
return builder.EndObject()
|
return builder.EndObject()
|
||||||
|
|||||||
@ -82,6 +82,14 @@ func makeDomainGoodItem(builder *flatbuffers.Builder, in entity.GoodsItem) flatb
|
|||||||
|
|
||||||
producer := builder.CreateString(in.Producer)
|
producer := builder.CreateString(in.Producer)
|
||||||
|
|
||||||
|
var w, h, l float32
|
||||||
|
if in.Sizes != (entity.GoodsItemSize{}) {
|
||||||
|
w = float32(in.Sizes.Width.AdjustTo(entity.DimensionKindCentimeter).Value)
|
||||||
|
h = float32(in.Sizes.Height.AdjustTo(entity.DimensionKindCentimeter).Value)
|
||||||
|
l = float32(in.Sizes.Length.AdjustTo(entity.DimensionKindCentimeter).Value)
|
||||||
|
}
|
||||||
|
sizes := CreateDimensions(builder, w, h, l)
|
||||||
|
|
||||||
GoodItemStart(builder)
|
GoodItemStart(builder)
|
||||||
GoodItemAddSku(builder, sku)
|
GoodItemAddSku(builder, sku)
|
||||||
GoodItemAddPhoto(builder, photo)
|
GoodItemAddPhoto(builder, photo)
|
||||||
@ -98,6 +106,7 @@ func makeDomainGoodItem(builder *flatbuffers.Builder, in entity.GoodsItem) flatb
|
|||||||
GoodItemAddTariff(builder, float32(in.TariffPrice))
|
GoodItemAddTariff(builder, float32(in.TariffPrice))
|
||||||
GoodItemAddCart(builder, int64(in.Cart))
|
GoodItemAddCart(builder, int64(in.Cart))
|
||||||
GoodItemAddStock(builder, int16(in.Stock))
|
GoodItemAddStock(builder, int16(in.Stock))
|
||||||
|
GoodItemAddSizes(builder, sizes)
|
||||||
GoodItemAddParameters(builder, parameters)
|
GoodItemAddParameters(builder, parameters)
|
||||||
GoodItemAddCreatedAt(builder, in.CreatedAt.Unix())
|
GoodItemAddCreatedAt(builder, in.CreatedAt.Unix())
|
||||||
|
|
||||||
@ -136,6 +145,17 @@ func ParseGoodsItem(data []byte) (item entity.GoodsItem, err error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sizes := itemFBS.Sizes(nil)
|
||||||
|
w := float64(sizes.Width())
|
||||||
|
h := float64(sizes.Height())
|
||||||
|
l := float64(sizes.Length())
|
||||||
|
|
||||||
|
item.Sizes = entity.GoodsItemSize{
|
||||||
|
Width: entity.NewMilimeterDimension(w),
|
||||||
|
Height: entity.NewMilimeterDimension(h),
|
||||||
|
Length: entity.NewMilimeterDimension(l),
|
||||||
|
}
|
||||||
|
|
||||||
createdAt := itemFBS.CreatedAt()
|
createdAt := itemFBS.CreatedAt()
|
||||||
if createdAt > 0 {
|
if createdAt > 0 {
|
||||||
item.CreatedAt = time.Unix(createdAt, 0)
|
item.CreatedAt = time.Unix(createdAt, 0)
|
||||||
|
|||||||
142
internal/entity/dimension.go
Normal file
142
internal/entity/dimension.go
Normal file
@ -0,0 +1,142 @@
|
|||||||
|
package entity
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
var DefaultLocale = DimensionLocalRU
|
||||||
|
|
||||||
|
type DimensionLocale uint8
|
||||||
|
|
||||||
|
const (
|
||||||
|
DimensionLocalUnspecified DimensionLocale = iota
|
||||||
|
DimensionLocalRU
|
||||||
|
|
||||||
|
dimensionLocalEnd
|
||||||
|
)
|
||||||
|
|
||||||
|
type DimensionKind uint8
|
||||||
|
|
||||||
|
func (k DimensionKind) GetPos() float64 {
|
||||||
|
switch k {
|
||||||
|
case DimensionKindMilimeter:
|
||||||
|
return 1
|
||||||
|
case DimensionKindCentimeter:
|
||||||
|
return 10
|
||||||
|
case DimensionKindMeter:
|
||||||
|
return 1000
|
||||||
|
default:
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (k DimensionKind) String() string {
|
||||||
|
m := getLocaleKindToStringMap()[DefaultLocale]
|
||||||
|
return m[k]
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
DimensionKindUnspecified DimensionKind = iota
|
||||||
|
DimensionKindMilimeter
|
||||||
|
DimensionKindCentimeter
|
||||||
|
DimensionKindMeter
|
||||||
|
)
|
||||||
|
|
||||||
|
type Dimension struct {
|
||||||
|
Value float64
|
||||||
|
Kind DimensionKind
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d Dimension) MarshalText() ([]byte, error) {
|
||||||
|
value := strconv.FormatFloat(d.Value, 'f', 4, 64) + " " + d.Kind.String()
|
||||||
|
return []byte(value), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Dimension) UnmarshalText(data []byte) (err error) {
|
||||||
|
*d, err = ParseDimention(string(data), DefaultLocale)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d Dimension) AdjustTo(kind DimensionKind) Dimension {
|
||||||
|
from := d.Kind.GetPos()
|
||||||
|
to := kind.GetPos()
|
||||||
|
|
||||||
|
switch {
|
||||||
|
case from < to:
|
||||||
|
mult := to / from
|
||||||
|
return Dimension{
|
||||||
|
Kind: kind,
|
||||||
|
Value: d.Value / float64(mult),
|
||||||
|
}
|
||||||
|
case from > to:
|
||||||
|
mult := from / to
|
||||||
|
return Dimension{
|
||||||
|
Kind: kind,
|
||||||
|
Value: d.Value * float64(mult),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return d
|
||||||
|
}
|
||||||
|
|
||||||
|
func ParseDimention(value string, locale DimensionLocale) (Dimension, error) {
|
||||||
|
switch locale {
|
||||||
|
case DimensionLocalRU:
|
||||||
|
default:
|
||||||
|
return Dimension{}, SimpleError("unknown locale for parse")
|
||||||
|
}
|
||||||
|
|
||||||
|
dimensionStrToKind := getLocaleToKindMap()[locale]
|
||||||
|
lastSpaceIdx := strings.LastIndex(value, " ")
|
||||||
|
if lastSpaceIdx == -1 {
|
||||||
|
return Dimension{}, SimpleError("expected 2 values after split for value " + value)
|
||||||
|
}
|
||||||
|
|
||||||
|
var splitted [2]string
|
||||||
|
splitted[0] = strings.ReplaceAll(value[:lastSpaceIdx], " ", "")
|
||||||
|
splitted[1] = value[lastSpaceIdx+1:]
|
||||||
|
|
||||||
|
var out Dimension
|
||||||
|
var ok bool
|
||||||
|
out.Kind, ok = dimensionStrToKind[splitted[1]]
|
||||||
|
if !ok {
|
||||||
|
return Dimension{}, SimpleError("dimension map not found for kind " + splitted[1])
|
||||||
|
}
|
||||||
|
|
||||||
|
var err error
|
||||||
|
out.Value, err = strconv.ParseFloat(splitted[0], 64)
|
||||||
|
if err != nil {
|
||||||
|
return Dimension{}, fmt.Errorf("parsing value: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return out, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewMilimeterDimension(value float64) Dimension {
|
||||||
|
return Dimension{
|
||||||
|
Value: value,
|
||||||
|
Kind: DimensionKindMilimeter,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func getLocaleToKindMap() map[DimensionLocale]map[string]DimensionKind {
|
||||||
|
return map[DimensionLocale]map[string]DimensionKind{
|
||||||
|
DimensionLocalRU: {
|
||||||
|
"мм": DimensionKindMilimeter,
|
||||||
|
"см": DimensionKindCentimeter,
|
||||||
|
"м": DimensionKindMeter,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func getLocaleKindToStringMap() map[DimensionLocale]map[DimensionKind]string {
|
||||||
|
return map[DimensionLocale]map[DimensionKind]string{
|
||||||
|
DimensionLocalRU: {
|
||||||
|
DimensionKindMilimeter: "мм",
|
||||||
|
DimensionKindCentimeter: "см",
|
||||||
|
DimensionKindMeter: "м",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
31
internal/entity/dimension_inner_test.go
Normal file
31
internal/entity/dimension_inner_test.go
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
package entity
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestLocaleMap(t *testing.T) {
|
||||||
|
kindToStr := getLocaleKindToStringMap()
|
||||||
|
strToKind := getLocaleToKindMap()
|
||||||
|
|
||||||
|
assert := assert.New(t)
|
||||||
|
for locale := DimensionLocalUnspecified + 1; locale < dimensionLocalEnd; locale++ {
|
||||||
|
localeKinds, ok := kindToStr[locale]
|
||||||
|
assert.True(ok)
|
||||||
|
localeStrs, ok := strToKind[locale]
|
||||||
|
assert.True(ok)
|
||||||
|
|
||||||
|
assert.Equal(len(localeKinds), len(localeStrs))
|
||||||
|
|
||||||
|
for kindKey, kindValue := range localeKinds {
|
||||||
|
strKey := kindValue
|
||||||
|
strValue, ok := localeStrs[strKey]
|
||||||
|
assert.True(ok)
|
||||||
|
|
||||||
|
assert.Equal(kindKey, strValue)
|
||||||
|
assert.Equal(strKey, kindValue)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
72
internal/entity/dimension_test.go
Normal file
72
internal/entity/dimension_test.go
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
package entity_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"git.loyso.art/frx/eway/internal/entity"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestDimension_AdjustTo(t *testing.T) {
|
||||||
|
// Test adjusting from smaller dimension to larger one
|
||||||
|
d := entity.Dimension{Value: 5.0, Kind: entity.DimensionKindCentimeter}
|
||||||
|
expected := entity.Dimension{Value: 0.05, Kind: entity.DimensionKindMeter}
|
||||||
|
actual := d.AdjustTo(entity.DimensionKindMeter)
|
||||||
|
|
||||||
|
assert.EqualValues(t, expected.Value, actual.Value)
|
||||||
|
assert.Equal(t, expected.Kind, actual.Kind)
|
||||||
|
|
||||||
|
// Test adjusting from larger dimension to smaller one
|
||||||
|
d = entity.Dimension{Value: 0.05, Kind: entity.DimensionKindMeter}
|
||||||
|
expected = entity.Dimension{Value: 50.0, Kind: entity.DimensionKindMilimeter}
|
||||||
|
actual = d.AdjustTo(entity.DimensionKindMilimeter)
|
||||||
|
|
||||||
|
assert.EqualValues(t, expected.Value, actual.Value)
|
||||||
|
assert.Equal(t, expected.Kind, actual.Kind)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestParseDimension_Success(t *testing.T) {
|
||||||
|
// Test parsing a valid dimension string with RU locale
|
||||||
|
input := "10 см"
|
||||||
|
expected := entity.Dimension{Value: 10.0, Kind: entity.DimensionKindCentimeter}
|
||||||
|
|
||||||
|
actual, err := entity.ParseDimention(input, entity.DimensionLocalRU)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
assert.EqualValues(t, expected.Value, actual.Value)
|
||||||
|
assert.Equal(t, expected.Kind, actual.Kind)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestParseDimensionComplex_Success(t *testing.T) {
|
||||||
|
// Test parsing a valid dimension string with RU locale
|
||||||
|
input := "10 256.20 см"
|
||||||
|
expected := entity.Dimension{Value: 10256.20, Kind: entity.DimensionKindCentimeter}
|
||||||
|
|
||||||
|
actual, err := entity.ParseDimention(input, entity.DimensionLocalRU)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
assert.EqualValues(t, expected.Value, actual.Value)
|
||||||
|
assert.Equal(t, expected.Kind, actual.Kind)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestParseDimension_InvalidInputFormat(t *testing.T) {
|
||||||
|
// Test parsing an invalid dimension string with RU locale
|
||||||
|
input := "invalid value 2"
|
||||||
|
expectedErr := errors.New("expected 2 values after split for value invalid value 2")
|
||||||
|
|
||||||
|
_, err := entity.ParseDimention(input, entity.DimensionLocalRU)
|
||||||
|
assert.Error(t, err)
|
||||||
|
assert.EqualError(t, err, expectedErr.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestParseDimension_InvalidLocale(t *testing.T) {
|
||||||
|
// Test parsing a dimension string with an unsupported locale
|
||||||
|
input := "10 мм"
|
||||||
|
expectedErr := errors.New("unknown locale for parse")
|
||||||
|
|
||||||
|
_, err := entity.ParseDimention(input, 3) // An invalid locale value is used here for demonstration purposes
|
||||||
|
assert.EqualError(t, err, expectedErr.Error())
|
||||||
|
}
|
||||||
3
internal/entity/empty.go
Normal file
3
internal/entity/empty.go
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
package entity
|
||||||
|
|
||||||
|
type Empty struct{}
|
||||||
@ -8,6 +8,26 @@ import (
|
|||||||
"unicode"
|
"unicode"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type GoodsItemSize struct {
|
||||||
|
Width Dimension
|
||||||
|
Height Dimension
|
||||||
|
Length Dimension
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s GoodsItemSize) GetSum(kind DimensionKind) float64 {
|
||||||
|
var value float64
|
||||||
|
sum := func(ds ...Dimension) {
|
||||||
|
for _, d := range ds {
|
||||||
|
value += d.AdjustTo(kind).Value
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sum(s.Height, s.Length, s.Length)
|
||||||
|
|
||||||
|
return value
|
||||||
|
}
|
||||||
|
|
||||||
type GoodsItem struct {
|
type GoodsItem struct {
|
||||||
Articul string `json:"sku"`
|
Articul string `json:"sku"`
|
||||||
PhotoURLs []string `json:"photo"`
|
PhotoURLs []string `json:"photo"`
|
||||||
@ -22,6 +42,7 @@ type GoodsItem struct {
|
|||||||
TariffPrice float64 `json:"tariff_price"`
|
TariffPrice float64 `json:"tariff_price"`
|
||||||
Cart int64 `json:"cart"`
|
Cart int64 `json:"cart"`
|
||||||
Stock int `json:"stock"`
|
Stock int `json:"stock"`
|
||||||
|
Sizes GoodsItemSize `json:"sizes"`
|
||||||
Parameters map[string]string `json:"parameters"`
|
Parameters map[string]string `json:"parameters"`
|
||||||
CreatedAt time.Time `json:"created_at"`
|
CreatedAt time.Time `json:"created_at"`
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user