Skip to content

Commit 4f282f8

Browse files
authored
implement gateway for 17vin decoder (#284)
* implement gateway for 17vin decoder * decoding working with mmy * test, implement into decoding service
1 parent 9f642ad commit 4f282f8

12 files changed

Lines changed: 276 additions & 23 deletions

File tree

cmd/device-definitions-api/decode_vin.go

Lines changed: 25 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,9 @@ import (
55
"flag"
66
"fmt"
77

8+
"github.com/goccy/go-json"
9+
810
"github.com/DIMO-Network/device-definitions-api/internal/config"
9-
"github.com/DIMO-Network/device-definitions-api/internal/core/services"
1011
"github.com/DIMO-Network/device-definitions-api/internal/infrastructure/gateways"
1112
"github.com/google/subcommands"
1213
"github.com/rs/zerolog"
@@ -16,23 +17,25 @@ type decodeVINCmd struct {
1617
logger *zerolog.Logger
1718
settings *config.Settings
1819

19-
datGroup bool
20-
drivly bool
21-
vincario bool
20+
datGroup bool
21+
drivly bool
22+
vincario bool
23+
japan17vin bool
2224
}
2325

2426
func (*decodeVINCmd) Name() string { return "decodevin" }
2527
func (*decodeVINCmd) Synopsis() string {
2628
return "tries decoding a vin with chosen provider - does not insert in our db"
2729
}
2830
func (*decodeVINCmd) Usage() string {
29-
return `decodevin [-dat|-drivly|-vincario] <vin 17 chars> <country two letter iso>`
31+
return `decodevin [-dat|-drivly|-vincario|-japan17vin] <vin 17 chars> <country two letter iso>`
3032
}
3133

3234
func (p *decodeVINCmd) SetFlags(f *flag.FlagSet) {
3335
f.BoolVar(&p.datGroup, "dat", false, "use dat group vin decoder")
34-
f.BoolVar(&p.datGroup, "drivly", false, "use drivly vin decoder")
35-
f.BoolVar(&p.datGroup, "vincario", false, "use vincario vin decoder")
36+
f.BoolVar(&p.drivly, "drivly", false, "use drivly vin decoder")
37+
f.BoolVar(&p.vincario, "vincario", false, "use vincario vin decoder")
38+
f.BoolVar(&p.japan17vin, "japan17vin", false, "use japan17vin vin decoder")
3639
}
3740

3841
func (p *decodeVINCmd) Execute(_ context.Context, f *flag.FlagSet, _ ...interface{}) subcommands.ExitStatus {
@@ -41,11 +44,8 @@ func (p *decodeVINCmd) Execute(_ context.Context, f *flag.FlagSet, _ ...interfac
4144
return subcommands.ExitUsageError
4245
}
4346
vin := f.Args()[0]
44-
if !services.ValidateVIN(vin) {
45-
fmt.Println("invalid vin")
46-
return subcommands.ExitUsageError
47-
}
48-
country := "US"
47+
48+
country := "USA"
4949
if len(f.Args()) == 2 {
5050
country = f.Args()[1]
5151
}
@@ -83,6 +83,19 @@ func (p *decodeVINCmd) Execute(_ context.Context, f *flag.FlagSet, _ ...interfac
8383

8484
fmt.Printf("VIN Response: %+v\n", vinInfo)
8585
}
86+
if p.japan17vin {
87+
jp17vinAPI := gateways.NewJapan17VINAPI(p.logger, p.settings)
88+
vinInfo, payload, err := jp17vinAPI.GetVINInfo(vin)
89+
if err != nil {
90+
fmt.Println(err.Error())
91+
return subcommands.ExitFailure
92+
}
93+
jsonBytes, _ := json.MarshalIndent(vinInfo, "", " ")
94+
fmt.Println("VIN Info:")
95+
fmt.Println(string(jsonBytes))
96+
fmt.Println("Raw JSON Payload:")
97+
fmt.Println(string(payload))
98+
}
8699

87100
fmt.Println()
88101
return subcommands.ExitSuccess

go.mod

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ require (
1212
github.com/docker/go-connections v0.5.0
1313
github.com/ethereum/go-ethereum v1.14.7
1414
github.com/friendsofgo/errors v0.9.2
15+
github.com/goccy/go-json v0.10.2
1516
github.com/gofiber/adaptor/v2 v2.2.1
1617
github.com/gofiber/contrib/jwt v1.0.10
1718
github.com/gofiber/fiber/v2 v2.52.5
@@ -20,7 +21,6 @@ require (
2021
github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.1.0
2122
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0
2223
github.com/jarcoal/httpmock v1.1.0
23-
github.com/lib/pq v1.10.9
2424
github.com/mitchellh/mapstructure v1.5.0
2525
github.com/patrickmn/go-cache v2.1.0+incompatible
2626
github.com/pkg/errors v0.9.1
@@ -88,6 +88,7 @@ require (
8888
github.com/googleapis/gax-go/v2 v2.13.0 // indirect
8989
github.com/gorilla/websocket v1.5.3 // indirect
9090
github.com/holiman/uint256 v1.3.1 // indirect
91+
github.com/lib/pq v1.10.9 // indirect
9192
github.com/lufia/plan9stats v0.0.0-20240513124658-fba389f38bae // indirect
9293
github.com/mattn/go-colorable v0.1.13 // indirect
9394
github.com/mattn/go-isatty v0.0.20 // indirect

go.sum

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -327,6 +327,8 @@ github.com/go-redis/redis/v8 v8.11.5/go.mod h1:gREzHqY1hg6oD9ngVRbLStwAWKhA0FEgq
327327
github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
328328
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
329329
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
330+
github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU=
331+
github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
330332
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
331333
github.com/gofiber/adaptor/v2 v2.2.1 h1:givE7iViQWlsTR4Jh7tB4iXzrlKBgiraB/yTdHs9Lv4=
332334
github.com/gofiber/adaptor/v2 v2.2.1/go.mod h1:AhR16dEqs25W2FY/l8gSj1b51Azg5dtPDmm+pruNOrc=

internal/api/api.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ func Run(ctx context.Context, logger zerolog.Logger, settings *config.Settings,
5959
vincarioAPIService := gateways.NewVincarioAPIService(settings, &logger)
6060
fuelAPIService := gateways.NewFuelAPIService(settings, &logger)
6161
autoIsoAPIService := gateways.NewAutoIsoAPIService(settings.AutoIsoAPIUid, settings.AutoIsoAPIKey)
62+
japan17VINAPI := gateways.NewJapan17VINAPI(&logger, settings)
6263
registryInstance, err := contracts.NewRegistry(settings.EthereumRegistryAddress, ethClient)
6364
if err != nil {
6465
logger.Fatal().Err(err).Msg("Failed to create registry query instance.")
@@ -73,7 +74,7 @@ func Run(ctx context.Context, logger zerolog.Logger, settings *config.Settings,
7374
vinRepository := repositories.NewVINRepository(pdb.DBS, registryInstance)
7475

7576
//cache services
76-
vincDecodingService := services.NewVINDecodingService(drivlyAPIService, vincarioAPIService, autoIsoAPIService, &logger, ddOnChainService, datGroupWSService, pdb.DBS)
77+
vincDecodingService := services.NewVINDecodingService(drivlyAPIService, vincarioAPIService, autoIsoAPIService, &logger, ddOnChainService, datGroupWSService, pdb.DBS, japan17VINAPI)
7778
powerTrainTypeService, err := services.NewPowerTrainTypeService("powertrain_type_rule.yaml", &logger, ddOnChainService)
7879
searchService := search.NewTypesenseAPIService(settings, &logger)
7980
if err != nil {

internal/config/settings.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,8 @@ type Settings struct {
5151
IdentityAPIURL url.URL `yaml:"IDENTITY_API_URL"`
5252
PolygonScanAPIKey string `yaml:"POLYGON_SCAN_API_KEY"`
5353
GoogleSheetsCredentials string `yaml:"GOOGLE_SHEETS_CREDENTIALS"`
54+
Japan17VINUser string `yaml:"JAPAN17_VIN_USER"`
55+
Japan17VINPassword string `yaml:"JAPAN17_VIN_PASSWORD"`
5456
}
5557

5658
func (s *Settings) IsProd() bool {

internal/core/models/vin_decoding_models.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ const (
1818
DATGroupProvider DecodeProviderEnum = "dat"
1919
AllProviders DecodeProviderEnum = ""
2020
TeslaProvider DecodeProviderEnum = "tesla"
21+
Japan17VIN DecodeProviderEnum = "japan17vin"
2122
)
2223

2324
type VINDecodingInfoData struct {
@@ -403,3 +404,12 @@ type DATGroupEquipment struct {
403404
ManufacturerDescription string `json:"manufacturerDescription"`
404405
Description string `json:"description"`
405406
}
407+
408+
// nolint
409+
type Japan17MMY struct {
410+
VIN string `json:"vin"`
411+
ManufacturerName string `json:"manufacturerName"`
412+
ManufacturerLowerCase string `json:"manufacturerLowerCase"`
413+
ModelName string `json:"modelName"`
414+
Year int `json:"year"`
415+
}

internal/core/queries/decode_vin.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -204,7 +204,7 @@ func (dc DecodeVINQueryHandler) Handle(ctx context.Context, query mediator.Messa
204204
}
205205
// not a tesla, regular decode path
206206
if vinInfo == nil || vinInfo.Model == "" {
207-
vinInfo, err = dc.vinDecodingService.GetVIN(ctx, vin.String(), dt, coremodels.AllProviders, qry.Country) // this will try drivly first
207+
vinInfo, err = dc.vinDecodingService.GetVIN(ctx, vin.String(), dt, coremodels.AllProviders, qry.Country) // this will try drivly first unless of japan
208208
}
209209

210210
// if no luck decoding VIN, try buildingVinInfo from known data passed in, typically smartcar or software connections

internal/core/services/vin_decoding_service.go

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -32,19 +32,21 @@ type VINDecodingService interface {
3232
}
3333

3434
type vinDecodingService struct {
35+
logger *zerolog.Logger
3536
drivlyAPISvc gateways.DrivlyAPIService
3637
vincarioAPISvc gateways.VincarioAPIService
37-
logger *zerolog.Logger
3838
autoIsoAPIService gateways.AutoIsoAPIService
3939
DATGroupAPIService gateways.DATGroupAPIService
40+
japan17VINAPI gateways.Japan17VINAPI
4041
onChainSvc gateways.DeviceDefinitionOnChainService
4142
dbs func() *db.ReaderWriter
4243
}
4344

4445
func NewVINDecodingService(drivlyAPISvc gateways.DrivlyAPIService, vincarioAPISvc gateways.VincarioAPIService, autoIso gateways.AutoIsoAPIService, logger *zerolog.Logger,
45-
onChainSvc gateways.DeviceDefinitionOnChainService, datGroupAPIService gateways.DATGroupAPIService, dbs func() *db.ReaderWriter) VINDecodingService {
46-
return &vinDecodingService{drivlyAPISvc: drivlyAPISvc, vincarioAPISvc: vincarioAPISvc, autoIsoAPIService: autoIso, logger: logger,
47-
onChainSvc: onChainSvc, DATGroupAPIService: datGroupAPIService, dbs: dbs}
46+
onChainSvc gateways.DeviceDefinitionOnChainService, datGroupAPIService gateways.DATGroupAPIService, dbs func() *db.ReaderWriter,
47+
japan17VINAPI gateways.Japan17VINAPI) VINDecodingService {
48+
return &vinDecodingService{drivlyAPISvc: drivlyAPISvc, vincarioAPISvc: vincarioAPISvc, autoIsoAPIService: autoIso,
49+
japan17VINAPI: japan17VINAPI, logger: logger, onChainSvc: onChainSvc, DATGroupAPIService: datGroupAPIService, dbs: dbs}
4850
}
4951

5052
func (c vinDecodingService) GetVIN(ctx context.Context, vin string, dt *repoModel.DeviceType, provider coremodels.DecodeProviderEnum, country string) (*coremodels.VINDecodingInfoData, error) {
@@ -53,7 +55,10 @@ func (c vinDecodingService) GetVIN(ctx context.Context, vin string, dt *repoMode
5355

5456
result := &coremodels.VINDecodingInfoData{}
5557
vin = strings.ToUpper(strings.TrimSpace(vin))
56-
if !ValidateVIN(vin) {
58+
// check for japan chasis
59+
if (len(vin) < 17 && len(vin) > 10) || country == "JPN" {
60+
provider = coremodels.Japan17VIN
61+
} else if !ValidateVIN(vin) {
5762
return nil, fmt.Errorf("invalid vin: %s", vin)
5863
}
5964

@@ -105,6 +110,20 @@ func (c vinDecodingService) GetVIN(ctx context.Context, vin string, dt *repoMode
105110
if err != nil {
106111
return nil, err
107112
}
113+
case coremodels.Japan17VIN:
114+
mmy, raw, err := c.japan17VINAPI.GetVINInfo(vin)
115+
if err != nil {
116+
return nil, errors.Wrapf(err, "unable to decode vin: %s with japan17vin", vin)
117+
}
118+
result = &coremodels.VINDecodingInfoData{
119+
VIN: vin,
120+
Make: mmy.ManufacturerName,
121+
Model: mmy.ModelName,
122+
Year: int32(mmy.Year),
123+
Source: coremodels.Japan17VIN,
124+
MetaData: null.JSONFrom(raw),
125+
Raw: raw,
126+
}
108127
case coremodels.AutoIsoProvider:
109128
vinAutoIsoInfo, err := c.autoIsoAPIService.GetVIN(vin)
110129
if err != nil {

internal/core/services/vin_decoding_service_test.go

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,9 @@ type VINDecodingServiceSuite struct {
3232
mockVincarioAPISvc *mock_gateways.MockVincarioAPIService
3333
mockAutoIsoAPISvc *mock_gateways.MockAutoIsoAPIService
3434
mockDATGroupAPIService *mock_gateways.MockDATGroupAPIService
35-
mockOnChainSvc *mock_gateways.MockDeviceDefinitionOnChainService
35+
mockJapan17VINAPI *mock_gateways.MockJapan17VINAPI
3636

37+
mockOnChainSvc *mock_gateways.MockDeviceDefinitionOnChainService
3738
vinDecodingService VINDecodingService
3839
}
3940

@@ -58,10 +59,11 @@ func (s *VINDecodingServiceSuite) SetupTest() {
5859
s.mockAutoIsoAPISvc = mock_gateways.NewMockAutoIsoAPIService(s.ctrl)
5960
s.mockAutoIsoAPISvc = mock_gateways.NewMockAutoIsoAPIService(s.ctrl)
6061
s.mockDATGroupAPIService = mock_gateways.NewMockDATGroupAPIService(s.ctrl)
62+
s.mockJapan17VINAPI = mock_gateways.NewMockJapan17VINAPI(s.ctrl)
6163
s.mockOnChainSvc = mock_gateways.NewMockDeviceDefinitionOnChainService(s.ctrl)
6264

6365
s.vinDecodingService = NewVINDecodingService(s.mockDrivlyAPISvc, s.mockVincarioAPISvc, s.mockAutoIsoAPISvc, dbtesthelper.Logger(),
64-
s.mockOnChainSvc, s.mockDATGroupAPIService, s.pdb.DBS)
66+
s.mockOnChainSvc, s.mockDATGroupAPIService, s.pdb.DBS, s.mockJapan17VINAPI)
6567
}
6668

6769
func (s *VINDecodingServiceSuite) TearDownTest() {
@@ -76,6 +78,33 @@ func (s *VINDecodingServiceSuite) TearDownSuite() {
7678
}
7779
}
7880

81+
func (s *VINDecodingServiceSuite) Test_VINDecodingService_Japan17VIN_Success() {
82+
ctx := context.Background()
83+
const vin = "ZWR90-8000186"
84+
const makeID = "Toyota"
85+
const country = "CHN"
86+
87+
vinInfoResp := &coremodels.Japan17MMY{
88+
VIN: vin,
89+
ManufacturerName: makeID,
90+
ManufacturerLowerCase: "toyota",
91+
ModelName: "Voxy",
92+
Year: 2022,
93+
}
94+
s.mockJapan17VINAPI.EXPECT().GetVINInfo(vin).Times(1).Return(vinInfoResp, []byte{0x1, 0x22}, nil)
95+
96+
dt := dbtesthelper.SetupCreateDeviceType(s.T(), s.pdb)
97+
98+
result, err := s.vinDecodingService.GetVIN(ctx, vin, dt, coremodels.AllProviders, country)
99+
100+
s.NoError(err)
101+
assert.Equal(s.T(), result.VIN, vin)
102+
assert.Equal(s.T(), result.Source, coremodels.Japan17VIN)
103+
assert.Equal(s.T(), result.Make, "Toyota")
104+
assert.Equal(s.T(), result.Model, "Voxy")
105+
assert.Equal(s.T(), result.Year, int32(2022))
106+
}
107+
79108
func (s *VINDecodingServiceSuite) Test_VINDecodingService_Drivly_Success() {
80109
ctx := context.Background()
81110
const vin = "1FMCU0G61MUA52727" // ford escape 2021

0 commit comments

Comments
 (0)