diff --git a/internal/core/queries/decode_vin.go b/internal/core/queries/decode_vin.go index 3d4563b4..2d499889 100644 --- a/internal/core/queries/decode_vin.go +++ b/internal/core/queries/decode_vin.go @@ -490,18 +490,33 @@ func (dc DecodeVINQueryHandler) vinInfoFromKnown(vin vin.VIN, knownModel string, vinInfo.VIN = vin.String() wmis, err := models.Wmis(models.WmiWhere.Wmi.EQ(vin.Wmi())).All(context.Background(), dc.dbs().Reader) if err != nil { - return nil, errors.Wrap(err, "vinInfoFromKnown: could not get WMI from vin wmi "+vin.Wmi()) + return nil, errors.Wrap(err, "vinInfoFromKnown: unknown WMI "+vin.Wmi()) } if len(wmis) > 1 { - return nil, fmt.Errorf("vinInfoFromKnown: more than one WMI found for vin wmi %s", vin.Wmi()) + // see if we can find an existing device definition for this WMI + makeNamesForError := "" + for _, wmi := range wmis { + makeNamesForError += wmi.ManufacturerName + ", " + definitionID := common.DeviceDefinitionSlug(stringutils.SlugString(wmi.ManufacturerName), stringutils.SlugString(knownModel), int16(knownYear)) + deviceDefinitionTablelandModel, _, err := dc.deviceDefinitionOnChainService.GetDefinitionByID(context.Background(), definitionID) + if err == nil && deviceDefinitionTablelandModel != nil { + vinInfo.Make = wmi.ManufacturerName + break + } + } + // if make is blank means no matching DD's found. We don't have a good way to determine the right Make / OEM + if vinInfo.Make == "" { + return nil, fmt.Errorf("vinInfoFromKnown: unable to determine the right OEM between %sfor WMI %s", makeNamesForError, vin.Wmi()) + } + } else { + vinInfo.Make = wmis[0].ManufacturerName } - vinInfo.Make = wmis[0].ManufacturerName vinInfo.Year = knownYear vinInfo.Model = knownModel vinInfo.Source = "probably smartcar" if len(vinInfo.Model) == 0 || len(vinInfo.Make) == 0 || vinInfo.Year == 0 { - return nil, fmt.Errorf("unable to decode from known info") + return nil, fmt.Errorf("vinInfoFromKnown: unable to decode from known info") } return vinInfo, nil diff --git a/internal/core/queries/decode_vin_test.go b/internal/core/queries/decode_vin_test.go index feced071..631cb26a 100644 --- a/internal/core/queries/decode_vin_test.go +++ b/internal/core/queries/decode_vin_test.go @@ -947,3 +947,86 @@ func TestResolveMetadataFromInfo(t *testing.T) { func buildStyleName(vinInfo *coremodels.DrivlyVINResponse) string { return strings.TrimSpace(vinInfo.Trim + " " + vinInfo.SubModel) } + +func (s *DecodeVINQueryHandlerSuite) TestDecodeVINQueryHandler_vinInfoFromKnown_multipleWMI() { + vinny := "1FMCU0G61MUA52727" + v := vinutil.VIN(vinny) + // insert into wmi + wmi1 := models.Wmi{ + Wmi: "1FM", + ManufacturerName: "Ford", + } + wmi2 := models.Wmi{ + Wmi: "1FM", + ManufacturerName: "Lincoln", + } + err := wmi1.Insert(s.ctx, s.pdb.DBS().Writer, boil.Infer()) + require.NoError(s.T(), err) + err = wmi2.Insert(s.ctx, s.pdb.DBS().Writer, boil.Infer()) + require.NoError(s.T(), err) + // mock call to get definition by id + definitionID := "ford_escape_2020" + + s.mockDeviceDefinitionOnChainService.EXPECT().GetDefinitionByID(gomock.Any(), gomock.AnyOf("lincoln_escape_2020", definitionID)).AnyTimes().Return(&coremodels.DeviceDefinitionTablelandModel{ + ID: definitionID, + KSUID: ksuid.New().String(), + Model: "Escape", + Year: 2020, + DeviceType: common.DefaultDeviceType, + ImageURI: "", + Metadata: nil, + }, nil, nil) + //s.mockDeviceDefinitionOnChainService.EXPECT().GetDefinitionByID(gomock.Any(), "lincoln_escape_2020").AnyTimes().Return(nil, nil, fmt.Errorf("not found")) + + got, err := s.queryHandler.vinInfoFromKnown(v, "Escape", 2020) + require.NoError(s.T(), err) + assert.Equal(s.T(), "1FMCU0G61MUA52727", got.VIN) + assert.Equal(s.T(), "Ford", got.Make) + assert.Equal(s.T(), "Escape", got.Model) + assert.Equal(s.T(), int32(2020), got.Year) +} + +func (s *DecodeVINQueryHandlerSuite) TestDecodeVINQueryHandler_vinInfoFromKnown_singleWMI() { + vinny := "1FMCU0G61MUA52727" + v := vinutil.VIN(vinny) + // insert into wmi + wmi1 := models.Wmi{ + Wmi: "1FM", + ManufacturerName: "Ford", + } + + err := wmi1.Insert(s.ctx, s.pdb.DBS().Writer, boil.Infer()) + require.NoError(s.T(), err) + + got, err := s.queryHandler.vinInfoFromKnown(v, "Escape", 2020) + require.NoError(s.T(), err) + assert.Equal(s.T(), "1FMCU0G61MUA52727", got.VIN) + assert.Equal(s.T(), "Ford", got.Make) + assert.Equal(s.T(), "Escape", got.Model) + assert.Equal(s.T(), int32(2020), got.Year) +} + +func (s *DecodeVINQueryHandlerSuite) TestDecodeVINQueryHandler_vinInfoFromKnown_multipleWMINoDDFound() { + vinny := "1FMCU0G61MUA52727" + v := vinutil.VIN(vinny) + // insert into wmi + wmi1 := models.Wmi{ + Wmi: "1FM", + ManufacturerName: "Ford", + } + wmi2 := models.Wmi{ + Wmi: "1FM", + ManufacturerName: "Lincoln", + } + err := wmi1.Insert(s.ctx, s.pdb.DBS().Writer, boil.Infer()) + require.NoError(s.T(), err) + err = wmi2.Insert(s.ctx, s.pdb.DBS().Writer, boil.Infer()) + require.NoError(s.T(), err) + // mock call to get definition by id + definitionID := "ford_escape_2020" + s.mockDeviceDefinitionOnChainService.EXPECT().GetDefinitionByID(gomock.Any(), gomock.AnyOf("lincoln_escape_2020", definitionID)).Times(2).Return(nil, nil, fmt.Errorf("not found")) + + got, err := s.queryHandler.vinInfoFromKnown(v, "Escape", 2020) + require.Error(s.T(), err, "vinInfoFromKnown: unable to determine the right OEM between Ford, Lincoln for WMI %s 1FM") + require.Nil(s.T(), got) +}