Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions charts/device-definitions-api/templates/secret.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,12 @@ spec:
- remoteRef:
key: {{ .Release.Namespace }}/definitions/carvx/apikey
secretKey: CAR_VX_API_KEY
- remoteRef:
key: {{ .Release.Namespace }}/definitions/kaufmann/username
secretKey: ELEVA_USERNAME
- remoteRef:
key: {{ .Release.Namespace }}/definitions/kaufmann/password
secretKey: ELEVA_PASSWORD
secretStoreRef:
kind: ClusterSecretStore
name: aws-secretsmanager-secret-store
Expand Down
20 changes: 16 additions & 4 deletions cmd/device-definitions-api/decode_vin.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,14 +37,15 @@ type decodeVINCmd struct {
fromFile bool
persistToDB bool
carvx bool
eleva bool
}

func (*decodeVINCmd) Name() string { return "decodevin" }
func (*decodeVINCmd) Synopsis() string {
return "tries decoding a vin with chosen provider - does not insert in our db"
}
func (*decodeVINCmd) Usage() string {
return `decodevin [-dat|-drivly|-vincario|-japan17vin|carvx|-from-file] <vin 17 chars OR filaname in /tmp> <country two letter iso>`
return `decodevin [-dat|-drivly|-vincario|-japan17vin|-carvx|-eleva|-from-file] <vin 17 chars OR filaname in /tmp> <country three letter iso>`
}

func (p *decodeVINCmd) SetFlags(f *flag.FlagSet) {
Expand All @@ -53,6 +54,7 @@ func (p *decodeVINCmd) SetFlags(f *flag.FlagSet) {
f.BoolVar(&p.vincario, "vincario", false, "use vincario vin decoder")
f.BoolVar(&p.japan17vin, "japan17vin", false, "use japan17vin vin decoder")
f.BoolVar(&p.carvx, "carvx", false, "use carvx vin decoder")
f.BoolVar(&p.eleva, "eleva", false, "use eleva kaufmann vin decoder")
f.BoolVar(&p.fromFile, "from-file", false, "read vin from file in /tmp directory")
f.BoolVar(&p.persistToDB, "persist-to-db", false, "persist successful vin decodings to db, table vin_numbers")
}
Expand Down Expand Up @@ -160,6 +162,14 @@ func (p *decodeVINCmd) Execute(ctx context.Context, f *flag.FlagSet, _ ...interf
fmt.Println("VIN Info:")
fmt.Println(string(jsonBytes))
}
if p.eleva {
vinInfo, _, err = vinDecodingService.GetVIN(ctx, vin, coremodels.ElevaKaufmannProvider, country)
if err != nil {
fmt.Println(err.Error())
continue
}
fmt.Printf("VIN Response: \n %+v\n", vinInfo)
}
fmt.Println()
if p.persistToDB {
if vinInfo == nil || vinInfo.Model == "" {
Expand Down Expand Up @@ -250,6 +260,10 @@ func instantiateVINDecodingSvc(ctx context.Context, settings *config.Settings, l
vincarioAPI := gateways.NewVincarioAPIService(settings, logger)
jp17vinAPI := gateways.NewJapan17VINAPI(logger, settings)
carvxAPI := gateways.NewCarVxVINAPI(logger, settings)
elevaAPI := gateways.NewElevaAPI(settings)
if settings.Environment == "local" {
return services.NewVINDecodingService(drivlyAPI, vincarioAPI, nil, logger, nil, datAPI, pdb.DBS, jp17vinAPI, carvxAPI, elevaAPI)
}

send, err := createSender(ctx, settings, logger)
if err != nil {
Expand All @@ -267,7 +281,5 @@ func instantiateVINDecodingSvc(ctx context.Context, settings *config.Settings, l
}
deviceDefinitionOnChainService := gateways.NewDeviceDefinitionOnChainService(settings, logger, ethClient, chainID, send, pdb.DBS)

vinDecodingService := services.NewVINDecodingService(drivlyAPI, vincarioAPI, nil, logger, deviceDefinitionOnChainService, datAPI, pdb.DBS, jp17vinAPI, carvxAPI)

return vinDecodingService
return services.NewVINDecodingService(drivlyAPI, vincarioAPI, nil, logger, deviceDefinitionOnChainService, datAPI, pdb.DBS, jp17vinAPI, carvxAPI, elevaAPI)
}
3 changes: 2 additions & 1 deletion internal/api/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ func Run(ctx context.Context, logger zerolog.Logger, settings *config.Settings,
autoIsoAPIService := gateways.NewAutoIsoAPIService(settings.AutoIsoAPIUid, settings.AutoIsoAPIKey)
japan17VINAPI := gateways.NewJapan17VINAPI(&logger, settings)
carvxAPI := gateways.NewCarVxVINAPI(&logger, settings)
elevaAPI := gateways.NewElevaAPI(settings)
registryInstance, err := contracts.NewRegistry(settings.EthereumRegistryAddress, ethClient)
if err != nil {
logger.Fatal().Err(err).Msg("Failed to create registry query instance.")
Expand All @@ -75,7 +76,7 @@ func Run(ctx context.Context, logger zerolog.Logger, settings *config.Settings,
vinRepository := repositories.NewVINRepository(pdb.DBS, registryInstance, identityAPI)

//cache services
vincDecodingService := services.NewVINDecodingService(drivlyAPIService, vincarioAPIService, autoIsoAPIService, &logger, ddOnChainService, datGroupWSService, pdb.DBS, japan17VINAPI, carvxAPI)
vincDecodingService := services.NewVINDecodingService(drivlyAPIService, vincarioAPIService, autoIsoAPIService, &logger, ddOnChainService, datGroupWSService, pdb.DBS, japan17VINAPI, carvxAPI, elevaAPI)
powerTrainTypeService, err := services.NewPowerTrainTypeService("powertrain_type_rule.yaml", &logger, ddOnChainService)
searchService := search.NewTypesenseAPIService(settings, &logger)
if err != nil {
Expand Down
3 changes: 3 additions & 0 deletions internal/config/settings.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,9 @@ type Settings struct {
Japan17VINPassword string `yaml:"JAPAN17_VIN_PASSWORD"`
CarVxUserID string `yaml:"CAR_VX_USER_ID"`
CarVxAPIKey string `yaml:"CAR_VX_API_KEY"`
// used for Kaufmann API
ElevaUsername string `yaml:"ELEVA_USERNAME"`
ElevaPassword string `yaml:"ELEVA_PASSWORD"`
}

func (s *Settings) IsProd() bool {
Expand Down
42 changes: 34 additions & 8 deletions internal/core/models/vin_decoding_models.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,15 @@ import (
type DecodeProviderEnum string

const (
DrivlyProvider DecodeProviderEnum = "drivly"
VincarioProvider DecodeProviderEnum = "vincario"
AutoIsoProvider DecodeProviderEnum = "autoiso"
DATGroupProvider DecodeProviderEnum = "dat"
AllProviders DecodeProviderEnum = ""
TeslaProvider DecodeProviderEnum = "tesla"
Japan17VIN DecodeProviderEnum = "japan17vin"
CarVXVIN DecodeProviderEnum = "carvxvin"
DrivlyProvider DecodeProviderEnum = "drivly"
VincarioProvider DecodeProviderEnum = "vincario"
AutoIsoProvider DecodeProviderEnum = "autoiso"
DATGroupProvider DecodeProviderEnum = "dat"
AllProviders DecodeProviderEnum = ""
TeslaProvider DecodeProviderEnum = "tesla"
Japan17VIN DecodeProviderEnum = "japan17vin"
CarVXVIN DecodeProviderEnum = "carvxvin"
ElevaKaufmannProvider DecodeProviderEnum = "eleva"
)

type VINDecodingInfoData struct {
Expand Down Expand Up @@ -444,3 +445,28 @@ type CarVxResponse struct {
} `json:"data"`
Error string `json:"error"`
}

// nolint
type ElevaVINResponse struct {
Error int `json:"error"`
Message string `json:"message"`
Data struct {
Client struct {
Rut string `json:"rut"`
ClientId int `json:"clientId"`
Name string `json:"name"`
Lastname string `json:"lastname"`
Email string `json:"email"`
Phone string `json:"phone"`
BusinessName string `json:"businessName"`
} `json:"client"`
Vehicle struct {
Plate string `json:"plate"`
Chassis string `json:"chassis"`
Model string `json:"model"`
Kms int `json:"kms"`
Baumuster string `json:"baumuster"`
Brand string `json:"brand"`
} `json:"vehicle"`
} `json:"data"`
}
23 changes: 23 additions & 0 deletions internal/core/services/eleva_resp.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
{
"error": 0,
"message": "Success",
"data": {
"client": {
"rut": "12866851-9",
"clientId": 13,
"name": "MACARENA",
"lastname": "RAMOS ALERCE",
"email": "maxhoja@gmail.com",
"phone": "995339163",
"businessName": "MACARENA RAMOS ALERCE"
},
"vehicle": {
"plate": "SC-SS29",
"chassis": "W1K3F4GB9NN286196",
"model": "A 250",
"kms": 43879,
"baumuster": "177046",
"brand": "MERCEDES-BENZ"
}
}
}
56 changes: 53 additions & 3 deletions internal/core/services/vin_decoding_service.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"strconv"
"strings"
"time"
"unicode"

"github.com/DIMO-Network/shared/pkg/logfields"

Expand Down Expand Up @@ -37,15 +38,17 @@ type vinDecodingService struct {
DATGroupAPIService gateways.DATGroupAPIService
japan17VINAPI gateways.Japan17VINAPI
carvxAPI gateways.CarVxVINAPI
elevaAPI gateways.ElevaAPI
onChainSvc gateways.DeviceDefinitionOnChainService
dbs func() *db.ReaderWriter
}

func NewVINDecodingService(drivlyAPISvc gateways.DrivlyAPIService, vincarioAPISvc gateways.VincarioAPIService, autoIso gateways.AutoIsoAPIService, logger *zerolog.Logger,
onChainSvc gateways.DeviceDefinitionOnChainService, datGroupAPIService gateways.DATGroupAPIService, dbs func() *db.ReaderWriter,
japan17VINAPI gateways.Japan17VINAPI, carvxAPI gateways.CarVxVINAPI) VINDecodingService {
japan17VINAPI gateways.Japan17VINAPI, carvxAPI gateways.CarVxVINAPI, elevaAPI gateways.ElevaAPI) VINDecodingService {
return &vinDecodingService{drivlyAPISvc: drivlyAPISvc, vincarioAPISvc: vincarioAPISvc, autoIsoAPIService: autoIso,
japan17VINAPI: japan17VINAPI, carvxAPI: carvxAPI, logger: logger, onChainSvc: onChainSvc, DATGroupAPIService: datGroupAPIService, dbs: dbs}
japan17VINAPI: japan17VINAPI, carvxAPI: carvxAPI, logger: logger, onChainSvc: onChainSvc,
DATGroupAPIService: datGroupAPIService, dbs: dbs, elevaAPI: elevaAPI}
}

func (c vinDecodingService) GetVIN(ctx context.Context, vin string, provider coremodels.DecodeProviderEnum, country string) (*coremodels.VINDecodingInfoData, *coremodels.VINDecodingVendorExtra, error) {
Expand All @@ -56,7 +59,10 @@ func (c vinDecodingService) GetVIN(ctx context.Context, vin string, provider cor
vin = strings.ToUpper(strings.TrimSpace(vin))
providersToTry := make([]coremodels.DecodeProviderEnum, 0)
// check for japan chasis if all providers
if provider == coremodels.AllProviders && ((len(vin) < 17 && len(vin) > 10) || country == "JPN") {
if country == "CHL" {
providersToTry = append(providersToTry, coremodels.ElevaKaufmannProvider)
providersToTry = append(providersToTry, coremodels.VincarioProvider) // sometimes works in latam as backup
} else if provider == coremodels.AllProviders && ((len(vin) < 17 && len(vin) > 10) || country == "JPN") {
providersToTry = append(providersToTry, coremodels.CarVXVIN)
providersToTry = append(providersToTry, coremodels.Japan17VIN)
} else if !ValidateVIN(vin) {
Expand Down Expand Up @@ -227,6 +233,33 @@ func (c vinDecodingService) GetVIN(ctx context.Context, vin string, provider cor
continue
}
return result, resultVendorExtra, nil
case coremodels.ElevaKaufmannProvider:
resultVendorExtra.VendorsTried = append(resultVendorExtra.VendorsTried, string(coremodels.ElevaKaufmannProvider))
localLog.Info().Msgf("trying to decode VIN: %s with eleva", vin)

vinInfo, err := c.elevaAPI.GetVINInfo(vin)
if err != nil {
errFinal = errors.Wrapf(err, "unable to decode vin: %s with eleva", vin)
continue
}
vinObj := vinutil.VIN(vin)
yr := vinObj.Year()
if yr < 2018 {
yr = time.Now().Year() - 1
localLog.Info().Msgf("vin year is less than 2019 for eleva kaufmann, using %d instead", yr)
}

result = &coremodels.VINDecodingInfoData{
VIN: vin,
Make: titleCase(vinInfo.Data.Vehicle.Brand), // MERCEDES-BENZ to Mercedes-Benz
Model: vinInfo.Data.Vehicle.Model,
SubModel: "",
Year: int32(yr),
StyleName: "",
Source: coremodels.ElevaKaufmannProvider,
Raw: nil,
}
return result, resultVendorExtra, nil
case coremodels.AllProviders:
// this should never hit
errFinal = fmt.Errorf("all providers - invalid option reached")
Expand Down Expand Up @@ -395,3 +428,20 @@ func validateVinDecoding(vdi *coremodels.VINDecodingInfoData) error {

return nil
}

func titleCase(s string) string {
parts := strings.Split(s, "-")

for i, part := range parts {
if len(part) == 0 {
continue
}
part = strings.ToLower(part)

runes := []rune(part)
runes[0] = unicode.ToUpper(runes[0])

parts[i] = string(runes)
}
return strings.Join(parts, "-")
}
29 changes: 28 additions & 1 deletion internal/core/services/vin_decoding_service_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ type VINDecodingServiceSuite struct {

mockOnChainSvc *mock_gateways.MockDeviceDefinitionOnChainService
vinDecodingService VINDecodingService
mockElevaAPI *mock_gateways.MockElevaAPI
}

func TestVINDecodingService(t *testing.T) {
Expand All @@ -62,10 +63,11 @@ func (s *VINDecodingServiceSuite) SetupTest() {
s.mockDATGroupAPIService = mock_gateways.NewMockDATGroupAPIService(s.ctrl)
s.mockJapan17VINAPI = mock_gateways.NewMockJapan17VINAPI(s.ctrl)
s.mockCarvxAPI = mock_gateways.NewMockCarVxVINAPI(s.ctrl)
s.mockElevaAPI = mock_gateways.NewMockElevaAPI(s.ctrl)
s.mockOnChainSvc = mock_gateways.NewMockDeviceDefinitionOnChainService(s.ctrl)

s.vinDecodingService = NewVINDecodingService(s.mockDrivlyAPISvc, s.mockVincarioAPISvc, s.mockAutoIsoAPISvc, dbtesthelper.Logger(),
s.mockOnChainSvc, s.mockDATGroupAPIService, s.pdb.DBS, s.mockJapan17VINAPI, s.mockCarvxAPI)
s.mockOnChainSvc, s.mockDATGroupAPIService, s.pdb.DBS, s.mockJapan17VINAPI, s.mockCarvxAPI, s.mockElevaAPI)
}

func (s *VINDecodingServiceSuite) TearDownTest() {
Expand Down Expand Up @@ -108,6 +110,31 @@ func (s *VINDecodingServiceSuite) Test_VINDecodingService_Japan17VIN_Success() {
assert.Equal(s.T(), result.Year, int32(2022))
}

//go:embed eleva_resp.json
var elevaAPIResponse []byte

func (s *VINDecodingServiceSuite) Test_VINDecodingService_KaufmannEleva_Success() {
ctx := context.Background()
const vin = "W1K3F4GB9NN286196"
const country = "CHL" // chile only

vinInfoResp := &coremodels.ElevaVINResponse{}
err := json.Unmarshal(elevaAPIResponse, vinInfoResp)
require.NoError(s.T(), err)
s.mockElevaAPI.EXPECT().GetVINInfo(vin).Times(1).Return(vinInfoResp, nil)

_ = dbtesthelper.SetupCreateDeviceType(s.T(), s.pdb)

result, _, err := s.vinDecodingService.GetVIN(ctx, vin, coremodels.AllProviders, country)

s.NoError(err)
assert.Equal(s.T(), result.VIN, vin)
assert.Equal(s.T(), result.Source, coremodels.ElevaKaufmannProvider)
assert.Equal(s.T(), result.Make, "Mercedes-Benz")
assert.Equal(s.T(), result.Model, "A 250")
assert.Equal(s.T(), result.Year, int32(2022))
}

func (s *VINDecodingServiceSuite) Test_VINDecodingService_Drivly_Success() {
ctx := context.Background()
const vin = "1FMCU0G61MUA52727" // ford escape 2021
Expand Down
Loading
Loading