Initial cloud-services repo - gateway service + pkg modules

This commit is contained in:
Chris Rai
2026-01-30 23:14:52 -05:00
commit fbb820d7b3
1037 changed files with 171318 additions and 0 deletions

View File

@@ -0,0 +1,58 @@
package vehicleconfig
import (
"encoding/json"
"fmt"
"io"
"net/http"
"fiskerinc.com/modules/common"
"fiskerinc.com/modules/httpclient"
"fiskerinc.com/modules/logger"
"fiskerinc.com/modules/utils/envtool"
"github.com/pkg/errors"
)
func NewConfigService() ConfigServiceInterface {
return &ConfigService{
configURL: envtool.GetEnv("ODX_URL", "http://odx.prd.cec.internal:5000/api/v1/OdxService"),
}
}
type ConfigServiceInterface interface {
GetCDS(request common.VODCDSRequest) (map[string]string, error)
}
// ConfigService is currently a mock of the actual calls to the ODX parser services
type ConfigService struct {
configURL string
}
func (cs *ConfigService) GetCDS(request common.VODCDSRequest) (map[string]string, error) {
header := http.Header{}
header.Add("Content-Type", "application/json")
resp, err := httpclient.Post(cs.configURL+"/GetVodCDSCodingData", request, header)
if err != nil {
return nil, errors.WithStack(err)
}
if resp.StatusCode != http.StatusOK {
return nil, errors.WithStack(fmt.Errorf("calling ODX failed with status: %s", resp.Status))
}
defer resp.Body.Close()
respBody, err := io.ReadAll(resp.Body)
if err != nil {
return nil, errors.WithStack(err)
}
logger.Info().Msg(fmt.Sprintf("odx service has returned the next answer: %s", string(respBody)))
respPayload := map[string]string{}
err = json.Unmarshal(respBody, &respPayload)
if err != nil {
return nil, errors.WithStack(err)
}
return respPayload, nil
}

780
pkg/vehicleconfig/mocks.go Normal file
View File

@@ -0,0 +1,780 @@
package vehicleconfig
import "fiskerinc.com/modules/common"
var ecus = []string{"AGS",
"ADB",
"ADAS",
"ACU",
"ACP",
"AMP",
"AP_FL",
"AP_FR",
"AP_RL",
"AP_RR",
"AL",
"BCS",
"BMS",
"BMU",
"BCM",
"CDS",
"CCU",
"CIM",
"CVM",
"CFM",
"CMRR_FL",
"CMRR_FR",
"CMRR_RL",
"CMRR_RR",
"DVRC",
"DC-CHM",
"DMC",
"DSMC",
"DWSG",
"EPS",
"EAS",
"ECC",
"EWP_B",
"EWP_FD",
"EWP_H",
"EWP_RD",
"EWM",
"EXV_B",
"EXV_HP",
"ESP",
"FDHA_FL",
"FDHA_FR",
"FDHA_RL",
"FDHA_RR",
"Lumber",
"FBM_L",
"FBM_R",
"FVC",
"GW",
"HUD",
"IDS",
"ICC",
"IBS",
"iBooster",
"KS",
"LSC",
"MRR",
"MCU",
"MCU_F",
"MCU_R",
"MDV",
"MFS",
"MIS",
"MPC",
"OMC",
"OHC",
"PAS",
"PCU",
"PMS",
"PSM",
"PEPS",
"PKC",
"PKC_ANT_L",
"PKC_ANT_R",
"PWC_L",
"PWC_R",
"PVIU",
"PASC",
"PDU",
"PLGM",
"RLS",
"RAC",
"RVC",
"RSC",
"RCM",
"RSM",
"SCM",
"TBOX",
"TPMS",
"TDS",
"USB Box",
"VCU",
"VSP",
"WTC_B",
"WTC_H",
}
var vehicleOrder = `<VehicleOrderReplicate>
<HeaderArea>
<CreationDateTime>2022-05-27T12:49</CreationDateTime>
<MessageIdentifier>VEHICLEORDERSUBMISSION</MessageIdentifier>
<InterfaceId>8</InterfaceId>
<Sender>
<SourceSystem>FISKERSAP-DS4</SourceSystem>
<TargetSystem>SAM-DEV</TargetSystem>
</Sender>
</HeaderArea>
<DataArea>
<VehicleOrder>
<SpecId>800010200</SpecId>
<VehicleOrderNumber>8000102</VehicleOrderNumber>
<VehicleSpecification>
<OrderIndicator>S</OrderIndicator>
<FleetOrderIndicator>N</FleetOrderIndicator>
<ProductionPhaseIndicator>01</ProductionPhaseIndicator>
<VehicleIndicator>000</VehicleIndicator>
<ManufacturingPlant>G</ManufacturingPlant>
<ExpectedReferenceDate>2022-05-26</ExpectedReferenceDate>
<ModelType>FM29</ModelType>
<ModelYearIndicator>2023</ModelYearIndicator>
<VehicleModel>F29</VehicleModel>
<VinPrefix>VCF1ZBU2_PG</VinPrefix>
<VehicleFeatures>
<FeatureCodes>
<FamilyCode>0201</FamilyCode>
<FeatureCode>020102</FeatureCode>
</FeatureCodes>
<FeatureCodes>
<FamilyCode>0202</FamilyCode>
<FeatureCode>020201</FeatureCode>
</FeatureCodes>
<FeatureCodes>
<FamilyCode>0204</FamilyCode>
<FeatureCode>020402</FeatureCode>
</FeatureCodes>
<FeatureCodes>
<FamilyCode>0205</FamilyCode>
<FeatureCode>020501</FeatureCode>
</FeatureCodes>
<FeatureCodes>
<FamilyCode>0206</FamilyCode>
<FeatureCode>020601</FeatureCode>
</FeatureCodes>
<FeatureCodes>
<FamilyCode>0207</FamilyCode>
<FeatureCode>020701</FeatureCode>
</FeatureCodes>
<FeatureCodes>
<FamilyCode>0208</FamilyCode>
<FeatureCode>020801</FeatureCode>
</FeatureCodes>
<FeatureCodes>
<FamilyCode>0209</FamilyCode>
<FeatureCode>020901</FeatureCode>
</FeatureCodes>
<FeatureCodes>
<FamilyCode>0210</FamilyCode>
<FeatureCode>021001</FeatureCode>
</FeatureCodes>
<FeatureCodes>
<FamilyCode>0211</FamilyCode>
<FeatureCode>021101</FeatureCode>
</FeatureCodes>
<FeatureCodes>
<FamilyCode>0212</FamilyCode>
<FeatureCode>021201</FeatureCode>
</FeatureCodes>
<FeatureCodes>
<FamilyCode>0303</FamilyCode>
<FeatureCode>030301</FeatureCode>
</FeatureCodes>
<FeatureCodes>
<FamilyCode>0401</FamilyCode>
<FeatureCode>040101</FeatureCode>
</FeatureCodes>
<FeatureCodes>
<FamilyCode>0404</FamilyCode>
<FeatureCode>040401</FeatureCode>
</FeatureCodes>
<FeatureCodes>
<FamilyCode>0405</FamilyCode>
<FeatureCode>040501</FeatureCode>
</FeatureCodes>
<FeatureCodes>
<FamilyCode>0406</FamilyCode>
<FeatureCode>040601</FeatureCode>
</FeatureCodes>
<FeatureCodes>
<FamilyCode>0407</FamilyCode>
<FeatureCode>040701</FeatureCode>
</FeatureCodes>
<FeatureCodes>
<FamilyCode>0501</FamilyCode>
<FeatureCode>050103</FeatureCode>
</FeatureCodes>
<FeatureCodes>
<FamilyCode>0601</FamilyCode>
<FeatureCode>060101</FeatureCode>
</FeatureCodes>
<FeatureCodes>
<FamilyCode>0602</FamilyCode>
<FeatureCode>060201</FeatureCode>
</FeatureCodes>
<FeatureCodes>
<FamilyCode>0603</FamilyCode>
<FeatureCode>060302</FeatureCode>
</FeatureCodes>
<FeatureCodes>
<FamilyCode>0604</FamilyCode>
<FeatureCode>060401</FeatureCode>
</FeatureCodes>
<FeatureCodes>
<FamilyCode>0701</FamilyCode>
<FeatureCode>070102</FeatureCode>
</FeatureCodes>
<FeatureCodes>
<FamilyCode>0702</FamilyCode>
<FeatureCode>070202</FeatureCode>
</FeatureCodes>
<FeatureCodes>
<FamilyCode>0703</FamilyCode>
<FeatureCode>070302</FeatureCode>
</FeatureCodes>
<FeatureCodes>
<FamilyCode>1001</FamilyCode>
<FeatureCode>100101</FeatureCode>
</FeatureCodes>
<FeatureCodes>
<FamilyCode>1003</FamilyCode>
<FeatureCode>100301</FeatureCode>
</FeatureCodes>
<FeatureCodes>
<FamilyCode>1004</FamilyCode>
<FeatureCode>100401</FeatureCode>
</FeatureCodes>
<FeatureCodes>
<FamilyCode>1005</FamilyCode>
<FeatureCode>100501</FeatureCode>
</FeatureCodes>
<FeatureCodes>
<FamilyCode>1006</FamilyCode>
<FeatureCode>100601</FeatureCode>
</FeatureCodes>
<FeatureCodes>
<FamilyCode>1101</FamilyCode>
<FeatureCode>110103</FeatureCode>
</FeatureCodes>
<FeatureCodes>
<FamilyCode>1102</FamilyCode>
<FeatureCode>110201</FeatureCode>
</FeatureCodes>
<FeatureCodes>
<FamilyCode>1103</FamilyCode>
<FeatureCode>110301</FeatureCode>
</FeatureCodes>
<FeatureCodes>
<FamilyCode>1105</FamilyCode>
<FeatureCode>110501</FeatureCode>
</FeatureCodes>
<FeatureCodes>
<FamilyCode>1106</FamilyCode>
<FeatureCode>110601</FeatureCode>
</FeatureCodes>
<FeatureCodes>
<FamilyCode>1107</FamilyCode>
<FeatureCode>110701</FeatureCode>
</FeatureCodes>
<FeatureCodes>
<FamilyCode>1108</FamilyCode>
<FeatureCode>110801</FeatureCode>
</FeatureCodes>
<FeatureCodes>
<FamilyCode>1109</FamilyCode>
<FeatureCode>110901</FeatureCode>
</FeatureCodes>
<FeatureCodes>
<FamilyCode>1110</FamilyCode>
<FeatureCode>111001</FeatureCode>
</FeatureCodes>
<FeatureCodes>
<FamilyCode>1111</FamilyCode>
<FeatureCode>111101</FeatureCode>
</FeatureCodes>
<FeatureCodes>
<FamilyCode>1112</FamilyCode>
<FeatureCode>111201</FeatureCode>
</FeatureCodes>
<FeatureCodes>
<FamilyCode>1113</FamilyCode>
<FeatureCode>111301</FeatureCode>
</FeatureCodes>
<FeatureCodes>
<FamilyCode>1114</FamilyCode>
<FeatureCode>111401</FeatureCode>
</FeatureCodes>
<FeatureCodes>
<FamilyCode>1115</FamilyCode>
<FeatureCode>111501</FeatureCode>
</FeatureCodes>
<FeatureCodes>
<FamilyCode>1116</FamilyCode>
<FeatureCode>111601</FeatureCode>
</FeatureCodes>
<FeatureCodes>
<FamilyCode>1117</FamilyCode>
<FeatureCode>111701</FeatureCode>
</FeatureCodes>
<FeatureCodes>
<FamilyCode>1118</FamilyCode>
<FeatureCode>111801</FeatureCode>
</FeatureCodes>
<FeatureCodes>
<FamilyCode>1119</FamilyCode>
<FeatureCode>111901</FeatureCode>
</FeatureCodes>
<FeatureCodes>
<FamilyCode>1120</FamilyCode>
<FeatureCode>112001</FeatureCode>
</FeatureCodes>
<FeatureCodes>
<FamilyCode>1121</FamilyCode>
<FeatureCode>112101</FeatureCode>
</FeatureCodes>
<FeatureCodes>
<FamilyCode>1122</FamilyCode>
<FeatureCode>112201</FeatureCode>
</FeatureCodes>
<FeatureCodes>
<FamilyCode>1123</FamilyCode>
<FeatureCode>112301</FeatureCode>
</FeatureCodes>
<FeatureCodes>
<FamilyCode>1125</FamilyCode>
<FeatureCode>112502</FeatureCode>
</FeatureCodes>
<FeatureCodes>
<FamilyCode>1126</FamilyCode>
<FeatureCode>112601</FeatureCode>
</FeatureCodes>
<FeatureCodes>
<FamilyCode>1127</FamilyCode>
<FeatureCode>112701</FeatureCode>
</FeatureCodes>
<FeatureCodes>
<FamilyCode>1128</FamilyCode>
<FeatureCode>112801</FeatureCode>
</FeatureCodes>
<FeatureCodes>
<FamilyCode>1129</FamilyCode>
<FeatureCode>112901</FeatureCode>
</FeatureCodes>
<FeatureCodes>
<FamilyCode>1130</FamilyCode>
<FeatureCode>113001</FeatureCode>
</FeatureCodes>
<FeatureCodes>
<FamilyCode>1131</FamilyCode>
<FeatureCode>113101</FeatureCode>
</FeatureCodes>
<FeatureCodes>
<FamilyCode>1201</FamilyCode>
<FeatureCode>120101</FeatureCode>
</FeatureCodes>
<FeatureCodes>
<FamilyCode>1202</FamilyCode>
<FeatureCode>120202</FeatureCode>
</FeatureCodes>
<FeatureCodes>
<FamilyCode>1203</FamilyCode>
<FeatureCode>120302</FeatureCode>
</FeatureCodes>
<FeatureCodes>
<FamilyCode>1206</FamilyCode>
<FeatureCode>120603</FeatureCode>
</FeatureCodes>
<FeatureCodes>
<FamilyCode>1207</FamilyCode>
<FeatureCode>120702</FeatureCode>
</FeatureCodes>
<FeatureCodes>
<FamilyCode>1208</FamilyCode>
<FeatureCode>120802</FeatureCode>
</FeatureCodes>
<FeatureCodes>
<FamilyCode>1209</FamilyCode>
<FeatureCode>120901</FeatureCode>
</FeatureCodes>
<FeatureCodes>
<FamilyCode>1210</FamilyCode>
<FeatureCode>121001</FeatureCode>
</FeatureCodes>
<FeatureCodes>
<FamilyCode>1211</FamilyCode>
<FeatureCode>121101</FeatureCode>
</FeatureCodes>
<FeatureCodes>
<FamilyCode>1213</FamilyCode>
<FeatureCode>121302</FeatureCode>
</FeatureCodes>
<FeatureCodes>
<FamilyCode>1301</FamilyCode>
<FeatureCode>130101</FeatureCode>
</FeatureCodes>
<FeatureCodes>
<FamilyCode>1401</FamilyCode>
<FeatureCode>140101</FeatureCode>
</FeatureCodes>
<FeatureCodes>
<FamilyCode>1402</FamilyCode>
<FeatureCode>140201</FeatureCode>
</FeatureCodes>
<FeatureCodes>
<FamilyCode>1403</FamilyCode>
<FeatureCode>140301</FeatureCode>
</FeatureCodes>
<FeatureCodes>
<FamilyCode>1404</FamilyCode>
<FeatureCode>140401</FeatureCode>
</FeatureCodes>
<FeatureCodes>
<FamilyCode>1405</FamilyCode>
<FeatureCode>140501</FeatureCode>
</FeatureCodes>
<FeatureCodes>
<FamilyCode>1406</FamilyCode>
<FeatureCode>140601</FeatureCode>
</FeatureCodes>
<FeatureCodes>
<FamilyCode>1407</FamilyCode>
<FeatureCode>140701</FeatureCode>
</FeatureCodes>
<FeatureCodes>
<FamilyCode>1408</FamilyCode>
<FeatureCode>140801</FeatureCode>
</FeatureCodes>
<FeatureCodes>
<FamilyCode>1409</FamilyCode>
<FeatureCode>140901</FeatureCode>
</FeatureCodes>
<FeatureCodes>
<FamilyCode>1602</FamilyCode>
<FeatureCode>160201</FeatureCode>
</FeatureCodes>
<FeatureCodes>
<FamilyCode>1603</FamilyCode>
<FeatureCode>160301</FeatureCode>
</FeatureCodes>
<FeatureCodes>
<FamilyCode>1604</FamilyCode>
<FeatureCode>160401</FeatureCode>
</FeatureCodes>
<FeatureCodes>
<FamilyCode>1605</FamilyCode>
<FeatureCode>160502</FeatureCode>
</FeatureCodes>
<FeatureCodes>
<FamilyCode>1606</FamilyCode>
<FeatureCode>160601</FeatureCode>
</FeatureCodes>
<FeatureCodes>
<FamilyCode>1607</FamilyCode>
<FeatureCode>160701</FeatureCode>
</FeatureCodes>
<FeatureCodes>
<FamilyCode>1702</FamilyCode>
<FeatureCode>170201</FeatureCode>
</FeatureCodes>
<FeatureCodes>
<FamilyCode>1703</FamilyCode>
<FeatureCode>170301</FeatureCode>
</FeatureCodes>
<FeatureCodes>
<FamilyCode>1801</FamilyCode>
<FeatureCode>180102</FeatureCode>
</FeatureCodes>
<FeatureCodes>
<FamilyCode>1802</FamilyCode>
<FeatureCode>180201</FeatureCode>
</FeatureCodes>
<FeatureCodes>
<FamilyCode>1803</FamilyCode>
<FeatureCode>180301</FeatureCode>
</FeatureCodes>
<FeatureCodes>
<FamilyCode>1804</FamilyCode>
<FeatureCode>180401</FeatureCode>
</FeatureCodes>
<FeatureCodes>
<FamilyCode>1805</FamilyCode>
<FeatureCode>180501</FeatureCode>
</FeatureCodes>
<FeatureCodes>
<FamilyCode>1806</FamilyCode>
<FeatureCode>180601</FeatureCode>
</FeatureCodes>
<FeatureCodes>
<FamilyCode>1807</FamilyCode>
<FeatureCode>180701</FeatureCode>
</FeatureCodes>
<FeatureCodes>
<FamilyCode>1809</FamilyCode>
<FeatureCode>180901</FeatureCode>
</FeatureCodes>
<FeatureCodes>
<FamilyCode>1810</FamilyCode>
<FeatureCode>181001</FeatureCode>
</FeatureCodes>
<FeatureCodes>
<FamilyCode>1812</FamilyCode>
<FeatureCode>181201</FeatureCode>
</FeatureCodes>
<FeatureCodes>
<FamilyCode>1813</FamilyCode>
<FeatureCode>181301</FeatureCode>
</FeatureCodes>
<FeatureCodes>
<FamilyCode>1814</FamilyCode>
<FeatureCode>181401</FeatureCode>
</FeatureCodes>
<FeatureCodes>
<FamilyCode>1819</FamilyCode>
<FeatureCode>181901</FeatureCode>
</FeatureCodes>
<FeatureCodes>
<FamilyCode>1820</FamilyCode>
<FeatureCode>182001</FeatureCode>
</FeatureCodes>
<FeatureCodes>
<FamilyCode>1821</FamilyCode>
<FeatureCode>182101</FeatureCode>
</FeatureCodes>
<FeatureCodes>
<FamilyCode>1822</FamilyCode>
<FeatureCode>182201</FeatureCode>
</FeatureCodes>
<FeatureCodes>
<FamilyCode>1823</FamilyCode>
<FeatureCode>182301</FeatureCode>
</FeatureCodes>
<FeatureCodes>
<FamilyCode>1824</FamilyCode>
<FeatureCode>182401</FeatureCode>
</FeatureCodes>
<FeatureCodes>
<FamilyCode>1825</FamilyCode>
<FeatureCode>182501</FeatureCode>
</FeatureCodes>
<FeatureCodes>
<FamilyCode>1826</FamilyCode>
<FeatureCode>182601</FeatureCode>
</FeatureCodes>
<FeatureCodes>
<FamilyCode>1827</FamilyCode>
<FeatureCode>182701</FeatureCode>
</FeatureCodes>
<FeatureCodes>
<FamilyCode>1828</FamilyCode>
<FeatureCode>182801</FeatureCode>
</FeatureCodes>
<FeatureCodes>
<FamilyCode>1901</FamilyCode>
<FeatureCode>190101</FeatureCode>
</FeatureCodes>
<FeatureCodes>
<FamilyCode>1902</FamilyCode>
<FeatureCode>190202</FeatureCode>
</FeatureCodes>
<FeatureCodes>
<FamilyCode>1903</FamilyCode>
<FeatureCode>190301</FeatureCode>
</FeatureCodes>
<FeatureCodes>
<FamilyCode>2101</FamilyCode>
<FeatureCode>210102</FeatureCode>
</FeatureCodes>
<FeatureCodes>
<FamilyCode>2103</FamilyCode>
<FeatureCode>210302</FeatureCode>
</FeatureCodes>
<FeatureCodes>
<FamilyCode>2104</FamilyCode>
<FeatureCode>210402</FeatureCode>
</FeatureCodes>
<FeatureCodes>
<FamilyCode>2105</FamilyCode>
<FeatureCode>210501</FeatureCode>
</FeatureCodes>
<FeatureCodes>
<FamilyCode>2106</FamilyCode>
<FeatureCode>210601</FeatureCode>
</FeatureCodes>
<FeatureCodes>
<FamilyCode>2108</FamilyCode>
<FeatureCode>210801</FeatureCode>
</FeatureCodes>
<FeatureCodes>
<FamilyCode>2109</FamilyCode>
<FeatureCode>210901</FeatureCode>
</FeatureCodes>
<FeatureCodes>
<FamilyCode>2110</FamilyCode>
<FeatureCode>211001</FeatureCode>
</FeatureCodes>
<FeatureCodes>
<FamilyCode>2111</FamilyCode>
<FeatureCode>211100</FeatureCode>
</FeatureCodes>
<FeatureCodes>
<FamilyCode>2113</FamilyCode>
<FeatureCode>211301</FeatureCode>
</FeatureCodes>
<FeatureCodes>
<FamilyCode>2114</FamilyCode>
<FeatureCode>211401</FeatureCode>
</FeatureCodes>
<FeatureCodes>
<FamilyCode>2201</FamilyCode>
<FeatureCode>220102</FeatureCode>
</FeatureCodes>
<FeatureCodes>
<FamilyCode>2202</FamilyCode>
<FeatureCode>220202</FeatureCode>
</FeatureCodes>
<FeatureCodes>
<FamilyCode>2203</FamilyCode>
<FeatureCode>220302</FeatureCode>
</FeatureCodes>
<FeatureCodes>
<FamilyCode>2204</FamilyCode>
<FeatureCode>220401</FeatureCode>
</FeatureCodes>
<FeatureCodes>
<FamilyCode>2401</FamilyCode>
<FeatureCode>240101</FeatureCode>
</FeatureCodes>
<FeatureCodes>
<FamilyCode>2402</FamilyCode>
<FeatureCode>240203</FeatureCode>
</FeatureCodes>
<FeatureCodes>
<FamilyCode>2404</FamilyCode>
<FeatureCode>240401</FeatureCode>
</FeatureCodes>
<FeatureCodes>
<FamilyCode>2405</FamilyCode>
<FeatureCode>240502</FeatureCode>
</FeatureCodes>
<FeatureCodes>
<FamilyCode>2406</FamilyCode>
<FeatureCode>240601</FeatureCode>
</FeatureCodes>
<FeatureCodes>
<FamilyCode>2407</FamilyCode>
<FeatureCode>240701</FeatureCode>
</FeatureCodes>
<FeatureCodes>
<FamilyCode>2408</FamilyCode>
<FeatureCode>240801</FeatureCode>
</FeatureCodes>
<FeatureCodes>
<FamilyCode>2410</FamilyCode>
<FeatureCode>241001</FeatureCode>
</FeatureCodes>
<FeatureCodes>
<FamilyCode>2411</FamilyCode>
<FeatureCode>241101</FeatureCode>
</FeatureCodes>
<FeatureCodes>
<FamilyCode>2412</FamilyCode>
<FeatureCode>241201</FeatureCode>
</FeatureCodes>
<FeatureCodes>
<FamilyCode>2413</FamilyCode>
<FeatureCode>241300</FeatureCode>
</FeatureCodes>
<FeatureCodes>
<FamilyCode>2414</FamilyCode>
<FeatureCode>241401</FeatureCode>
</FeatureCodes>
<FeatureCodes>
<FamilyCode>2501</FamilyCode>
<FeatureCode>250101</FeatureCode>
</FeatureCodes>
<FeatureCodes>
<FamilyCode>2502</FamilyCode>
<FeatureCode>250201</FeatureCode>
</FeatureCodes>
<FeatureCodes>
<FamilyCode>2601</FamilyCode>
<FeatureCode>260102</FeatureCode>
</FeatureCodes>
<FeatureCodes>
<FamilyCode>2603</FamilyCode>
<FeatureCode>260301</FeatureCode>
</FeatureCodes>
<FeatureCodes>
<FamilyCode>2801</FamilyCode>
<FeatureCode>280102</FeatureCode>
</FeatureCodes>
<FeatureCodes>
<FamilyCode>2804</FamilyCode>
<FeatureCode>280401</FeatureCode>
</FeatureCodes>
<FeatureCodes>
<FamilyCode>2805</FamilyCode>
<FeatureCode>280501</FeatureCode>
</FeatureCodes>
<FeatureCodes>
<FamilyCode>2806</FamilyCode>
<FeatureCode>280601</FeatureCode>
</FeatureCodes>
<FeatureCodes>
<FamilyCode>2807</FamilyCode>
<FeatureCode>280701</FeatureCode>
</FeatureCodes>
<FeatureCodes>
<FamilyCode>2901</FamilyCode>
<FeatureCode>290101</FeatureCode>
</FeatureCodes>
<FeatureCodes>
<FamilyCode>3002</FamilyCode>
<FeatureCode>300201</FeatureCode>
</FeatureCodes>
<FeatureCodes>
<FamilyCode>3003</FamilyCode>
<FeatureCode>300301</FeatureCode>
</FeatureCodes>
<FeatureCodes>
<FamilyCode>3201</FamilyCode>
<FeatureCode>320101</FeatureCode>
</FeatureCodes>
</VehicleFeatures>
</VehicleSpecification>
</VehicleOrder>
</DataArea>
</VehicleOrderReplicate>`
type ConfigMock struct {
GetVODCDSCodingDataMock func(request common.VODCDSRequest) (map[string]string, error)
}
func (m ConfigMock) GetCDS(request common.VODCDSRequest) (map[string]string, error) {
return m.GetVODCDSCodingDataMock(request)
}
type SAPServiceMock struct {
GetSAPOrderMock func(vin string) (order common.VehicleOrder, err error)
GetECUVersionsMock func(vin string) (versions map[string]string, err error)
UpdateECUVersionsMock func(vin string, versions map[string]string) (err error)
GetConfigurationMock func(vin string) (common.SAPResponse, error)
SubmitResultMock func(vin string, success bool) (err error)
}
func (s SAPServiceMock) GetSAPOrder(vin string) (order common.VehicleOrder, err error) {
return s.GetSAPOrderMock(vin)
}
func (s SAPServiceMock) GetECUVersions(vin string) (versions map[string]string, err error) {
return s.GetECUVersionsMock(vin)
}
func (s SAPServiceMock) UpdateECUVersions(vin string, versions map[string]string) (err error) {
return s.UpdateECUVersionsMock(vin, versions)
}
func (s SAPServiceMock) GetFeatureCodes(vin string) (common.SAPResponse, error) {
return s.GetConfigurationMock(vin)
}
func (s SAPServiceMock) SubmitResult(vin string, success bool) (err error) {
return nil
}
func (s SAPServiceMock) SubmitCarFlashpackVersion(vin string, previousFlashpack string, flashpack string) error {
return nil
}

211
pkg/vehicleconfig/sap.go Normal file
View File

@@ -0,0 +1,211 @@
package vehicleconfig
import (
"bytes"
"crypto/tls"
"encoding/base64"
"encoding/json"
"encoding/xml"
"fmt"
"io"
"net/http"
"time"
"github.com/pkg/errors"
"fiskerinc.com/modules/common"
"fiskerinc.com/modules/common/staticerrors"
"fiskerinc.com/modules/logger"
"fiskerinc.com/modules/utils/envtool"
)
func NewSAPService() SAPServiceInterface {
return &SAPService{
sapUser: envtool.GetEnv("SAP_USER", "REPLACE_ME"),
sapPass: envtool.GetEnv("SAP_PASS", "REPLACE_ME"),
sapURL: envtool.GetEnv("SAP_URL", "REPLACE_ME"),
}
}
type SAPServiceInterface interface {
GetSAPOrder(vin string) (order common.VehicleOrder, err error)
GetECUVersions(vin string) (versions map[string]string, err error)
UpdateECUVersions(vin string, versions map[string]string) (err error)
GetFeatureCodes(vin string) (common.SAPResponse, error)
SubmitResult(vin string, success bool) (err error)
SubmitCarFlashpackVersion(vin string, previousFlashpack string, flashpack string) error
}
// This is currently a mock of the actual calls to the SAP and the ODX parser services
type SAPService struct {
sapUser string
sapPass string
sapURL string
}
type SAPSubmitResultBody struct {
VIN string `json:"vin" validate:"required,vin"`
DateTime string `json:"dateTime"`
Flag string `json:"flag"`
}
type SAPSubmitCarFlashpackVersionBody struct {
VIN string `json:"vin" validate:"required,vin"`
CreatedOn string `json:"createdOn"`
CurrentSWV string `json:"currentSWV"`
PreviousSWV string `json:"previousSWV"`
ModeOfSWU string `json:"modeOfSWU"`
}
// Returns the current vehicle order from SAP
func (cs *SAPService) GetSAPOrder(vin string) (order common.VehicleOrder, err error) {
var result common.OrderUpdated
err = xml.Unmarshal([]byte(vehicleOrder), &result)
if err != nil {
return
}
order = result.VehicleOrder
return
}
// Returns the current ECU versions for a car
func (cs *SAPService) GetECUVersions(vin string) (versions map[string]string, err error) {
versions = map[string]string{}
for _, ecu := range ecus {
versions[ecu] = "10000"
}
return
}
// Submits the updated ECU versions for a car back to SAP
func (cs *SAPService) UpdateECUVersions(vin string, versions map[string]string) (err error) {
return
}
func (cs *SAPService) GetFeatureCodes(vin string) (common.SAPResponse, error) {
headers := http.Header{}
headers.Add("Authorization", cs.createToken())
url := fmt.Sprintf("%s/vehicleSpec?vin=%s", cs.sapURL, vin)
request, err := http.NewRequest(http.MethodGet, url, nil)
if err != nil {
return common.SAPResponse{}, errors.WithStack(err)
}
client := createHttpClient()
request.Header = headers
resp, err := client.Do(request)
if err != nil {
return common.SAPResponse{}, errors.WithStack(err)
}
if resp.StatusCode != http.StatusOK {
return common.SAPResponse{}, errors.WithStack(fmt.Errorf(staticerrors.ErrorSAPFailedCall+" with status: %s", resp.Status))
}
defer resp.Body.Close()
respBody, err := io.ReadAll(resp.Body)
if err != nil {
return common.SAPResponse{}, errors.WithStack(err)
}
respPayload := common.SAPResponse{}
err = json.Unmarshal(respBody, &respPayload)
if err != nil {
return common.SAPResponse{}, errors.WithStack(err)
}
return respPayload, nil
}
func (cs *SAPService) SubmitResult(vin string, success bool) (err error) {
headers := http.Header{}
headers.Add("Authorization", cs.createToken())
headers.Add("Content-Type", "application/json")
timeNow := time.Now()
formattedTime := timeNow.Format("2006-01-02T15:04:05")
body := &SAPSubmitResultBody{
VIN: vin,
DateTime: formattedTime,
Flag: "not completed",
}
if success {
body.Flag = "completed"
}
bodyJSON, err := json.Marshal(body)
if err != nil {
return errors.WithStack(err)
}
return cs.submit("vehicleSpecAck", bodyJSON, http.StatusOK)
}
func (cs *SAPService) SubmitCarFlashpackVersion(vin string, previousFlashpack string, flashpack string) error {
timeNow := time.Now()
formattedTime := timeNow.Format("2006-01-02T15:04:05.999999Z")
body := &SAPSubmitCarFlashpackVersionBody{
VIN: vin,
CreatedOn: formattedTime,
PreviousSWV: previousFlashpack,
CurrentSWV: flashpack,
ModeOfSWU: "OTA",
}
bodyJSON, err := json.Marshal(body)
if err != nil {
return errors.WithStack(err)
}
return cs.submit("swVersionUpdate", bodyJSON, http.StatusCreated)
}
func (cs *SAPService) submit(endpoint string, bodyJSON []byte, successStatus int) error {
headers := http.Header{}
headers.Add("Authorization", cs.createToken())
headers.Add("Content-Type", "application/json")
url := fmt.Sprintf("%s/%s", cs.sapURL, endpoint)
request, err := http.NewRequest(http.MethodPost, url, bytes.NewBuffer(bodyJSON))
if err != nil {
return errors.WithStack(err)
}
client := createHttpClient()
request.Header = headers
resp, err := client.Do(request)
if err != nil {
return errors.WithStack(err)
}
if resp.StatusCode != successStatus {
return errors.WithStack(fmt.Errorf(staticerrors.ErrorSAPFailedCall+" with status: %s and payload: %s", resp.Status, string(bodyJSON)))
}
defer resp.Body.Close()
respBody, err := io.ReadAll(resp.Body)
if err != nil {
return errors.WithStack(err)
}
logger.Info().Msg(fmt.Sprintf("sap service has been notified at %s of car update: %s", endpoint, string(respBody)))
return nil
}
func (cs *SAPService) createToken() string {
token := base64.StdEncoding.EncodeToString([]byte(cs.sapUser + ":" + cs.sapPass))
return fmt.Sprintf("Basic %s", token)
}
func createHttpClient() http.Client {
transport := http.DefaultTransport.(*http.Transport)
transport.TLSClientConfig = &tls.Config{InsecureSkipVerify: true}
return http.Client{
Transport: transport,
}
}

View File

@@ -0,0 +1,188 @@
package vehicleconfig
import (
"encoding/csv"
"encoding/json"
"log"
"os"
"slices"
"testing"
)
/*
1 - Create a directory here: /vin_lists
2 - In that directory place CSV files that consist of newline-delimited lists of VINs.
These can be generated by PGAdmin. Just remove the quotes around each VIN.
cec_prd_vins.csv
cec_euprd_vins.csv
preprod_vins.csv
dev_vins.csv
3 - Remove t.Skip() from the desired test below.
4 - Run the test and wait. It will take several hours.
*/
type VinSAPData struct {
vin string
configData string
}
func TestGetSAPDataProd(t *testing.T) {
t.Skip()
t.Setenv("SAP_URL", "https://tpapi.fiskerinc.com/connected-car-mule")
t.Setenv("SAP_VEHICLESPEC_API_KEY", "3d5c948d-9bcc-47cf-ab7d-800f8ff4236c")
//
// For all NA prod vins
//
naVinsFile, err := os.Open("vin_lists/cec_prd_vins.csv")
if err != nil {
log.Fatal(err)
}
defer naVinsFile.Close()
allNAVins, err := csv.NewReader(naVinsFile).ReadAll()
if err != nil {
log.Fatalln("csv failed", err)
}
allNAVinsSlice := slices.Concat(allNAVins...)
naOutFile, err := os.Create("all_cec_prd_config_data.csv")
if err != nil {
log.Fatalln("failed to open file", err)
}
defer naOutFile.Close()
w := csv.NewWriter(naOutFile)
defer w.Flush()
getDataAndWriteFile(allNAVinsSlice, w)
//
// For all EU prod vins
//
euVinsFile, err := os.Open("vin_lists/cec_euprd_vins.csv")
if err != nil {
log.Fatal(err)
}
defer euVinsFile.Close()
allEUVins, err := csv.NewReader(euVinsFile).ReadAll()
if err != nil {
log.Fatalln("csv failed", err)
}
allEUVinsSlice := slices.Concat(allEUVins...)
euOutFile, err := os.Create("all_cec_euprd_config_data.csv")
if err != nil {
log.Fatalln("failed to open file", err)
}
defer euOutFile.Close()
w = csv.NewWriter(euOutFile)
defer w.Flush()
getDataAndWriteFile(allEUVinsSlice, w)
}
func TestGetSAPDataPreProd(t *testing.T) {
t.Skip()
t.Setenv("SAP_URL", "https://stg.tpapi.fiskerinc.com/connected-car-mule")
t.Setenv("SAP_VEHICLESPEC_API_KEY", "ff2406ad-de67-479e-aac7-c9681f9e767c")
//
// For all preprod vins
//
preprdVinsFile, err := os.Open("vin_lists/preprod_vins.csv")
if err != nil {
log.Fatal(err)
}
defer preprdVinsFile.Close()
allPreprodVins, err := csv.NewReader(preprdVinsFile).ReadAll()
if err != nil {
log.Fatalln("csv failed", err)
}
allPreprodVinsSlice := slices.Concat(allPreprodVins...)
preprodOutFile, err := os.Create("all_preprd_config_data.csv")
if err != nil {
log.Fatalln("failed to open file", err)
}
defer preprodOutFile.Close()
w := csv.NewWriter(preprodOutFile)
defer w.Flush()
getDataAndWriteFile(allPreprodVinsSlice, w)
}
func TestGetSAPDataDev(t *testing.T) {
t.Skip()
t.Setenv("SAP_URL", "https://dev.tpapi.fiskerinc.com/connected-car-mule")
t.Setenv("SAP_VEHICLESPEC_API_KEY", "330e9277-eb7c-4604-934c-45f67d1c98b3")
//
// For all dev vins
//
devVinsFile, err := os.Open("vin_lists/dev_vins.csv")
if err != nil {
log.Fatal(err)
}
defer devVinsFile.Close()
allDevVins, err := csv.NewReader(devVinsFile).ReadAll()
if err != nil {
log.Fatalln("csv failed", err)
}
allDevVinsSlice := slices.Concat(allDevVins...)
devOutFile, err := os.Create("all_dev_config_data.csv")
if err != nil {
log.Fatalln("failed to open file", err)
}
defer devOutFile.Close()
w := csv.NewWriter(devOutFile)
defer w.Flush()
getDataAndWriteFile(allDevVinsSlice, w)
}
func getDataAndWriteFile(vins []string, w *csv.Writer) {
for _, vin := range vins {
res, err := NewSAPService().GetFeatureCodes(vin)
if err != nil {
log.Fatalln("sap failed", err)
}
if len(res.Features) == 0 {
continue
}
sapJSON, err := json.Marshal(res)
if err != nil {
log.Fatal(err)
}
sapData := VinSAPData{
vin: vin,
configData: string(sapJSON),
}
row := []string{sapData.vin, sapData.configData}
if err := w.Write(row); err != nil {
log.Fatalln("error writing record to file", err)
}
}
}