Compare commits
28 Commits
48844127d7
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
| dcd1a9ccec | |||
| aee37eb8f7 | |||
| 0ce0dc35e1 | |||
| 1ddf18a400 | |||
| 41a7f57988 | |||
| bd6682e861 | |||
| bbeb96dbda | |||
| ca45a77a0f | |||
| 8b6892df60 | |||
| f1ca48c1d0 | |||
| 57f42a0e47 | |||
| eb928a7c56 | |||
| 36b05af60e | |||
| a3a08d9cff | |||
| 857f94c59a | |||
| cc2cbd09e1 | |||
| aed30707be | |||
| b8406a7f71 | |||
| 469fb0ff5f | |||
| 9a2d57f975 | |||
| 6a81fe4f87 | |||
| 547c5c935c | |||
| cbf7bb8de6 | |||
| 68c9e01ef1 | |||
| d95d947bc2 | |||
| c9e956d004 | |||
| ff20615481 | |||
| b259b77967 |
@@ -1,8 +1,7 @@
|
|||||||
using Microsoft.AspNetCore.Mvc;
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using PartSource.Data.Models;
|
using PartSource.Data.Models;
|
||||||
using PartSource.Services;
|
using PartSource.Services;
|
||||||
using System.Net;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace PartSource.Api.Controllers
|
namespace PartSource.Api.Controllers
|
||||||
{
|
{
|
||||||
@@ -23,7 +22,7 @@ namespace PartSource.Api.Controllers
|
|||||||
[Route("sku/{sku}/storeNumber/{storeNumber}")]
|
[Route("sku/{sku}/storeNumber/{storeNumber}")]
|
||||||
public async Task<ActionResult> GetInventory(int sku, int storeNumber)
|
public async Task<ActionResult> GetInventory(int sku, int storeNumber)
|
||||||
{
|
{
|
||||||
PartsAvailability inventory = await _inventoryService.GetInventory(sku, storeNumber);
|
PartAvailability inventory = await _inventoryService.GetInventory(sku, storeNumber);
|
||||||
|
|
||||||
if (inventory == null)
|
if (inventory == null)
|
||||||
{
|
{
|
||||||
@@ -36,7 +35,8 @@ namespace PartSource.Api.Controllers
|
|||||||
{
|
{
|
||||||
StoreNumber = inventory.Store,
|
StoreNumber = inventory.Store,
|
||||||
Sku = sku,
|
Sku = sku,
|
||||||
Quantity = inventory.QTY
|
Quantity = inventory.QTY,
|
||||||
|
Updated = inventory.Updated
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ using PartSource.Data.Dtos;
|
|||||||
using PartSource.Data.Models;
|
using PartSource.Data.Models;
|
||||||
using PartSource.Data.Nexpart;
|
using PartSource.Data.Nexpart;
|
||||||
using PartSource.Services;
|
using PartSource.Services;
|
||||||
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
@@ -19,12 +20,100 @@ namespace PartSource.Api.Controllers
|
|||||||
private readonly NexpartService _nexpartService;
|
private readonly NexpartService _nexpartService;
|
||||||
private readonly PartService _partService;
|
private readonly PartService _partService;
|
||||||
private readonly VehicleService _vehicleService;
|
private readonly VehicleService _vehicleService;
|
||||||
|
private readonly FitmentService _fitmentService;
|
||||||
|
|
||||||
public PartsController(NexpartService nexpartService, PartService partService, VehicleService vehicleService)
|
public PartsController(NexpartService nexpartService, PartService partService, VehicleService vehicleService, FitmentService fitmentService)
|
||||||
{
|
{
|
||||||
_nexpartService = nexpartService;
|
_nexpartService = nexpartService;
|
||||||
_partService = partService;
|
_partService = partService;
|
||||||
_vehicleService = vehicleService;
|
_vehicleService = vehicleService;
|
||||||
|
_fitmentService = fitmentService;
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpGet]
|
||||||
|
[Route("fitment")]
|
||||||
|
[Route("fitmentnote")]
|
||||||
|
public async Task<ActionResult> GetFitment([FromQuery] string sku, [FromQuery] int vehicleId)
|
||||||
|
{
|
||||||
|
VehicleFitmentDto vehicleFitment = await _fitmentService.GetFitmentNotes(sku, vehicleId);
|
||||||
|
|
||||||
|
if (vehicleFitment == null)
|
||||||
|
{
|
||||||
|
return NotFound();
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
string[] segments = vehicleFitment.NoteText.Split(']');
|
||||||
|
vehicleFitment.PartDescription = segments[0].TrimStart('[');
|
||||||
|
vehicleFitment.DriveTypes = GetDriveTypesFromNote(vehicleFitment.NoteText);
|
||||||
|
vehicleFitment.Notes = segments[1].Split(';')
|
||||||
|
.Select(n => n.Trim())
|
||||||
|
.ToList();
|
||||||
|
}
|
||||||
|
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException($"The note_text field provided by WHI for {vehicleFitment.LineCode} {vehicleFitment.PartNumber} was in an invalid format.");
|
||||||
|
}
|
||||||
|
|
||||||
|
SmartPageDataSearch smartPageDataSearch = new SmartPageDataSearch
|
||||||
|
{
|
||||||
|
Items = new[]
|
||||||
|
{
|
||||||
|
new Item { PartNumber = vehicleFitment.PartNumber, MfrCode = vehicleFitment.LineCode }
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
SmartPageDataSearchResponse smartPageResponse = await _nexpartService.SendRequest<SmartPageDataSearch, SmartPageDataSearchResponse>(smartPageDataSearch);
|
||||||
|
if (smartPageResponse.ResponseBody?.Item != null)
|
||||||
|
{
|
||||||
|
PartType[] partTypes = smartPageResponse.ResponseBody.Item.Select(i => new PartType
|
||||||
|
{
|
||||||
|
Id = i.Part.PartType.Id
|
||||||
|
})
|
||||||
|
.ToArray();
|
||||||
|
|
||||||
|
ApplicationSearch applicationSearch = new ApplicationSearch
|
||||||
|
{
|
||||||
|
VehicleIdentifier = new VehicleIdentifier
|
||||||
|
{
|
||||||
|
BaseVehicleId = vehicleFitment.BaseVehicleId,
|
||||||
|
EngineConfigId = vehicleFitment.EngineConfigId
|
||||||
|
},
|
||||||
|
MfrCode = new[] { vehicleFitment.LineCode },
|
||||||
|
PartType = partTypes,
|
||||||
|
GroupBy = "MFR",
|
||||||
|
QuestionOption = "QUESTION_OTHERWISE_APP"
|
||||||
|
};
|
||||||
|
|
||||||
|
ApplicationSearchResponse response = await _nexpartService.SendRequest<ApplicationSearch, ApplicationSearchResponse>(applicationSearch);
|
||||||
|
if (response.ResponseBody != null && response.ResponseBody is Questions)
|
||||||
|
{
|
||||||
|
Question driveTypeQuestion = ((Questions)response.ResponseBody).Question
|
||||||
|
.Where(q => q.Attribute == "DRIVE_TYPE")
|
||||||
|
.FirstOrDefault();
|
||||||
|
|
||||||
|
if (driveTypeQuestion != null)
|
||||||
|
{
|
||||||
|
foreach (Answer answer in driveTypeQuestion.Answer)
|
||||||
|
{
|
||||||
|
applicationSearch.Criterion = new[]
|
||||||
|
{
|
||||||
|
new Criterion { Attribute = "DRIVE_TYPE", Id = answer.Id}
|
||||||
|
};
|
||||||
|
|
||||||
|
ApplicationSearchResponse driveTypeResponse = await _nexpartService.SendRequest<ApplicationSearch, ApplicationSearchResponse>(applicationSearch);
|
||||||
|
if (driveTypeResponse.ResponseBody != null && ((Apps)driveTypeResponse.ResponseBody).App.Where(a => a.Part == vehicleFitment.PartNumber).Any())
|
||||||
|
{
|
||||||
|
vehicleFitment.DriveTypes.Add(answer.Value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Ok(vehicleFitment);
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpGet]
|
[HttpGet]
|
||||||
@@ -47,18 +136,18 @@ namespace PartSource.Api.Controllers
|
|||||||
{
|
{
|
||||||
return BadRequest(new
|
return BadRequest(new
|
||||||
{
|
{
|
||||||
Message = $"No vehicle data is available for SKU {sku}. Confirm it is available in the database maintained by Sound Press.",
|
Message = $"No vehicle data is available for vehicle ID {vehicleId}. Confirm it is available in the database maintained by Sound Press.",
|
||||||
Reason = $"{nameof(_vehicleService.GetVehicleById)} returned null"
|
Reason = $"{nameof(_vehicleService.GetVehicleById)} returned null"
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
IList<DcfMapping> mappings = await _partService.GetDcfMapping(part.LineCode);
|
IList<DcfMapping> mappings = await _partService.GetDcfMapping(part.LineCode);
|
||||||
Item[] items = mappings.Select(m => new Item
|
Item[] items = mappings.Select(m => new Item
|
||||||
{
|
{
|
||||||
PartNumber = part.PartNumber,
|
PartNumber = part.PartNumber,
|
||||||
MfrCode = m.WhiCode
|
MfrCode = m.WhiCode
|
||||||
})
|
})
|
||||||
.ToArray();
|
.ToArray();
|
||||||
|
|
||||||
SmartPageDataSearch smartPageDataSearch = new SmartPageDataSearch
|
SmartPageDataSearch smartPageDataSearch = new SmartPageDataSearch
|
||||||
{
|
{
|
||||||
@@ -76,10 +165,10 @@ namespace PartSource.Api.Controllers
|
|||||||
}
|
}
|
||||||
|
|
||||||
PartType[] partTypes = smartPageResponse.ResponseBody.Item.Select(i => new PartType
|
PartType[] partTypes = smartPageResponse.ResponseBody.Item.Select(i => new PartType
|
||||||
{
|
{
|
||||||
Id = i.Part.PartType.Id
|
Id = i.Part.PartType.Id
|
||||||
})
|
})
|
||||||
.ToArray();
|
.ToArray();
|
||||||
|
|
||||||
ApplicationSearch applicationSearch = new ApplicationSearch
|
ApplicationSearch applicationSearch = new ApplicationSearch
|
||||||
{
|
{
|
||||||
@@ -90,13 +179,13 @@ namespace PartSource.Api.Controllers
|
|||||||
MfrCode = mappings.Select(m => m.WhiCode).ToArray(),
|
MfrCode = mappings.Select(m => m.WhiCode).ToArray(),
|
||||||
PartType = new[] { new PartType { Id = smartPageResponse.ResponseBody.Item[0].Part.PartType.Id } },
|
PartType = new[] { new PartType { Id = smartPageResponse.ResponseBody.Item[0].Part.PartType.Id } },
|
||||||
Criterion = new[]
|
Criterion = new[]
|
||||||
|
{
|
||||||
|
new Criterion
|
||||||
{
|
{
|
||||||
new Criterion
|
Attribute = "REGION",
|
||||||
{
|
Id = 2
|
||||||
Attribute = "REGION",
|
}
|
||||||
Id = 2
|
},
|
||||||
}
|
|
||||||
},
|
|
||||||
GroupBy = "PARTTYPE"
|
GroupBy = "PARTTYPE"
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -112,7 +201,7 @@ namespace PartSource.Api.Controllers
|
|||||||
}
|
}
|
||||||
|
|
||||||
IList<string> positions = new List<string>();
|
IList<string> positions = new List<string>();
|
||||||
foreach (App app in response.ResponseBody?.App)
|
foreach (App app in ((Apps)response.ResponseBody)?.App)
|
||||||
{
|
{
|
||||||
if (!string.IsNullOrEmpty(app.Position) && app.Part == part.PartNumber)
|
if (!string.IsNullOrEmpty(app.Position) && app.Part == part.PartNumber)
|
||||||
{
|
{
|
||||||
@@ -128,5 +217,33 @@ namespace PartSource.Api.Controllers
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private IList<string> GetDriveTypesFromNote(string fitmentNote)
|
||||||
|
{
|
||||||
|
fitmentNote = fitmentNote.ToUpperInvariant();
|
||||||
|
IList<string> driveTypes = new List<string>();
|
||||||
|
|
||||||
|
if (fitmentNote.Contains("FWD"))
|
||||||
|
{
|
||||||
|
driveTypes.Add("FWD");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fitmentNote.Contains("RWD"))
|
||||||
|
{
|
||||||
|
driveTypes.Add("RWD");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fitmentNote.Contains("AWD"))
|
||||||
|
{
|
||||||
|
driveTypes.Add("AWD");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fitmentNote.Contains("4WD"))
|
||||||
|
{
|
||||||
|
driveTypes.Add("4WD");
|
||||||
|
}
|
||||||
|
|
||||||
|
return driveTypes;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ namespace PartSource.Api.Controllers
|
|||||||
|
|
||||||
if (response.ResponseBody != null)
|
if (response.ResponseBody != null)
|
||||||
{
|
{
|
||||||
return NexpartResponse<ApplicationSearchResponse, Apps>(response);
|
return NexpartResponse<ApplicationSearchResponse, object>(response);
|
||||||
}
|
}
|
||||||
|
|
||||||
else
|
else
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
<TargetFramework>net6.0</TargetFramework>
|
<TargetFramework>net6.0</TargetFramework>
|
||||||
<UserSecretsId>f9e2fd37-0f2d-4e3a-955a-8e49a16fce1c</UserSecretsId>
|
<UserSecretsId>f9e2fd37-0f2d-4e3a-955a-8e49a16fce1c</UserSecretsId>
|
||||||
<Configurations>Debug;Release;Also Debug</Configurations>
|
<Configurations>Debug;Release;Also Debug</Configurations>
|
||||||
|
<SatelliteResourceLanguages>en-us;en</SatelliteResourceLanguages>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
|
||||||
@@ -23,7 +24,6 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<None Include="..\.editorconfig" Link=".editorconfig" />
|
|
||||||
<None Include="appsettings.development.json">
|
<None Include="appsettings.development.json">
|
||||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||||
</None>
|
</None>
|
||||||
@@ -35,7 +35,7 @@
|
|||||||
<PackageReference Include="Microsoft.AspNetCore.Razor.Design" Version="2.2.0" PrivateAssets="All" />
|
<PackageReference Include="Microsoft.AspNetCore.Razor.Design" Version="2.2.0" PrivateAssets="All" />
|
||||||
<PackageReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Version="6.0.5" />
|
<PackageReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Version="6.0.5" />
|
||||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
|
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
|
||||||
<PackageReference Include="Ratermania.Shopify" Version="1.3.1" />
|
<PackageReference Include="Ratermania.Shopify" Version="6.16.11" />
|
||||||
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.3.1" />
|
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.3.1" />
|
||||||
<PackageReference Include="Swashbuckle.AspNetCore.ReDoc" Version="6.3.1" />
|
<PackageReference Include="Swashbuckle.AspNetCore.ReDoc" Version="6.3.1" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|||||||
@@ -1,13 +1,4 @@
|
|||||||
{
|
{
|
||||||
"iisSettings": {
|
|
||||||
"windowsAuthentication": false,
|
|
||||||
"anonymousAuthentication": true,
|
|
||||||
"iisExpress": {
|
|
||||||
"applicationUrl": "http://localhost:31337",
|
|
||||||
"sslPort": 0
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"$schema": "http://json.schemastore.org/launchsettings.json",
|
|
||||||
"profiles": {
|
"profiles": {
|
||||||
"IIS Express": {
|
"IIS Express": {
|
||||||
"commandName": "IISExpress",
|
"commandName": "IISExpress",
|
||||||
@@ -18,12 +9,20 @@
|
|||||||
},
|
},
|
||||||
"PartSource.Api": {
|
"PartSource.Api": {
|
||||||
"commandName": "Project",
|
"commandName": "Project",
|
||||||
"launchBrowser": true,
|
|
||||||
"launchUrl": "api/values",
|
"launchUrl": "api/values",
|
||||||
"environmentVariables": {
|
"environmentVariables": {
|
||||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||||
},
|
},
|
||||||
"applicationUrl": "https://localhost:5001;http://localhost:5000"
|
"applicationUrl": "https://localhost:5001;http://localhost:5000"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"$schema": "http://json.schemastore.org/launchsettings.json",
|
||||||
|
"iisSettings": {
|
||||||
|
"windowsAuthentication": false,
|
||||||
|
"anonymousAuthentication": true,
|
||||||
|
"iisExpress": {
|
||||||
|
"applicationUrl": "http://localhost:31337",
|
||||||
|
"sslPort": 0
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -52,6 +52,7 @@ namespace PartSource.Api
|
|||||||
services.AddAutoMapper(typeof(PartSourceProfile));
|
services.AddAutoMapper(typeof(PartSourceProfile));
|
||||||
|
|
||||||
services.AddTransient<PartService>();
|
services.AddTransient<PartService>();
|
||||||
|
services.AddTransient<FitmentService>();
|
||||||
services.AddTransient<NexpartService>();
|
services.AddTransient<NexpartService>();
|
||||||
services.AddTransient<SecurityService>();
|
services.AddTransient<SecurityService>();
|
||||||
services.AddTransient<VehicleService>();
|
services.AddTransient<VehicleService>();
|
||||||
@@ -67,9 +68,9 @@ namespace PartSource.Api
|
|||||||
services.AddDbContext<PartSourceContext>(options =>
|
services.AddDbContext<PartSourceContext>(options =>
|
||||||
options.UseSqlServer(Configuration.GetConnectionString("PartSourceDatabase"))
|
options.UseSqlServer(Configuration.GetConnectionString("PartSourceDatabase"))
|
||||||
);
|
);
|
||||||
//services.AddDbContext<FitmentContext>(options =>
|
services.AddDbContext<FitmentContext>(options =>
|
||||||
// options.UseSqlServer(Configuration.GetConnectionString("FitmentDatabase"))
|
options.UseSqlServer(Configuration.GetConnectionString("FitmentDatabase"))
|
||||||
//);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
|
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
"ConnectionStrings": {
|
"ConnectionStrings": {
|
||||||
"PartSourceDatabase": "Server=tcp:ps-whi.database.windows.net,1433;Initial Catalog=ps-whi-stage;Persist Security Info=False;User ID=ps-whi;Password=9-^*N5dw!6:|.5Q;MultipleActiveResultSets=False;Encrypt=True;TrustServerCertificate=False;Connection Timeout=30;",
|
"PartSourceDatabase": "Server=tcp:ps-whi.database.windows.net,1433;Initial Catalog=ps-whi-stage;Persist Security Info=False;User ID=ps-whi;Password=9-^*N5dw!6:|.5Q;MultipleActiveResultSets=False;Encrypt=True;TrustServerCertificate=False;Connection Timeout=30;",
|
||||||
//"FitmentDatabase": "Data Source=localhost;Initial Catalog=WhiFitment;Integrated Security=true"
|
//"FitmentDatabase": "Data Source=localhost;Initial Catalog=WhiFitment;Integrated Security=true"
|
||||||
|
"FitmentDatabase": "Server=tcp:ps-automation.eastus2.cloudapp.azure.com,1433;Initial Catalog=WhiFitment;User ID=sa;Password=GZ0`-ekd~[2u;Encrypt=True;TrustServerCertificate=True;Connection Timeout=300"
|
||||||
},
|
},
|
||||||
"Logging": {
|
"Logging": {
|
||||||
"LogLevel": {
|
"LogLevel": {
|
||||||
|
|||||||
23
PartSource.Automation/Extensions/FileInfoExtensions.cs
Normal file
23
PartSource.Automation/Extensions/FileInfoExtensions.cs
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Globalization;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace PartSource.Automation.Extensions
|
||||||
|
{
|
||||||
|
public static class FileInfoExtensions
|
||||||
|
{
|
||||||
|
public static DateTime GetWhiTimestamp(this FileInfo fileInfo)
|
||||||
|
{
|
||||||
|
Match match = Regex.Match(fileInfo.Name, "[0-9]{8}");
|
||||||
|
|
||||||
|
return match.Success && DateTime.TryParseExact(match.Value, "MMddyyyy", CultureInfo.InvariantCulture, DateTimeStyles.None, out DateTime timestamp)
|
||||||
|
? timestamp
|
||||||
|
: DateTime.MinValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
107
PartSource.Automation/Jobs/BulkUpdateInventory.cs
Normal file
107
PartSource.Automation/Jobs/BulkUpdateInventory.cs
Normal file
@@ -0,0 +1,107 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Data;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.Data.SqlClient;
|
||||||
|
using Microsoft.Extensions.Configuration;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
using PartSource.Automation.Models.Configuration;
|
||||||
|
using PartSource.Automation.Models.Ftp;
|
||||||
|
using PartSource.Automation.Services;
|
||||||
|
using Ratermania.Automation.Interfaces;
|
||||||
|
|
||||||
|
namespace PartSource.Automation.Jobs
|
||||||
|
{
|
||||||
|
public class BulkUpdateInventory : IAutomationJob
|
||||||
|
{
|
||||||
|
private readonly FtpService _ftpService;
|
||||||
|
private readonly ILogger<BulkUpdateInventory> _logger;
|
||||||
|
private readonly string _connectionString;
|
||||||
|
|
||||||
|
public BulkUpdateInventory(IConfiguration configuration, ILogger<BulkUpdateInventory> logger)
|
||||||
|
{
|
||||||
|
FtpConfiguration ftpConfiguration = configuration.GetSection("FtpServers:AutomationConfiguration").Get<FtpConfiguration>();
|
||||||
|
_ftpService = new FtpService(ftpConfiguration);
|
||||||
|
|
||||||
|
_connectionString = configuration.GetConnectionString("PartSourceDatabase");
|
||||||
|
|
||||||
|
_logger = logger;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task Run(CancellationToken token, params string[] arguments)
|
||||||
|
{
|
||||||
|
FtpFileInfo lastUploadedFile = _ftpService.ListFilesExtended()
|
||||||
|
.Where(f => f.FileType == FtpFileType.File && f.Filename.IndexOf("Availability Full") > -1)
|
||||||
|
.OrderByDescending(f => f.Modified)
|
||||||
|
.FirstOrDefault();
|
||||||
|
|
||||||
|
if (lastUploadedFile == null)
|
||||||
|
{
|
||||||
|
_logger.LogInformation($"No full inventory file available.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
string file = _ftpService.Download(lastUploadedFile.Filename);
|
||||||
|
|
||||||
|
DataTable dataTable = GetDataTable(file);
|
||||||
|
|
||||||
|
using SqlConnection connection = new SqlConnection(_connectionString);
|
||||||
|
connection.Open();
|
||||||
|
|
||||||
|
using SqlCommand command = new SqlCommand("TRUNCATE TABLE PartAvailability", connection);
|
||||||
|
await command.ExecuteNonQueryAsync(token);
|
||||||
|
|
||||||
|
using SqlBulkCopy bulk = new SqlBulkCopy(connection)
|
||||||
|
{
|
||||||
|
DestinationTableName = "PartAvailability",
|
||||||
|
BulkCopyTimeout = 14400
|
||||||
|
};
|
||||||
|
|
||||||
|
await bulk.WriteToServerAsync(dataTable, token);
|
||||||
|
|
||||||
|
_ftpService.Delete(lastUploadedFile.Filename);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
private DataTable GetDataTable(string filename)
|
||||||
|
{
|
||||||
|
using DataTable dataTable = new DataTable();
|
||||||
|
dataTable.Columns.Add("Store", typeof(int));
|
||||||
|
dataTable.Columns.Add("SKU", typeof(string));
|
||||||
|
dataTable.Columns.Add("QTY", typeof(int));
|
||||||
|
dataTable.Columns.Add("Updated", typeof(string));
|
||||||
|
|
||||||
|
using StreamReader reader = new StreamReader(filename);
|
||||||
|
string line = reader.ReadLine(); // Burn the header row
|
||||||
|
|
||||||
|
while (reader.Peek() > 0)
|
||||||
|
{
|
||||||
|
line = reader.ReadLine();
|
||||||
|
|
||||||
|
string[] columns = line.Split("|");
|
||||||
|
for (int i = 0; i < columns.Length; i++)
|
||||||
|
{
|
||||||
|
columns[i] = columns[i].Replace("\"", string.Empty);
|
||||||
|
}
|
||||||
|
|
||||||
|
string sku = columns[1].Trim();
|
||||||
|
string updated = columns[3].Trim();
|
||||||
|
|
||||||
|
if (int.TryParse(columns[0], out int store)
|
||||||
|
&& !string.IsNullOrEmpty(sku)
|
||||||
|
&& int.TryParse(columns[2], out int quantity)
|
||||||
|
&& !string.IsNullOrEmpty(updated))
|
||||||
|
{
|
||||||
|
dataTable.Rows.Add(new object[] { store, sku, quantity, updated });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return dataTable;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,55 +1,69 @@
|
|||||||
using Microsoft.Extensions.Configuration;
|
using Microsoft.Extensions.Configuration;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using PartSource.Automation.Models.Configuration;
|
using PartSource.Automation.Models.Configuration;
|
||||||
|
using PartSource.Automation.Models.Ftp;
|
||||||
using PartSource.Automation.Services;
|
using PartSource.Automation.Services;
|
||||||
using Ratermania.Automation.Interfaces;
|
using Ratermania.Automation.Interfaces;
|
||||||
using System;
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace PartSource.Automation.Jobs
|
namespace PartSource.Automation.Jobs
|
||||||
{
|
{
|
||||||
public class ExecuteSsisPackages : IAutomationJob
|
public class ExecuteSsisPackages : IAutomationJob
|
||||||
{
|
{
|
||||||
private readonly EmailService _emailService;
|
private readonly EmailService _emailService;
|
||||||
private readonly FtpService _ftpService;
|
private readonly FtpService _ftpService;
|
||||||
private readonly SsisService _ssisService;
|
private readonly SsisService _ssisService;
|
||||||
private readonly ILogger<ExecuteSsisPackages> _logger;
|
private readonly ILogger<ExecuteSsisPackages> _logger;
|
||||||
|
|
||||||
// TODO: set from config
|
// TODO: set from config
|
||||||
private readonly string[] _ssisPackages = { "Parts Price", "Parts Availability" };
|
private readonly string[] _ssisPackages = {"Parts Price" };
|
||||||
|
|
||||||
public ExecuteSsisPackages(EmailService emailService, FtpService ftpService, SsisService ssisService, ILogger<ExecuteSsisPackages> logger)
|
public ExecuteSsisPackages(EmailService emailService, IConfiguration configuration, SsisService ssisService, ILogger<ExecuteSsisPackages> logger)
|
||||||
{
|
{
|
||||||
_ftpService = ftpService;
|
FtpConfiguration ftpConfiguration = configuration.GetSection("FtpServers:AutomationConfiguration").Get<FtpConfiguration>();
|
||||||
_emailService = emailService;
|
|
||||||
_ssisService = ssisService;
|
_emailService = emailService;
|
||||||
_logger = logger;
|
_ftpService = new FtpService(ftpConfiguration);
|
||||||
}
|
_ssisService = ssisService;
|
||||||
|
_logger = logger;
|
||||||
|
}
|
||||||
|
public async Task Run(CancellationToken token, params string[] arguments)
|
||||||
|
{
|
||||||
|
await Task.Run(() =>
|
||||||
|
{
|
||||||
|
foreach (string package in _ssisPackages)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
FtpFileInfo lastUploadedFile = _ftpService.ListFilesExtended()
|
||||||
|
.Where(f => f.FileType == FtpFileType.File && f.Filename.IndexOf(package) > -1)
|
||||||
|
.OrderByDescending(f => f.Modified)
|
||||||
|
.FirstOrDefault();
|
||||||
|
|
||||||
|
if (lastUploadedFile == null)
|
||||||
|
{
|
||||||
|
_logger.LogInformation($"No {package} file available.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
public async Task Run()
|
|
||||||
{
|
|
||||||
await Task.Run(() =>
|
|
||||||
{
|
|
||||||
foreach (string package in _ssisPackages)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
_ftpService.Download($"{package}.txt");
|
_ftpService.Download($"{package}.txt");
|
||||||
_ssisService.Execute($"{package}.dtsx");
|
_ssisService.Execute($"{package}.dtsx");
|
||||||
|
|
||||||
_logger.LogInformation("Execution of SSIS package {package} completed successfully.", package);
|
_logger.LogInformation($"Execution of SSIS package {package} completed successfully.");
|
||||||
}
|
}
|
||||||
|
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
_logger.LogError(ex, "Execution of SSIS package {package} failed", package);
|
_logger.LogError($"Execution of SSIS package {package} failed.", ex);
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
throw;
|
// _emailService.Send("Database Updates Complete", "Database updates to support pricing and availability have completed successfully.");
|
||||||
}
|
});
|
||||||
}
|
}
|
||||||
|
}
|
||||||
_emailService.Send("Database Updates Complete", "Database updates to support pricing and availability have completed successfully.");
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ using System;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace PartSource.Automation.Jobs
|
namespace PartSource.Automation.Jobs
|
||||||
@@ -18,7 +19,7 @@ namespace PartSource.Automation.Jobs
|
|||||||
_nexpartService = nexpartService;
|
_nexpartService = nexpartService;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task Run()
|
public async Task Run(CancellationToken token, params string[] arguments)
|
||||||
{
|
{
|
||||||
IList<string> rows = new List<string>
|
IList<string> rows = new List<string>
|
||||||
{
|
{
|
||||||
@@ -27,7 +28,7 @@ namespace PartSource.Automation.Jobs
|
|||||||
|
|
||||||
MenuNodesLookup menuNodesLookup = new MenuNodesLookup
|
MenuNodesLookup menuNodesLookup = new MenuNodesLookup
|
||||||
{
|
{
|
||||||
MenuId = 2,
|
MenuId = 1,
|
||||||
NumberOfLevels = 1
|
NumberOfLevels = 1
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -39,7 +40,7 @@ namespace PartSource.Automation.Jobs
|
|||||||
|
|
||||||
MenuNodesLookup subgroupLookup = new MenuNodesLookup
|
MenuNodesLookup subgroupLookup = new MenuNodesLookup
|
||||||
{
|
{
|
||||||
MenuId = 2,
|
MenuId = 1,
|
||||||
NumberOfLevels = 1,
|
NumberOfLevels = 1,
|
||||||
ParentMenuNodeId = categoryNode.Id
|
ParentMenuNodeId = categoryNode.Id
|
||||||
};
|
};
|
||||||
@@ -52,7 +53,7 @@ namespace PartSource.Automation.Jobs
|
|||||||
|
|
||||||
MenuNodesLookup thirdLookup = new MenuNodesLookup
|
MenuNodesLookup thirdLookup = new MenuNodesLookup
|
||||||
{
|
{
|
||||||
MenuId = 2,
|
MenuId = 1,
|
||||||
NumberOfLevels = 1,
|
NumberOfLevels = 1,
|
||||||
ParentMenuNodeId = subgroupNode.Id
|
ParentMenuNodeId = subgroupNode.Id
|
||||||
};
|
};
|
||||||
@@ -67,7 +68,7 @@ namespace PartSource.Automation.Jobs
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//await File.WriteAllLinesAsync("C:\\users\\Tommy\\desktop\\Partsource Menu Items.csv", rows);
|
await File.WriteAllLinesAsync("C:\\users\\Tommy\\desktop\\Partsource Menu Items.csv", rows);
|
||||||
|
|
||||||
;
|
;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,65 +0,0 @@
|
|||||||
using Ratermania.Automation.Interfaces;
|
|
||||||
using Ratermania.Shopify;
|
|
||||||
using Ratermania.Shopify.Resources;
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Text.RegularExpressions;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace PartSource.Automation.Jobs.POC
|
|
||||||
{
|
|
||||||
public class FixMultipleSeoTables : IAutomationJob
|
|
||||||
{
|
|
||||||
private readonly ShopifyClient _shopifyClient;
|
|
||||||
|
|
||||||
public FixMultipleSeoTables(ShopifyClient shopifyClient)
|
|
||||||
{
|
|
||||||
_shopifyClient = shopifyClient;
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task Run()
|
|
||||||
{
|
|
||||||
IEnumerable<Product> products = await _shopifyClient.Products.Get(new Dictionary<string, object> { { "limit", 250 }, { "product_type", "CA112-SC137-FL13750_Intake Manifolds" } });
|
|
||||||
|
|
||||||
while (products != null && products.Any())
|
|
||||||
{
|
|
||||||
foreach (Product product in products)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
string[] parts = product.BodyHtml.Split("<div id=\"seoData\">");
|
|
||||||
|
|
||||||
if (parts.Length > 2)
|
|
||||||
{
|
|
||||||
string ul = product.BodyHtml.Substring(0, product.BodyHtml.IndexOf("</ul>") + "</ul>".Length);
|
|
||||||
string seoData = "<div id=\"seoData\">" + parts[1].Substring(0, parts[1].IndexOf("</table>") + "</table>".Length) + "</div>";
|
|
||||||
string vehicleIds = new Regex("<div id=\"vehicleIDs\".*</div>").Match(product.BodyHtml).Value;
|
|
||||||
|
|
||||||
product.BodyHtml = ul + seoData + vehicleIds;
|
|
||||||
|
|
||||||
await _shopifyClient.Products.Update(product);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
Console.WriteLine($"Failed to update {product.Id}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
Console.WriteLine("Did 250");
|
|
||||||
products = await _shopifyClient.Products.GetNext();
|
|
||||||
}
|
|
||||||
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
products = await _shopifyClient.Products.GetPrevious();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
119
PartSource.Automation/Jobs/POC/GetImageUrls.cs
Normal file
119
PartSource.Automation/Jobs/POC/GetImageUrls.cs
Normal file
@@ -0,0 +1,119 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
using PartSource.Data.Contexts;
|
||||||
|
using PartSource.Data.Models;
|
||||||
|
using PartSource.Data.Nexpart;
|
||||||
|
using PartSource.Services;
|
||||||
|
using Ratermania.Automation.Interfaces;
|
||||||
|
using Ratermania.Shopify;
|
||||||
|
using Ratermania.Shopify.Resources;
|
||||||
|
|
||||||
|
namespace PartSource.Automation.Jobs.POC
|
||||||
|
{
|
||||||
|
public class GetImageUrls : IAutomationJob
|
||||||
|
{
|
||||||
|
private readonly NexpartService _nexpartService;
|
||||||
|
private readonly FitmentContext _fitmentContext;
|
||||||
|
private readonly PartService _partService;
|
||||||
|
private readonly ShopifyClient _shopifyClient;
|
||||||
|
|
||||||
|
public GetImageUrls(NexpartService nexpartService, PartService partService, FitmentContext fitmentContext, ShopifyClient shopifyClient)
|
||||||
|
{
|
||||||
|
_nexpartService = nexpartService;
|
||||||
|
_fitmentContext = fitmentContext;
|
||||||
|
_partService = partService;
|
||||||
|
_shopifyClient = shopifyClient;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task Run(CancellationToken token, params string[] arguments)
|
||||||
|
{
|
||||||
|
IList<string> rows = new List<string> {
|
||||||
|
"\"Line Code\", \"Part Number\", \"Image URL(s)\""
|
||||||
|
};
|
||||||
|
|
||||||
|
using StreamReader reader = new StreamReader("C:\\Users\\Tom\\Desktop\\image parts.csv");
|
||||||
|
string line = reader.ReadLine(); // Burn the header row
|
||||||
|
|
||||||
|
while (reader.Peek() > 0)
|
||||||
|
{
|
||||||
|
line = reader.ReadLine();
|
||||||
|
|
||||||
|
string[] columns = line.Split(",");
|
||||||
|
for (int i = 0; i < columns.Length; i++)
|
||||||
|
{
|
||||||
|
columns[i] = columns[i].Replace("\"", string.Empty);
|
||||||
|
}
|
||||||
|
|
||||||
|
string partsourceCode = columns[0].Trim();
|
||||||
|
string partNumber = columns[1].Trim();
|
||||||
|
|
||||||
|
|
||||||
|
IList<DcfMapping> dcfMappings = await _partService.GetDcfMapping(partsourceCode);
|
||||||
|
if (dcfMappings.Count == 0)
|
||||||
|
{
|
||||||
|
Console.WriteLine($"No images for {partsourceCode} {partNumber}");
|
||||||
|
}
|
||||||
|
|
||||||
|
bool hasImage = false;
|
||||||
|
foreach (DcfMapping mapping in dcfMappings)
|
||||||
|
{
|
||||||
|
if (hasImage)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
SmartPageDataSearch dataSearch = new SmartPageDataSearch
|
||||||
|
{
|
||||||
|
Items = new Item[]
|
||||||
|
{
|
||||||
|
new Item
|
||||||
|
{
|
||||||
|
MfrCode = mapping.WhiCode,
|
||||||
|
PartNumber = partNumber
|
||||||
|
}
|
||||||
|
},
|
||||||
|
DataOption = new[] { "ALL" }
|
||||||
|
};
|
||||||
|
|
||||||
|
SmartPageDataSearchResponse response = await _nexpartService.SendRequest<SmartPageDataSearch, SmartPageDataSearchResponse>(dataSearch);
|
||||||
|
|
||||||
|
if (response.ResponseBody.Item?.Length > 0)
|
||||||
|
{
|
||||||
|
List<string> urls = new List<string>();
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(response.ResponseBody.Item[0].PrimaryImg?.ImgUrl))
|
||||||
|
{
|
||||||
|
urls.Add(response.ResponseBody.Item[0].PrimaryImg?.ImgUrl);
|
||||||
|
};
|
||||||
|
|
||||||
|
if (response.ResponseBody.Item[0].AddImgs?.AddImg?.Length > 0)
|
||||||
|
{
|
||||||
|
urls.AddRange(response.ResponseBody.Item[0].AddImgs.AddImg.Select(i => i.AddImgUrl));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (urls.Count > 0)
|
||||||
|
{
|
||||||
|
rows.Add($"\"{partsourceCode}\", \"{partNumber}\", \"{string.Join(";", urls)}\"");
|
||||||
|
hasImage = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!hasImage)
|
||||||
|
{
|
||||||
|
Console.WriteLine($"No images for {partsourceCode} {partNumber}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
await File.WriteAllLinesAsync($"C:\\users\\Tom\\desktop\\WHI Images {DateTime.Now:yyyyMMdd}.csv", rows);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
106
PartSource.Automation/Jobs/POC/GetImageUrlsTemp.cs
Normal file
106
PartSource.Automation/Jobs/POC/GetImageUrlsTemp.cs
Normal file
@@ -0,0 +1,106 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
using PartSource.Data.Contexts;
|
||||||
|
using PartSource.Data.Models;
|
||||||
|
using PartSource.Data.Nexpart;
|
||||||
|
using PartSource.Services;
|
||||||
|
using Ratermania.Automation.Interfaces;
|
||||||
|
using Ratermania.Shopify;
|
||||||
|
using Ratermania.Shopify.Resources;
|
||||||
|
|
||||||
|
namespace PartSource.Automation.Jobs.POC
|
||||||
|
{
|
||||||
|
public class GetImageUrlsTemp : IAutomationJob
|
||||||
|
{
|
||||||
|
private readonly NexpartService _nexpartService;
|
||||||
|
private readonly FitmentContext _fitmentContext;
|
||||||
|
private readonly PartService _partService;
|
||||||
|
private readonly ShopifyClient _shopifyClient;
|
||||||
|
|
||||||
|
private readonly string chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
||||||
|
|
||||||
|
public GetImageUrlsTemp(NexpartService nexpartService, PartService partService, FitmentContext fitmentContext, ShopifyClient shopifyClient)
|
||||||
|
{
|
||||||
|
_nexpartService = nexpartService;
|
||||||
|
_fitmentContext = fitmentContext;
|
||||||
|
_partService = partService;
|
||||||
|
_shopifyClient = shopifyClient;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task Run(CancellationToken token, params string[] arguments)
|
||||||
|
{
|
||||||
|
IList<KeyValuePair<string, string>> parts = new List<KeyValuePair<string, string>>();
|
||||||
|
parts.Add(new KeyValuePair<string, string>("DAY", "89310"));
|
||||||
|
parts.Add(new KeyValuePair<string, string>("CNI", "141.40113"));
|
||||||
|
parts.Add(new KeyValuePair<string, string>("PRF", "MU19631"));
|
||||||
|
parts.Add(new KeyValuePair<string, string>("TRK", "SB8100"));
|
||||||
|
parts.Add(new KeyValuePair<string, string>("MON", "906970"));
|
||||||
|
parts.Add(new KeyValuePair<string, string>("FEL", "70804"));
|
||||||
|
parts.Add(new KeyValuePair<string, string>("FEL", "SS71198"));
|
||||||
|
parts.Add(new KeyValuePair<string, string>("CFP", "STS314"));
|
||||||
|
parts.Add(new KeyValuePair<string, string>("NGK", "21517"));
|
||||||
|
parts.Add(new KeyValuePair<string, string>("NGK", "RC-XX89"));
|
||||||
|
parts.Add(new KeyValuePair<string, string>("FRA", "CA176"));
|
||||||
|
|
||||||
|
for (int i = 0; i < chars.Length; i++)
|
||||||
|
{
|
||||||
|
for (int j = 0; j < chars.Length; j++)
|
||||||
|
{
|
||||||
|
for (int k = 0; k < chars.Length; k++)
|
||||||
|
{
|
||||||
|
string actualLineCode = $"{chars[i]}{chars[j]}{chars[k]}";
|
||||||
|
System.Diagnostics.Debug.WriteLine(actualLineCode);
|
||||||
|
|
||||||
|
foreach (KeyValuePair<string, string> part in parts)
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
SmartPageDataSearch dataSearch = new SmartPageDataSearch
|
||||||
|
{
|
||||||
|
Items = new Item[]
|
||||||
|
{
|
||||||
|
new Item
|
||||||
|
{
|
||||||
|
MfrCode = actualLineCode,
|
||||||
|
PartNumber = part.Value
|
||||||
|
}
|
||||||
|
},
|
||||||
|
DataOption = new[] { "DIST_LINE", "ALL" }
|
||||||
|
};
|
||||||
|
|
||||||
|
SmartPageDataSearchResponse response = await _nexpartService.SendRequest<SmartPageDataSearch, SmartPageDataSearchResponse>(dataSearch);
|
||||||
|
|
||||||
|
if (response.ResponseBody.Item?.Length > 0)
|
||||||
|
{
|
||||||
|
List<string> urls = new List<string>();
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(response.ResponseBody.Item[0].PrimaryImg?.ImgUrl))
|
||||||
|
{
|
||||||
|
urls.Add(response.ResponseBody.Item[0].PrimaryImg?.ImgUrl);
|
||||||
|
};
|
||||||
|
|
||||||
|
if (response.ResponseBody.Item[0].AddImgs?.AddImg?.Length > 0)
|
||||||
|
{
|
||||||
|
urls.AddRange(response.ResponseBody.Item[0].AddImgs.AddImg.Select(i => i.AddImgUrl));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (urls.Count > 0)
|
||||||
|
{
|
||||||
|
Console.WriteLine($"Image {urls[0]} found for {part.Value}. Expected: {part.Key}, Actual: {actualLineCode}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
95
PartSource.Automation/Jobs/POC/ImageList.cs
Normal file
95
PartSource.Automation/Jobs/POC/ImageList.cs
Normal file
@@ -0,0 +1,95 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
using PartSource.Data.Contexts;
|
||||||
|
using PartSource.Data.Models;
|
||||||
|
using PartSource.Data.Nexpart;
|
||||||
|
using PartSource.Services;
|
||||||
|
using Ratermania.Automation.Interfaces;
|
||||||
|
using Ratermania.Shopify;
|
||||||
|
using Ratermania.Shopify.Resources;
|
||||||
|
|
||||||
|
namespace PartSource.Automation.Jobs.POC
|
||||||
|
{
|
||||||
|
public class ImageList : IAutomationJob
|
||||||
|
{
|
||||||
|
private readonly NexpartService _nexpartService;
|
||||||
|
private readonly PartSourceContext _partSourceContext;
|
||||||
|
private readonly FitmentContext _fitmentContext;
|
||||||
|
|
||||||
|
public ImageList(NexpartService nexpartService, PartSourceContext partSourceContext, FitmentContext fitmentContext)
|
||||||
|
{
|
||||||
|
_nexpartService = nexpartService;
|
||||||
|
_partSourceContext = partSourceContext;
|
||||||
|
_fitmentContext = fitmentContext;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task Run(CancellationToken token, params string[] arguments)
|
||||||
|
{
|
||||||
|
IList<string> rows = new List<string> {
|
||||||
|
"\"Line Code\", \"Part Number\", \"Image URL(s)\""
|
||||||
|
};
|
||||||
|
|
||||||
|
IList<Data.Models.Part> parts = await _fitmentContext.Parts.ToListAsync();
|
||||||
|
string oldLineCode = string.Empty;
|
||||||
|
IList<DcfMapping> mappings = new List<DcfMapping>();
|
||||||
|
|
||||||
|
foreach (Data.Models.Part part in parts)
|
||||||
|
{
|
||||||
|
if (part.LineCode != oldLineCode)
|
||||||
|
{
|
||||||
|
mappings = await _fitmentContext.DcfMappings.Where(d => d.LineCode == part.LineCode).ToListAsync();
|
||||||
|
}
|
||||||
|
;
|
||||||
|
|
||||||
|
foreach (DcfMapping mapping in mappings)
|
||||||
|
{
|
||||||
|
SmartPageDataSearch dataSearch = new SmartPageDataSearch
|
||||||
|
{
|
||||||
|
Items = new Item[]
|
||||||
|
{
|
||||||
|
new Item
|
||||||
|
{
|
||||||
|
MfrCode = mapping.WhiCode,
|
||||||
|
PartNumber = part.PartNumber
|
||||||
|
}
|
||||||
|
},
|
||||||
|
DataOption = new[] { "ALL" }
|
||||||
|
};
|
||||||
|
|
||||||
|
SmartPageDataSearchResponse response = await _nexpartService.SendRequest<SmartPageDataSearch, SmartPageDataSearchResponse>(dataSearch);
|
||||||
|
|
||||||
|
if (response.ResponseBody.Item?.Length > 0)
|
||||||
|
{
|
||||||
|
List<string> urls = new List<string>();
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(response.ResponseBody.Item[0].PrimaryImg?.ImgUrl))
|
||||||
|
{
|
||||||
|
urls.Add(response.ResponseBody.Item[0].PrimaryImg?.ImgUrl);
|
||||||
|
};
|
||||||
|
|
||||||
|
if (response.ResponseBody.Item[0].AddImgs?.AddImg?.Length > 0)
|
||||||
|
{
|
||||||
|
urls.AddRange(response.ResponseBody.Item[0].AddImgs.AddImg.Select(i => i.AddImgUrl));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (urls.Count > 0)
|
||||||
|
{
|
||||||
|
rows.Add($"\"{part.LineCode}\", \"{part.PartNumber}\", \"{string.Join(";", urls)}\"");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
await File.WriteAllLinesAsync("C:\\users\\Tommy\\desktop\\WHI Images.csv", rows);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -3,6 +3,7 @@ using System.Collections.Generic;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
@@ -29,7 +30,7 @@ namespace PartSource.Automation.Jobs.POC
|
|||||||
_shopifyClient = shopifyClient;
|
_shopifyClient = shopifyClient;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task Run()
|
public async Task Run(CancellationToken token, params string[] arguments)
|
||||||
{
|
{
|
||||||
await BuildDatabase();
|
await BuildDatabase();
|
||||||
await UpdateShopify();
|
await UpdateShopify();
|
||||||
@@ -67,7 +68,7 @@ namespace PartSource.Automation.Jobs.POC
|
|||||||
ApplicationSearchResponse response = await _nexpartService.SendRequest<ApplicationSearch, ApplicationSearchResponse>(applicationSearch);
|
ApplicationSearchResponse response = await _nexpartService.SendRequest<ApplicationSearch, ApplicationSearchResponse>(applicationSearch);
|
||||||
if (response.ResponseBody != null)
|
if (response.ResponseBody != null)
|
||||||
{
|
{
|
||||||
foreach (App app in response.ResponseBody.App)
|
foreach (App app in ((Apps)response.ResponseBody).App)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -177,7 +178,7 @@ namespace PartSource.Automation.Jobs.POC
|
|||||||
Namespace = "position",
|
Namespace = "position",
|
||||||
Key = key,
|
Key = key,
|
||||||
Value = json,
|
Value = json,
|
||||||
ValueType = "json_string",
|
Type = "json",
|
||||||
OwnerResource = "product",
|
OwnerResource = "product",
|
||||||
OwnerId = product.Id
|
OwnerId = product.Id
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,145 +0,0 @@
|
|||||||
using Microsoft.EntityFrameworkCore;
|
|
||||||
using Microsoft.Extensions.Logging;
|
|
||||||
using Newtonsoft.Json;
|
|
||||||
using PartSource.Automation.Models;
|
|
||||||
using PartSource.Data;
|
|
||||||
using PartSource.Data.Contexts;
|
|
||||||
using PartSource.Data.Models;
|
|
||||||
using PartSource.Services;
|
|
||||||
using Ratermania.Automation.Interfaces;
|
|
||||||
using Ratermania.Shopify;
|
|
||||||
using Ratermania.Shopify.Exceptions;
|
|
||||||
using Ratermania.Shopify.Resources;
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Data;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Text.RegularExpressions;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace PartSource.Automation.Jobs
|
|
||||||
{
|
|
||||||
public class UpdateFitmentHtml : IAutomationJob
|
|
||||||
{
|
|
||||||
private readonly ILogger<UpdateFitmentHtml> _logger;
|
|
||||||
private readonly ShopifyClient _shopifyClient;
|
|
||||||
private readonly PartSourceContext _partSourceContext;
|
|
||||||
private readonly FitmentContext _fitmentContext;
|
|
||||||
private readonly VehicleService _vehicleService;
|
|
||||||
|
|
||||||
public UpdateFitmentHtml(ILogger<UpdateFitmentHtml> logger, PartSourceContext partSourceContext, FitmentContext fitmentContext, ShopifyClient shopifyClient, VehicleService vehicleService)
|
|
||||||
{
|
|
||||||
_logger = logger;
|
|
||||||
_partSourceContext = partSourceContext;
|
|
||||||
_fitmentContext = fitmentContext;
|
|
||||||
_shopifyClient = shopifyClient;
|
|
||||||
_vehicleService = vehicleService;
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task Run()
|
|
||||||
{
|
|
||||||
|
|
||||||
IEnumerable<Product> products = null;
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
products = await _shopifyClient.Products.Get(new Dictionary<string, object> { { "limit", 250 }, { "vendor", "FRAM" } });
|
|
||||||
}
|
|
||||||
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
_logger.LogError("Failed to get products from Shopify", ex);
|
|
||||||
throw;
|
|
||||||
}
|
|
||||||
|
|
||||||
int i = 1;
|
|
||||||
|
|
||||||
while (products != null && products.Any())
|
|
||||||
{
|
|
||||||
foreach (Product product in products)
|
|
||||||
{
|
|
||||||
ImportData importData = null;
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
importData = await _partSourceContext.ImportData.FirstOrDefaultAsync(parts => parts.VariantSku == product.Variants[0].Sku);
|
|
||||||
|
|
||||||
if (importData == null)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
product.BodyHtml = importData.BodyHtml;
|
|
||||||
|
|
||||||
IList<Vehicle> vehicles = _vehicleService.GetVehiclesForPart(importData.PartNumber, importData.LineCode);
|
|
||||||
|
|
||||||
IList<string> ymmFitment = _vehicleService.GetYmmFitment(vehicles);
|
|
||||||
if (ymmFitment.Count > 0)
|
|
||||||
{
|
|
||||||
StringBuilder stringBuilder = new StringBuilder();
|
|
||||||
stringBuilder.AppendLine("<table><tr><th colspan=\"2\">This Part Fits</th></tr>");
|
|
||||||
|
|
||||||
foreach (string fitment in ymmFitment)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
string[] parts = fitment.Split(' ', 2);
|
|
||||||
|
|
||||||
stringBuilder.AppendLine($"<tr><td>{parts[1]}</td><td>{parts[0].Replace("-", ", ")}</td></tr>");
|
|
||||||
}
|
|
||||||
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
// This is still a POC at this point. Oh well...
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
stringBuilder.AppendLine("</table>");
|
|
||||||
|
|
||||||
product.BodyHtml += $"<div id=\"seoData\">{stringBuilder.ToString()}</div>";
|
|
||||||
}
|
|
||||||
|
|
||||||
IList<int> vehicleIdFitment = _vehicleService.GetVehicleIdFitment(vehicles);
|
|
||||||
|
|
||||||
if (vehicleIdFitment.Count > 0)
|
|
||||||
{
|
|
||||||
string vehicleIdString = string.Join('-', vehicleIdFitment.Select(j => $"v{j}"));
|
|
||||||
product.BodyHtml += $"<div id=\"vehicleIDs\" style=\"display:none;\">{vehicleIdString}</div>";
|
|
||||||
}
|
|
||||||
|
|
||||||
List<string> tags = new List<string>
|
|
||||||
{
|
|
||||||
importData.LineCode,
|
|
||||||
importData.PartNumber,
|
|
||||||
"zzzIsFitment=true"
|
|
||||||
};
|
|
||||||
|
|
||||||
product.Tags = string.Join(',', tags);
|
|
||||||
|
|
||||||
await _shopifyClient.Products.Update(product);
|
|
||||||
}
|
|
||||||
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
_logger.LogError($"Failed to updated fitment data for SKU {importData?.VariantSku} - {ex.Message}", ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
Console.WriteLine(i);
|
|
||||||
products = await _shopifyClient.Products.GetNext();
|
|
||||||
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
_logger.LogWarning(ex, "Failed to get the next set of products. Retrying");
|
|
||||||
products = await _shopifyClient.Products.GetPrevious();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,144 +0,0 @@
|
|||||||
using Microsoft.EntityFrameworkCore;
|
|
||||||
using Microsoft.Extensions.Logging;
|
|
||||||
using Newtonsoft.Json;
|
|
||||||
using PartSource.Automation.Models;
|
|
||||||
using PartSource.Data;
|
|
||||||
using PartSource.Data.Contexts;
|
|
||||||
using PartSource.Data.Dtos;
|
|
||||||
using PartSource.Data.Models;
|
|
||||||
using PartSource.Services;
|
|
||||||
using Ratermania.Automation.Interfaces;
|
|
||||||
using Ratermania.Shopify;
|
|
||||||
using Ratermania.Shopify.Exceptions;
|
|
||||||
using Ratermania.Shopify.Resources;
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Data;
|
|
||||||
using System.IO;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Text.RegularExpressions;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace PartSource.Automation.Jobs.POC
|
|
||||||
{
|
|
||||||
public class UpdateFitmentScratchpad : IAutomationJob
|
|
||||||
{
|
|
||||||
private readonly ILogger<UpdateFitmentScratchpad> _logger;
|
|
||||||
private readonly ShopifyClient _shopifyClient;
|
|
||||||
private readonly PartSourceContext _partSourceContext;
|
|
||||||
private readonly FitmentContext _fitmentContext;
|
|
||||||
private readonly VehicleService _vehicleService;
|
|
||||||
|
|
||||||
public UpdateFitmentScratchpad(ILogger<UpdateFitmentScratchpad> logger, PartSourceContext partSourceContext, FitmentContext fitmentContext, ShopifyClient shopifyClient, VehicleService vehicleService)
|
|
||||||
{
|
|
||||||
_logger = logger;
|
|
||||||
_partSourceContext = partSourceContext;
|
|
||||||
_fitmentContext = fitmentContext;
|
|
||||||
_shopifyClient = shopifyClient;
|
|
||||||
_vehicleService = vehicleService;
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task Run()
|
|
||||||
{
|
|
||||||
IList<string> productTypes = new List<string>
|
|
||||||
{
|
|
||||||
"C172-S231-F23107_(PS) Wipers - TRICO Neoform",
|
|
||||||
"CA172-SC231-FL23106_Wiper Blades - Bosch Icon",
|
|
||||||
"CA172-SC231-FL23107_(PS) Wipers - TRICO Neoform",
|
|
||||||
"CA172-SC231-FL23109_(PS) Wipers - TRICO Tech/Exact Fit",
|
|
||||||
"CA172-SC231-FL23110_Wiper Accessories",
|
|
||||||
"CA172-SC231-FL23114_Wiper Blades - Rear",
|
|
||||||
"CA172-SC231-FL23116_(PS) Wipers - Bosch Insight (Hybrid)",
|
|
||||||
"CA172-SC231-FL23117_(PS) Wipers - Bosch Clear Advantage (Beam)",
|
|
||||||
"CA172-SC231-FL23118_(PS) Wipers - Winter",
|
|
||||||
"CA172-SC231-FL23125_Wiper Blades - Bosch Areotwin"
|
|
||||||
};
|
|
||||||
|
|
||||||
IList<string> csvData = new List<string>
|
|
||||||
{
|
|
||||||
"\"Line Code\", \"Part Number\", \"Year\", \"Make\", \"Model\", \"Position\""
|
|
||||||
};
|
|
||||||
|
|
||||||
foreach (string type in productTypes)
|
|
||||||
{
|
|
||||||
IEnumerable<Product> products = null;
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
products = await _shopifyClient.Products.Get(new Dictionary<string, object> { { "limit", 250 }, { "product_type", type } });
|
|
||||||
}
|
|
||||||
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
_logger.LogError("Failed to get products from Shopify", ex);
|
|
||||||
throw;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
while (products != null && products.Any())
|
|
||||||
{
|
|
||||||
foreach (Product product in products)
|
|
||||||
{
|
|
||||||
ImportData importData = null;
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
IEnumerable<Metafield> metafields = await _shopifyClient.Metafields.Get(new Dictionary<string, object> { { "metafield[owner_id]", product.Id }, { "metafield[owner_resource]", "product" } });
|
|
||||||
|
|
||||||
importData = new ImportData
|
|
||||||
{
|
|
||||||
LineCode = metafields.FirstOrDefault(m => m.Key == "custom_label_0").Value ?? string.Empty,
|
|
||||||
PartNumber = product.Title.Split(' ')[0],
|
|
||||||
VariantSku = product.Variants[0].Sku // They know we can't do fitment for variants
|
|
||||||
};
|
|
||||||
|
|
||||||
string csvRow = product.BodyHtml.Substring(0, product.BodyHtml.IndexOf("</ul>") + "</ul>".Length);
|
|
||||||
|
|
||||||
IList<VehicleFitmentDto> vehicles = _vehicleService.GetVehicleFitmentForPart(importData.PartNumber, importData.LineCode);
|
|
||||||
|
|
||||||
if (vehicles.Count > 0)
|
|
||||||
{
|
|
||||||
foreach (VehicleFitmentDto vehicle in vehicles)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
csvData.Add($"\"{importData.LineCode}\", \"{importData.PartNumber}\", \"{vehicle.Vehicle.Year}\", \"{vehicle.Vehicle.MakeName}\", \"{vehicle.Vehicle.ModelName}\", \"{vehicle.Fitment.Position}\"");
|
|
||||||
}
|
|
||||||
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
// This is still a POC at this point. Oh well...
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
_logger.LogError($"Failed to updated fitment data for SKU {importData?.VariantSku} - {ex.Message}", ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
Console.WriteLine($"Did an iteration of {type}");
|
|
||||||
products = await _shopifyClient.Products.GetNext();
|
|
||||||
}
|
|
||||||
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
_logger.LogWarning(ex, "Failed to get the next set of products. Retrying");
|
|
||||||
products = await _shopifyClient.Products.GetPrevious();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
await File.WriteAllLinesAsync("C:\\users\\Tommy\\desktop\\Wiper Fitment.csv", csvData);
|
|
||||||
;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -3,6 +3,7 @@ using System.Collections.Generic;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
@@ -29,9 +30,9 @@ namespace PartSource.Automation.Jobs.POC
|
|||||||
_shopifyClient = shopifyClient;
|
_shopifyClient = shopifyClient;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task Run()
|
public async Task Run(CancellationToken token, params string[] arguments)
|
||||||
{
|
{
|
||||||
// await BuildDatabase();
|
await BuildDatabase();
|
||||||
await UpdateShopify();
|
await UpdateShopify();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -51,7 +52,7 @@ namespace PartSource.Automation.Jobs.POC
|
|||||||
{
|
{
|
||||||
BaseVehicleId = baseVehicleId
|
BaseVehicleId = baseVehicleId
|
||||||
},
|
},
|
||||||
MfrCode = new[] { "BOS", "TRI" },
|
MfrCode = new[] { "CSD" },
|
||||||
PartType = new[] { new PartType { Id = 8852 } },
|
PartType = new[] { new PartType { Id = 8852 } },
|
||||||
Criterion = new[]
|
Criterion = new[]
|
||||||
{
|
{
|
||||||
@@ -67,7 +68,7 @@ namespace PartSource.Automation.Jobs.POC
|
|||||||
ApplicationSearchResponse response = await _nexpartService.SendRequest<ApplicationSearch, ApplicationSearchResponse>(applicationSearch);
|
ApplicationSearchResponse response = await _nexpartService.SendRequest<ApplicationSearch, ApplicationSearchResponse>(applicationSearch);
|
||||||
if (response.ResponseBody != null)
|
if (response.ResponseBody != null)
|
||||||
{
|
{
|
||||||
foreach (App app in response.ResponseBody.App)
|
foreach (App app in ((Apps)response.ResponseBody).App)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -143,7 +144,6 @@ namespace PartSource.Automation.Jobs.POC
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//[SuppressMessage("Globalization", "CA1308:Normalize strings to uppercase", Justification = "It's a Shopify metafield key")]
|
|
||||||
private async Task SavePositionMetafield(Product product, IList<int> vehicleIds, string position)
|
private async Task SavePositionMetafield(Product product, IList<int> vehicleIds, string position)
|
||||||
{
|
{
|
||||||
if (vehicleIds.Count == 0)
|
if (vehicleIds.Count == 0)
|
||||||
@@ -169,7 +169,7 @@ namespace PartSource.Automation.Jobs.POC
|
|||||||
Namespace = "position",
|
Namespace = "position",
|
||||||
Key = key,
|
Key = key,
|
||||||
Value = json,
|
Value = json,
|
||||||
ValueType = "json_string",
|
Type = "json",
|
||||||
OwnerResource = "product",
|
OwnerResource = "product",
|
||||||
OwnerId = product.Id
|
OwnerId = product.Id
|
||||||
};
|
};
|
||||||
|
|||||||
119
PartSource.Automation/Jobs/PartialInventoryUpdate.cs
Normal file
119
PartSource.Automation/Jobs/PartialInventoryUpdate.cs
Normal file
@@ -0,0 +1,119 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Data;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.Data.SqlClient;
|
||||||
|
using Microsoft.Extensions.Configuration;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
using PartSource.Automation.Models.Configuration;
|
||||||
|
using PartSource.Automation.Models.Ftp;
|
||||||
|
using PartSource.Automation.Services;
|
||||||
|
using Ratermania.Automation.Interfaces;
|
||||||
|
|
||||||
|
namespace PartSource.Automation.Jobs
|
||||||
|
{
|
||||||
|
public class PartialInventoryUpdate : IAutomationJob
|
||||||
|
{
|
||||||
|
private readonly FtpService _ftpService;
|
||||||
|
private readonly ILogger<PartialInventoryUpdate> _logger;
|
||||||
|
private readonly string _connectionString;
|
||||||
|
|
||||||
|
public PartialInventoryUpdate(IConfiguration configuration, ILogger<PartialInventoryUpdate> logger)
|
||||||
|
{
|
||||||
|
FtpConfiguration ftpConfiguration = configuration.GetSection("FtpServers:AutomationConfiguration").Get<FtpConfiguration>();
|
||||||
|
_ftpService = new FtpService(ftpConfiguration);
|
||||||
|
|
||||||
|
_connectionString = _connectionString = configuration.GetConnectionString("PartSourceDatabase");
|
||||||
|
|
||||||
|
_logger = logger;
|
||||||
|
}
|
||||||
|
|
||||||
|
[System.Diagnostics.CodeAnalysis.SuppressMessage("Security", "CA2100:Review SQL queries for security vulnerabilities")]
|
||||||
|
public async Task Run(CancellationToken token, params string[] arguments)
|
||||||
|
{
|
||||||
|
FtpFileInfo lastUploadedFile = _ftpService.ListFilesExtended()
|
||||||
|
.Where(f => f.FileType == FtpFileType.File && f.Filename.IndexOf("Availability Partial") > -1)
|
||||||
|
.OrderByDescending(f => f.Modified)
|
||||||
|
.FirstOrDefault();
|
||||||
|
|
||||||
|
if (lastUploadedFile == null)
|
||||||
|
{
|
||||||
|
_logger.LogInformation($"No partial inventory file available.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_logger.LogInformation("Processing {filename}", lastUploadedFile.Filename);
|
||||||
|
|
||||||
|
string file = _ftpService.Download($"{lastUploadedFile.Filename}");
|
||||||
|
|
||||||
|
using SqlConnection connection = new SqlConnection(_connectionString);
|
||||||
|
connection.Open();
|
||||||
|
|
||||||
|
using StreamReader reader = new StreamReader(file);
|
||||||
|
string line = reader.ReadLine(); // Burn the header row
|
||||||
|
|
||||||
|
IDictionary<string, object> parameters = new Dictionary<string, object>();
|
||||||
|
string command = string.Empty;
|
||||||
|
int i = 0;
|
||||||
|
|
||||||
|
while (reader.Peek() > 0)
|
||||||
|
{
|
||||||
|
line = reader.ReadLine();
|
||||||
|
|
||||||
|
string[] columns = line.Split("|");
|
||||||
|
for (int j = 0; j < columns.Length; j++)
|
||||||
|
{
|
||||||
|
columns[j] = columns[j].Replace("\"", string.Empty);
|
||||||
|
}
|
||||||
|
string sku = columns[1].Trim();
|
||||||
|
string updated = columns[3].Trim();
|
||||||
|
|
||||||
|
if (int.TryParse(columns[0], out int store)
|
||||||
|
&& !string.IsNullOrEmpty(sku)
|
||||||
|
&& int.TryParse(columns[2], out int quantity)
|
||||||
|
&& !string.IsNullOrEmpty(updated))
|
||||||
|
{
|
||||||
|
command += $"UPDATE PartAvailability SET QTY = @qty_{i}, Updated = @updated_{i} WHERE SKU = @sku_{i} AND Store = @store_{i};";
|
||||||
|
|
||||||
|
parameters.Add($"qty_{i}", quantity);
|
||||||
|
parameters.Add($"store_{i}", store);
|
||||||
|
parameters.Add($"sku_{i}", sku);
|
||||||
|
parameters.Add($"updated_{i}", updated);
|
||||||
|
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i == 250)
|
||||||
|
{
|
||||||
|
using SqlCommand nested = new SqlCommand(command, connection);
|
||||||
|
foreach (KeyValuePair<string, object> parameter in parameters)
|
||||||
|
{
|
||||||
|
nested.Parameters.Add(new SqlParameter(parameter.Key, parameter.Value));
|
||||||
|
}
|
||||||
|
|
||||||
|
await nested.ExecuteNonQueryAsync(token);
|
||||||
|
|
||||||
|
parameters.Clear();
|
||||||
|
command = string.Empty;
|
||||||
|
i = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
using SqlCommand sqlCommand = new SqlCommand(command, connection);
|
||||||
|
foreach (KeyValuePair<string, object> parameter in parameters)
|
||||||
|
{
|
||||||
|
sqlCommand.Parameters.Add(new SqlParameter(parameter.Key, parameter.Value));
|
||||||
|
}
|
||||||
|
|
||||||
|
await sqlCommand.ExecuteNonQueryAsync(token);
|
||||||
|
|
||||||
|
_ftpService.Delete(lastUploadedFile.Filename);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
89
PartSource.Automation/Jobs/PartsSync.cs
Normal file
89
PartSource.Automation/Jobs/PartsSync.cs
Normal file
@@ -0,0 +1,89 @@
|
|||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
using PartSource.Automation.Models.Jobs;
|
||||||
|
using PartSource.Automation.Services;
|
||||||
|
using PartSource.Data.Contexts;
|
||||||
|
using PartSource.Data.Models;
|
||||||
|
using Ratermania.Automation.Interfaces;
|
||||||
|
using Ratermania.Shopify;
|
||||||
|
using Ratermania.Shopify.Resources;
|
||||||
|
using Ratermania.Shopify.Resources.Enums;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Net.Mail;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace PartSource.Automation.Jobs
|
||||||
|
{
|
||||||
|
public class PartsSync : IAutomationJob
|
||||||
|
{
|
||||||
|
private readonly ILogger<UpdatePricing> _logger;
|
||||||
|
private readonly FitmentContext _fitmentContext;
|
||||||
|
private readonly ShopifyClient _shopifyClient;
|
||||||
|
|
||||||
|
public PartsSync(ILogger<UpdatePricing> logger, FitmentContext fitmentContext, ShopifyClient shopifyClient)
|
||||||
|
{
|
||||||
|
_logger = logger;
|
||||||
|
_fitmentContext = fitmentContext;
|
||||||
|
_shopifyClient = shopifyClient;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task Run(CancellationToken token, params string[] arguments)
|
||||||
|
{
|
||||||
|
IEnumerable<Product> products = await _shopifyClient.Products.Get(new Dictionary<string, object> { { "limit", 250 } });
|
||||||
|
|
||||||
|
while (products != null && products.Any())
|
||||||
|
{
|
||||||
|
|
||||||
|
foreach (Product product in products)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
IEnumerable<Metafield> metafields = await _shopifyClient.Metafields.Get(new Dictionary<string, object> { { "metafield[owner_id]", product.Id }, { "metafield[owner_resource]", "product" } });
|
||||||
|
Part part = new Part
|
||||||
|
{
|
||||||
|
LineCode = metafields.FirstOrDefault(m => m.Key == "custom_label_0")?.Value ?? string.Empty,
|
||||||
|
PartNumber = metafields.FirstOrDefault(m => m.Key == "custom_label_1")?.Value ?? string.Empty,
|
||||||
|
Sku = product.Variants[0].Sku // They know we can't do fitment for variants
|
||||||
|
};
|
||||||
|
|
||||||
|
// part.PartNumber = part.PartNumber.Replace("-", string.Empty);
|
||||||
|
|
||||||
|
if (
|
||||||
|
string.IsNullOrEmpty(part.LineCode)
|
||||||
|
|| string.IsNullOrEmpty(part.PartNumber)
|
||||||
|
|| int.TryParse(part.LineCode, out _)) //If the line code is numeric, it cannot have fitment data associated with it.
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
Part? existing = await _fitmentContext.Parts.FirstOrDefaultAsync(p => p.Sku == part.Sku);
|
||||||
|
if (existing == null)
|
||||||
|
{
|
||||||
|
await _fitmentContext.Parts.AddAsync(part);
|
||||||
|
await _fitmentContext.SaveChangesAsync();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogInformation(ex.Message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
products = await _shopifyClient.Products.GetNext();
|
||||||
|
}
|
||||||
|
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogInformation(ex.Message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -14,167 +14,171 @@ using System.Linq;
|
|||||||
using System.Security.Cryptography;
|
using System.Security.Cryptography;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace PartSource.Automation.Jobs
|
namespace PartSource.Automation.Jobs
|
||||||
{
|
{
|
||||||
public class ProcessWhiFitment : IAutomationJob
|
public class ProcessWhiFitment : IAutomationJob
|
||||||
{
|
{
|
||||||
private readonly ILogger<ProcessWhiFitment> _logger;
|
private readonly ILogger<ProcessWhiFitment> _logger;
|
||||||
private readonly WhiSeoService _whiSeoService;
|
private readonly WhiSeoService _whiSeoService;
|
||||||
private readonly FtpConfiguration _ftpConfiguration;
|
private readonly FtpConfiguration _ftpConfiguration;
|
||||||
private readonly SeoDataType _seoDataType;
|
private readonly SeoDataType _seoDataType;
|
||||||
|
|
||||||
private readonly IDictionary<string, string> _noteDictionary;
|
private readonly IDictionary<string, string> _noteDictionary;
|
||||||
|
|
||||||
public ProcessWhiFitment(IConfiguration configuration, ILogger<ProcessWhiFitment> logger, WhiSeoService whiSeoService)
|
public ProcessWhiFitment(IConfiguration configuration, ILogger<ProcessWhiFitment> logger, WhiSeoService whiSeoService)
|
||||||
{
|
{
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
_whiSeoService = whiSeoService;
|
_whiSeoService = whiSeoService;
|
||||||
|
|
||||||
_seoDataType = SeoDataType.Fitment;
|
_seoDataType = SeoDataType.Fitment;
|
||||||
|
|
||||||
_ftpConfiguration = configuration.GetSection("ftpServers:WhiConfiguration").Get<FtpConfiguration>();
|
_ftpConfiguration = configuration.GetSection("ftpServers:WhiConfiguration").Get<FtpConfiguration>();
|
||||||
|
|
||||||
_noteDictionary = new ConcurrentDictionary<string, string>();
|
_noteDictionary = new ConcurrentDictionary<string, string>();
|
||||||
}
|
}
|
||||||
|
|
||||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Reliability", "CA2008:Do not create tasks without passing a TaskScheduler", Justification = "<Pending>")]
|
[System.Diagnostics.CodeAnalysis.SuppressMessage("Reliability", "CA2008:Do not create tasks without passing a TaskScheduler", Justification = "<Pending>")]
|
||||||
public async Task Run()
|
public async Task Run(CancellationToken token, params string[] arguments)
|
||||||
{
|
{
|
||||||
_whiSeoService.TruncateFitmentTables();
|
_whiSeoService.TruncateFitmentTables();
|
||||||
// _whiSeoService.GetFiles(_seoDataType);
|
_whiSeoService.GetFiles(_seoDataType);
|
||||||
|
|
||||||
string directory = Path.Combine(_ftpConfiguration.Destination, _seoDataType.ToString().ToLowerInvariant());
|
string directory = Path.Combine(_ftpConfiguration.Destination, _seoDataType.ToString().ToLowerInvariant());
|
||||||
DirectoryInfo directoryInfo = new DirectoryInfo(directory);
|
DirectoryInfo directoryInfo = new DirectoryInfo(directory);
|
||||||
|
|
||||||
ConcurrentQueue<IGrouping<string, FileInfo>> fileGroups = new ConcurrentQueue<IGrouping<string, FileInfo>>();
|
ConcurrentQueue<IGrouping<string, FileInfo>> fileGroups = new ConcurrentQueue<IGrouping<string, FileInfo>>();
|
||||||
|
|
||||||
foreach (IGrouping<string, FileInfo> fileGroup in directoryInfo.GetFiles().Where(f => f.Name.EndsWith("csv.gz")).GroupBy(x => x.Name.Split('_').Last()))
|
foreach (IGrouping<string, FileInfo> fileGroup in directoryInfo.GetFiles().Where(f => f.Name.EndsWith("csv.gz")).GroupBy(x => x.Name.Split('_').Last()))
|
||||||
{
|
{
|
||||||
fileGroups.Enqueue(fileGroup);
|
fileGroups.Enqueue(fileGroup);
|
||||||
}
|
}
|
||||||
|
|
||||||
Task[] taskArray = new Task[8];
|
Task[] taskArray = new Task[18];
|
||||||
|
for (int i = 0; i < taskArray.Length; i++)
|
||||||
|
{
|
||||||
|
taskArray[i] = Task.Factory.StartNew(() =>
|
||||||
|
{
|
||||||
|
while (fileGroups.TryDequeue(out IGrouping<string, FileInfo> fileGroup))
|
||||||
|
{
|
||||||
|
string tableName = string.Empty;
|
||||||
|
|
||||||
for (int i = 0; i < taskArray.Length; i++)
|
foreach (FileInfo fileInfo in fileGroup)
|
||||||
{
|
{
|
||||||
taskArray[i] = Task.Factory.StartNew(() =>
|
try
|
||||||
{
|
{
|
||||||
while (fileGroups.TryDequeue(out IGrouping<string, FileInfo> fileGroup))
|
string filename = Decompress(fileInfo);
|
||||||
{
|
DataTable dataTable = GetDataTable(filename, out tableName);
|
||||||
foreach (FileInfo fileInfo in fileGroup)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
string filename = Decompress(fileInfo);
|
|
||||||
string tableName = fileInfo.Name.Substring(0, fileInfo.Name.IndexOf('.'));
|
|
||||||
|
|
||||||
DataTable dataTable = GetDataTable(filename);
|
string tempTable = $"Fitment_{Guid.NewGuid():N}_{tableName}";
|
||||||
|
|
||||||
_whiSeoService.BulkCopyFitment(dataTable, tableName);
|
_whiSeoService.BulkCopyFitment(dataTable, tempTable);
|
||||||
_logger.LogInformation($"Copied {fileInfo.Name} to the database.");
|
_logger.LogInformation($"Copied {fileInfo.Name} to the database.");
|
||||||
|
|
||||||
File.Delete(filename);
|
File.Delete(filename);
|
||||||
}
|
}
|
||||||
|
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
_logger.LogError($"Failed to write {fileInfo.Name} to the database - {ex.Message}", ex);
|
_logger.LogError($"Failed to write {fileInfo.Name} to the database - {ex.Message}", ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
string fitmentTable = fileGroup.Key.Substring(0, fileGroup.Key.IndexOf('.'));
|
_whiSeoService.CreateFitmentTable(tableName);
|
||||||
_whiSeoService.CreateFitmentTable(fitmentTable);
|
|
||||||
|
|
||||||
_logger.LogInformation($"Created fitment table for part group {fitmentTable}.");
|
_logger.LogInformation($"Created fitment table for part group {tableName}.");
|
||||||
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
Task.WaitAll(taskArray);
|
Task.WaitAll(taskArray);
|
||||||
|
_whiSeoService.SaveNotes(_noteDictionary);
|
||||||
|
|
||||||
_whiSeoService.CreateFitmentView();
|
_whiSeoService.CreateFitmentView();
|
||||||
|
}
|
||||||
|
|
||||||
_whiSeoService.SaveNotes(_noteDictionary);
|
public string Decompress(FileInfo fileInfo)
|
||||||
}
|
{
|
||||||
|
string decompressedFile = fileInfo.FullName.Remove(fileInfo.FullName.Length - fileInfo.Extension.Length);
|
||||||
|
|
||||||
public string Decompress(FileInfo fileInfo)
|
using FileStream filestream = File.Create(decompressedFile);
|
||||||
{
|
using GZipStream decompressionStream = new GZipStream(fileInfo.OpenRead(), CompressionMode.Decompress);
|
||||||
string decompressedFile = fileInfo.FullName.Remove(fileInfo.FullName.Length - fileInfo.Extension.Length);
|
|
||||||
|
|
||||||
using FileStream filestream = File.Create(decompressedFile);
|
decompressionStream.CopyTo(filestream);
|
||||||
using GZipStream decompressionStream = new GZipStream(fileInfo.OpenRead(), CompressionMode.Decompress);
|
|
||||||
|
|
||||||
decompressionStream.CopyTo(filestream);
|
return decompressedFile;
|
||||||
|
}
|
||||||
|
|
||||||
return decompressedFile;
|
private DataTable GetDataTable(string filename, out string lineCode)
|
||||||
}
|
{
|
||||||
|
lineCode = string.Empty;
|
||||||
|
|
||||||
private DataTable GetDataTable(string filename)
|
using DataTable dataTable = new DataTable();
|
||||||
{
|
dataTable.Columns.Add("LineCode", typeof(string));
|
||||||
using DataTable dataTable = new DataTable();
|
dataTable.Columns.Add("PartNumber", typeof(string));
|
||||||
dataTable.Columns.Add("LineCode", typeof(string));
|
dataTable.Columns.Add("BaseVehicleId", typeof(int));
|
||||||
dataTable.Columns.Add("PartNumber", typeof(string));
|
dataTable.Columns.Add("EngineConfigId", typeof(int));
|
||||||
dataTable.Columns.Add("BaseVehicleId", typeof(int));
|
dataTable.Columns.Add("Position", typeof(string));
|
||||||
dataTable.Columns.Add("EngineConfigId", typeof(int));
|
dataTable.Columns.Add("FitmentNoteHash", typeof(string));
|
||||||
dataTable.Columns.Add("Position", typeof(string));
|
dataTable.Columns.Add("PartTerminologyId", typeof(int));
|
||||||
dataTable.Columns.Add("FitmentNoteHash", typeof(string));
|
|
||||||
|
|
||||||
using StreamReader reader = new StreamReader(filename);
|
using StreamReader reader = new StreamReader(filename);
|
||||||
string line = reader.ReadLine(); // Burn the header row
|
string line = reader.ReadLine(); // Burn the header row
|
||||||
|
|
||||||
while (reader.Peek() > 0)
|
while (reader.Peek() > 0)
|
||||||
{
|
{
|
||||||
line = reader.ReadLine();
|
line = reader.ReadLine();
|
||||||
|
|
||||||
string[] columns = line.Split("\",\"");
|
string[] columns = line.Split("\",\"");
|
||||||
for (int i = 0; i < columns.Length; i++)
|
for (int i = 0; i < columns.Length; i++)
|
||||||
{
|
{
|
||||||
columns[i] = columns[i].Replace("\"", string.Empty);
|
columns[i] = columns[i].Replace("\"", string.Empty);
|
||||||
}
|
}
|
||||||
|
|
||||||
string lineCode = Regex.Replace(columns[0], "[^a-zA-Z0-9]", string.Empty).Trim();
|
lineCode = Regex.Replace(columns[0], "[^a-zA-Z0-9]", string.Empty).Trim();
|
||||||
string partNumber = Regex.Replace(columns[1], "[^a-zA-Z0-9]", string.Empty).Trim();
|
string partNumber = Regex.Replace(columns[1], "[^a-zA-Z0-9]", string.Empty).Trim();
|
||||||
string position = columns[7].Trim();
|
string position = columns[7].Trim();
|
||||||
|
|
||||||
string noteText = columns[4].Trim();
|
string noteText = columns[4].Trim();
|
||||||
string noteTextHash = GetMD5Hash(noteText);
|
string noteTextHash = GetMD5Hash(noteText);
|
||||||
|
|
||||||
if (!_noteDictionary.ContainsKey(noteTextHash))
|
if (!_noteDictionary.ContainsKey(noteTextHash))
|
||||||
{
|
{
|
||||||
_noteDictionary.Add(noteTextHash, noteText);
|
_noteDictionary.Add(noteTextHash, noteText);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(lineCode)
|
if (!string.IsNullOrEmpty(lineCode)
|
||||||
&& !string.IsNullOrEmpty(partNumber)
|
&& !string.IsNullOrEmpty(partNumber)
|
||||||
&& int.TryParse(columns[5], out int baseVehicleId)
|
&& int.TryParse(columns[2], out int partTerminologyId)
|
||||||
&& int.TryParse(columns[6], out int engineConfigId))
|
&& int.TryParse(columns[5], out int baseVehicleId)
|
||||||
{
|
&& int.TryParse(columns[6], out int engineConfigId))
|
||||||
dataTable.Rows.Add(new object[] { lineCode, partNumber, baseVehicleId, engineConfigId, position, noteTextHash });
|
{
|
||||||
}
|
dataTable.Rows.Add(new object[] { lineCode, partNumber, baseVehicleId, engineConfigId, position, noteTextHash, partTerminologyId });
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return dataTable;
|
return dataTable;
|
||||||
}
|
}
|
||||||
|
|
||||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Security", "CA5351:Do Not Use Broken Cryptographic Algorithms", Justification = "Not used for security")]
|
[System.Diagnostics.CodeAnalysis.SuppressMessage("Security", "CA5351:Do Not Use Broken Cryptographic Algorithms", Justification = "Not used for security")]
|
||||||
private string GetMD5Hash(string input)
|
private string GetMD5Hash(string input)
|
||||||
{
|
{
|
||||||
using MD5 md5 = MD5.Create();
|
using MD5 md5 = MD5.Create();
|
||||||
|
|
||||||
byte[] inputBytes = Encoding.UTF8.GetBytes(input);
|
byte[] inputBytes = Encoding.UTF8.GetBytes(input);
|
||||||
byte[] hashBytes = md5.ComputeHash(inputBytes);
|
byte[] hashBytes = md5.ComputeHash(inputBytes);
|
||||||
|
|
||||||
StringBuilder stringBuilder = new StringBuilder();
|
StringBuilder stringBuilder = new StringBuilder();
|
||||||
|
|
||||||
for (int i = 0; i < hashBytes.Length; i++)
|
for (int i = 0; i < hashBytes.Length; i++)
|
||||||
{
|
{
|
||||||
stringBuilder.Append(hashBytes[i].ToString("X2"));
|
stringBuilder.Append(hashBytes[i].ToString("X2"));
|
||||||
}
|
}
|
||||||
|
|
||||||
return stringBuilder.ToString();
|
return stringBuilder.ToString();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,134 +1,134 @@
|
|||||||
using Microsoft.Extensions.Configuration;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Data;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.Extensions.Configuration;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
|
using PartSource.Automation.Extensions;
|
||||||
using PartSource.Automation.Models.Configuration;
|
using PartSource.Automation.Models.Configuration;
|
||||||
using PartSource.Automation.Models.Enums;
|
using PartSource.Automation.Models.Enums;
|
||||||
using PartSource.Automation.Services;
|
using PartSource.Automation.Services;
|
||||||
using Ratermania.Automation.Interfaces;
|
using Ratermania.Automation.Interfaces;
|
||||||
using System;
|
|
||||||
using System.Collections.Concurrent;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Data;
|
|
||||||
using System.IO;
|
|
||||||
using System.IO.Compression;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Security.Cryptography;
|
|
||||||
using System.Text;
|
|
||||||
using System.Text.RegularExpressions;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace PartSource.Automation.Jobs
|
namespace PartSource.Automation.Jobs
|
||||||
{
|
{
|
||||||
public class ProcessWhiVehicles : IAutomationJob
|
public class ProcessWhiVehicles : IAutomationJob
|
||||||
{
|
{
|
||||||
private readonly ILogger<ProcessWhiVehicles> _logger;
|
private readonly ILogger<ProcessWhiVehicles> _logger;
|
||||||
private readonly WhiSeoService _whiSeoService;
|
private readonly WhiSeoService _whiSeoService;
|
||||||
private readonly FtpConfiguration _ftpConfiguration;
|
private readonly FtpConfiguration _ftpConfiguration;
|
||||||
private readonly SeoDataType _seoDataType;
|
private readonly SeoDataType _seoDataType;
|
||||||
|
|
||||||
public ProcessWhiVehicles(IConfiguration configuration, ILogger<ProcessWhiVehicles> logger, WhiSeoService whiSeoService)
|
public ProcessWhiVehicles(IConfiguration configuration, ILogger<ProcessWhiVehicles> logger, WhiSeoService whiSeoService)
|
||||||
{
|
{
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
_whiSeoService = whiSeoService;
|
_whiSeoService = whiSeoService;
|
||||||
|
|
||||||
_seoDataType = SeoDataType.Vehicle;
|
_seoDataType = SeoDataType.Vehicle;
|
||||||
|
|
||||||
_ftpConfiguration = configuration.GetSection("ftpServers:WhiConfiguration").Get<FtpConfiguration>();
|
_ftpConfiguration = configuration.GetSection("ftpServers:WhiConfiguration").Get<FtpConfiguration>();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task Run()
|
public async Task Run(CancellationToken token, params string[] arguments)
|
||||||
{
|
{
|
||||||
_whiSeoService.TruncateVehicleTables();
|
_whiSeoService.TruncateVehicleTable();
|
||||||
_whiSeoService.GetFiles(_seoDataType);
|
_whiSeoService.GetFiles(_seoDataType);
|
||||||
|
|
||||||
string directory = Path.Combine(_ftpConfiguration.Destination, _seoDataType.ToString().ToLowerInvariant());
|
string directory = Path.Combine(_ftpConfiguration.Destination, _seoDataType.ToString().ToLowerInvariant());
|
||||||
DirectoryInfo directoryInfo = new DirectoryInfo(directory);
|
DirectoryInfo directoryInfo = new DirectoryInfo(directory);
|
||||||
|
|
||||||
IEnumerable<FileInfo> files = directoryInfo.GetFiles().Where(f => f.Name.StartsWith("seo_aces_vehicle_feed"));
|
IEnumerable<FileInfo> files = directoryInfo.GetFiles()
|
||||||
|
.Where(f => f.Name.StartsWith("seo_aces_vehicle_feed"))
|
||||||
|
.OrderByDescending(f => f.GetWhiTimestamp());
|
||||||
|
|
||||||
foreach (FileInfo fileInfo in files)
|
foreach (FileInfo fileInfo in files)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
string tableName = fileInfo.Name.Substring(0, fileInfo.Name.IndexOf('.'));
|
string tableName = fileInfo.Name.Substring(0, fileInfo.Name.IndexOf('.'));
|
||||||
|
|
||||||
DataTable dataTable = GetDataTable(fileInfo.FullName);
|
DataTable dataTable = GetDataTable(fileInfo.FullName);
|
||||||
|
|
||||||
_whiSeoService.BulkCopyVehicle(dataTable, tableName);
|
_whiSeoService.BulkCopyVehicle(dataTable, tableName);
|
||||||
_logger.LogInformation($"Copied {fileInfo.Name} to the database.");
|
_logger.LogInformation($"Copied {fileInfo.Name} to the database.");
|
||||||
|
|
||||||
File.Delete(fileInfo.FullName);
|
File.Delete(fileInfo.FullName);
|
||||||
}
|
}
|
||||||
|
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
_logger.LogError($"Failed to write {fileInfo.Name} to the database - {ex.Message}", ex);
|
_logger.LogError($"Failed to write {fileInfo.Name} to the database - {ex.Message}", ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_whiSeoService.CreateVehicleTable();
|
_whiSeoService.CreateVehicleTable();
|
||||||
|
|
||||||
_logger.LogInformation($"Created vehicle table.");
|
_logger.LogInformation($"Created vehicle table.");
|
||||||
}
|
}
|
||||||
|
|
||||||
private DataTable GetDataTable(string filename)
|
private DataTable GetDataTable(string filename)
|
||||||
{
|
{
|
||||||
using DataTable dataTable = new DataTable();
|
using DataTable dataTable = new DataTable();
|
||||||
dataTable.Columns.Add("Year", typeof(int));
|
dataTable.Columns.Add("Year", typeof(int));
|
||||||
dataTable.Columns.Add("MakeId", typeof(int));
|
dataTable.Columns.Add("MakeId", typeof(int));
|
||||||
dataTable.Columns.Add("MakeName", typeof(string));
|
dataTable.Columns.Add("MakeName", typeof(string));
|
||||||
dataTable.Columns.Add("ModelId", typeof(int));
|
dataTable.Columns.Add("ModelId", typeof(int));
|
||||||
dataTable.Columns.Add("ModelName", typeof(string));
|
dataTable.Columns.Add("ModelName", typeof(string));
|
||||||
dataTable.Columns.Add("RegionId", typeof(int));
|
dataTable.Columns.Add("RegionId", typeof(int));
|
||||||
dataTable.Columns.Add("RegionName", typeof(string));
|
dataTable.Columns.Add("RegionName", typeof(string));
|
||||||
dataTable.Columns.Add("VehicleTypeId", typeof(int));
|
dataTable.Columns.Add("VehicleTypeId", typeof(int));
|
||||||
dataTable.Columns.Add("EngineConfigId", typeof(int));
|
dataTable.Columns.Add("EngineConfigId", typeof(int));
|
||||||
dataTable.Columns.Add("EngineDescription", typeof(string));
|
dataTable.Columns.Add("EngineDescription", typeof(string));
|
||||||
dataTable.Columns.Add("BaseVehicleId", typeof(int));
|
dataTable.Columns.Add("BaseVehicleId", typeof(int));
|
||||||
dataTable.Columns.Add("VehicleToEngineConfigId", typeof(int));
|
dataTable.Columns.Add("VehicleToEngineConfigId", typeof(int));
|
||||||
dataTable.Columns.Add("SubmodelId", typeof(int));
|
dataTable.Columns.Add("SubmodelId", typeof(int));
|
||||||
dataTable.Columns.Add("SubmodelName", typeof(string));
|
dataTable.Columns.Add("SubmodelName", typeof(string));
|
||||||
|
|
||||||
using StreamReader reader = new StreamReader(filename);
|
using StreamReader reader = new StreamReader(filename);
|
||||||
string line = reader.ReadLine(); // Burn the header row
|
string line = reader.ReadLine(); // Burn the header row
|
||||||
|
|
||||||
while (reader.Peek() > 0)
|
while (reader.Peek() > 0)
|
||||||
{
|
{
|
||||||
line = reader.ReadLine();
|
line = reader.ReadLine();
|
||||||
|
|
||||||
string[] columns = line.Split("\",\"");
|
string[] columns = line.Split("\",\"");
|
||||||
for (int i = 0; i < columns.Length; i++)
|
for (int i = 0; i < columns.Length; i++)
|
||||||
{
|
{
|
||||||
columns[i] = columns[i].Replace("\"", string.Empty);
|
columns[i] = columns[i].Replace("\"", string.Empty);
|
||||||
}
|
}
|
||||||
|
|
||||||
string makeName = columns[4].Trim();
|
string makeName = columns[4].Trim();
|
||||||
string modelName = columns[6].Trim();
|
string modelName = columns[6].Trim();
|
||||||
string regionName = columns[8].Trim();
|
string regionName = columns[8].Trim();
|
||||||
string submodelName = columns[34].Trim();
|
string submodelName = columns[34].Trim();
|
||||||
string engineDescription = columns[51].Trim();
|
string engineDescription = columns[51].Trim();
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(makeName)
|
if (!string.IsNullOrEmpty(makeName)
|
||||||
&& !string.IsNullOrEmpty(modelName)
|
&& !string.IsNullOrEmpty(modelName)
|
||||||
&& !string.IsNullOrEmpty(regionName)
|
&& !string.IsNullOrEmpty(submodelName)
|
||||||
&& !string.IsNullOrEmpty(submodelName)
|
&& !string.IsNullOrEmpty(engineDescription)
|
||||||
&& !string.IsNullOrEmpty(engineDescription)
|
&& int.TryParse(columns[0], out int baseVehicleId)
|
||||||
&& int.TryParse(columns[0], out int baseVehicleId)
|
&& int.TryParse(columns[2], out int year)
|
||||||
&& int.TryParse(columns[2], out int year)
|
&& int.TryParse(columns[3], out int makeId)
|
||||||
&& int.TryParse(columns[3], out int makeId)
|
&& int.TryParse(columns[5], out int modelId)
|
||||||
&& int.TryParse(columns[5], out int modelId)
|
&& int.TryParse(columns[7], out int regionId)
|
||||||
&& int.TryParse(columns[7], out int regionId)
|
&& int.TryParse(columns[9], out int vehicleTypeId)
|
||||||
&& int.TryParse(columns[9], out int vehicleTypeId)
|
&& int.TryParse(columns[33], out int submodelId)
|
||||||
&& int.TryParse(columns[33], out int submodelId)
|
&& int.TryParse(columns[35], out int engineConfigId)
|
||||||
&& int.TryParse(columns[35], out int engineConfigId)
|
&& int.TryParse(columns[36], out int vehicleToEngineConfigId))
|
||||||
&& int.TryParse(columns[36], out int vehicleToEngineConfigId)
|
{
|
||||||
&& new[] { 5, 6, 7 }.Contains(vehicleTypeId))
|
if (regionId == 2 && new[] { 5, 6, 7 }.Contains(vehicleTypeId))
|
||||||
{
|
{
|
||||||
dataTable.Rows.Add(new object[] { year, makeId, makeName, modelId, modelName, regionId, regionName, vehicleTypeId, engineConfigId, engineDescription, baseVehicleId, vehicleToEngineConfigId, submodelId, submodelName });
|
dataTable.Rows.Add(new object[] { year, makeId, makeName, modelId, modelName, regionId, regionName, vehicleTypeId, engineConfigId, engineDescription, baseVehicleId, vehicleToEngineConfigId, submodelId, submodelName });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return dataTable;
|
return dataTable;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
using PartSource.Automation.Models;
|
using PartSource.Automation.Models;
|
||||||
using PartSource.Automation.Services;
|
using PartSource.Automation.Services;
|
||||||
using Ratermania.Automation.Interfaces;
|
using Ratermania.Automation.Interfaces;
|
||||||
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace PartSource.Automation.Jobs
|
namespace PartSource.Automation.Jobs
|
||||||
@@ -15,7 +16,7 @@ namespace PartSource.Automation.Jobs
|
|||||||
_emailService = emailService;
|
_emailService = emailService;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task Run()
|
public async Task Run(CancellationToken token, params string[] arguments)
|
||||||
{
|
{
|
||||||
foreach (string phoneNumber in phoneNumbers)
|
foreach (string phoneNumber in phoneNumbers)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ using System.Text;
|
|||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using PartSource.Automation.Services;
|
using PartSource.Automation.Services;
|
||||||
|
using System.Threading;
|
||||||
|
|
||||||
namespace PartSource.Automation.Jobs
|
namespace PartSource.Automation.Jobs
|
||||||
{
|
{
|
||||||
@@ -21,9 +22,9 @@ namespace PartSource.Automation.Jobs
|
|||||||
}
|
}
|
||||||
|
|
||||||
#pragma warning disable CS1998, CA1303
|
#pragma warning disable CS1998, CA1303
|
||||||
public async Task Run()
|
public async Task Run(CancellationToken token, params string[] arguments)
|
||||||
{
|
{
|
||||||
// _emailService.Send("Automation Test Message", "This is a test email from the automation server. If this message was in your spam folder, whitelist the address that sent this email.");
|
_emailService.Send("Automation Test Message", "This is a test email from the automation server. If this message was in your spam folder, whitelist the address that sent this email.");
|
||||||
|
|
||||||
_logger.LogInformation("Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc scelerisque congue euismod. Curabitur enim eros, sollicitudin ac purus eget, dignissim mattis augue. In quam sapien, tincidunt et elementum vitae, interdum vitae sem.");
|
_logger.LogInformation("Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc scelerisque congue euismod. Curabitur enim eros, sollicitudin ac purus eget, dignissim mattis augue. In quam sapien, tincidunt et elementum vitae, interdum vitae sem.");
|
||||||
_logger.LogWarning("Praesent feugiat sapien non suscipit faucibus. Mauris fermentum ut augue a feugiat. Integer felis sem, laoreet et augue at, finibus maximus ex. Fusce sit amet erat non tortor porta condimentum condimentum quis ipsum.");
|
_logger.LogWarning("Praesent feugiat sapien non suscipit faucibus. Mauris fermentum ut augue a feugiat. Integer felis sem, laoreet et augue at, finibus maximus ex. Fusce sit amet erat non tortor porta condimentum condimentum quis ipsum.");
|
||||||
|
|||||||
@@ -1,22 +1,20 @@
|
|||||||
using Microsoft.EntityFrameworkCore;
|
using System;
|
||||||
using Microsoft.Extensions.Logging;
|
|
||||||
using Newtonsoft.Json;
|
|
||||||
using PartSource.Automation.Models;
|
|
||||||
using PartSource.Data;
|
|
||||||
using PartSource.Data.Contexts;
|
|
||||||
using PartSource.Data.Models;
|
|
||||||
using PartSource.Services;
|
|
||||||
using Ratermania.Automation.Interfaces;
|
|
||||||
using Ratermania.Shopify;
|
|
||||||
using Ratermania.Shopify.Exceptions;
|
|
||||||
using Ratermania.Shopify.Resources;
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Data;
|
using System.Data;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Text.RegularExpressions;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
using PartSource.Automation.Services;
|
||||||
|
using PartSource.Data.Contexts;
|
||||||
|
using PartSource.Data.Models;
|
||||||
|
using Ratermania.Automation.Interfaces;
|
||||||
|
using Ratermania.Shopify;
|
||||||
|
using Ratermania.Shopify.Resources;
|
||||||
|
using System.Web;
|
||||||
|
|
||||||
namespace PartSource.Automation.Jobs
|
namespace PartSource.Automation.Jobs
|
||||||
{
|
{
|
||||||
@@ -26,221 +24,164 @@ namespace PartSource.Automation.Jobs
|
|||||||
private readonly ShopifyClient _shopifyClient;
|
private readonly ShopifyClient _shopifyClient;
|
||||||
private readonly PartSourceContext _partSourceContext;
|
private readonly PartSourceContext _partSourceContext;
|
||||||
private readonly FitmentContext _fitmentContext;
|
private readonly FitmentContext _fitmentContext;
|
||||||
private readonly VehicleService _vehicleService;
|
private readonly VehicleFitmentService _vehicleFitmentService;
|
||||||
|
|
||||||
public UpdateFitment(ILogger<UpdateFitment> logger, PartSourceContext partSourceContext, FitmentContext fitmentContext, ShopifyClient shopifyClient, VehicleService vehicleService)
|
public UpdateFitment(ILogger<UpdateFitment> logger, PartSourceContext partSourceContext, FitmentContext fitmentContext, ShopifyClient shopifyClient, VehicleFitmentService vehicleFitmentService)
|
||||||
{
|
{
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
_partSourceContext = partSourceContext;
|
_partSourceContext = partSourceContext;
|
||||||
_fitmentContext = fitmentContext;
|
_fitmentContext = fitmentContext;
|
||||||
_shopifyClient = shopifyClient;
|
_shopifyClient = shopifyClient;
|
||||||
_vehicleService = vehicleService;
|
_vehicleFitmentService = vehicleFitmentService;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task Run()
|
public async Task Run(CancellationToken token, params string[] arguments)
|
||||||
{
|
{
|
||||||
IEnumerable<Product> products = null;
|
|
||||||
|
|
||||||
try
|
IList<string> productTypes = await _fitmentContext.ProductTypes
|
||||||
|
.Where(p => p.Active)
|
||||||
|
.Select(p => HttpUtility.UrlEncode(p.Name))
|
||||||
|
.ToListAsync();
|
||||||
|
|
||||||
|
foreach (string productType in productTypes)
|
||||||
{
|
{
|
||||||
products = await _shopifyClient.Products.Get(new Dictionary<string, object> { { "limit", 250 } });
|
_logger.LogInformation("Processing {productType}", HttpUtility.UrlDecode(productType));
|
||||||
}
|
|
||||||
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
_logger.LogError("Failed to get products from Shopify", ex);
|
|
||||||
throw;
|
|
||||||
}
|
|
||||||
|
|
||||||
int i = 1;
|
|
||||||
|
|
||||||
while (products != null && products.Any())
|
|
||||||
{
|
|
||||||
foreach (Product product in products)
|
|
||||||
{
|
|
||||||
// Wiper blades are a separate fitment process.
|
|
||||||
if (product.ProductType.Contains("CA172-SC231"))
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
ImportData importData = null;
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
IEnumerable<Metafield> metafields = await _shopifyClient.Metafields.Get(new Dictionary<string, object> { { "metafield[owner_id]", product.Id }, { "metafield[owner_resource]", "product" } });
|
|
||||||
|
|
||||||
//importData = await _partSourceContext.ImportData.FirstOrDefaultAsync(parts => parts.ShopifyId == product.Id);
|
|
||||||
|
|
||||||
//if (importData == null)
|
|
||||||
//{
|
|
||||||
// continue;
|
|
||||||
importData = new ImportData
|
|
||||||
{
|
|
||||||
LineCode = metafields.FirstOrDefault(m => m.Key == "custom_label_0").Value ?? string.Empty,
|
|
||||||
PartNumber = product.Title.Split(' ')[0],
|
|
||||||
VariantSku = product.Variants[0].Sku // They know we can't do fitment for variants
|
|
||||||
};
|
|
||||||
// }
|
|
||||||
|
|
||||||
bool isFitment = false;
|
|
||||||
string bodyHtml = product.BodyHtml[..(product.BodyHtml.IndexOf("</ul>") + "</ul>".Length)];
|
|
||||||
|
|
||||||
IList<Vehicle> vehicles = _vehicleService.GetVehiclesForPart(importData.PartNumber, importData.LineCode);
|
|
||||||
|
|
||||||
IList<int> vehicleIdFitment = _vehicleService.GetVehicleIdFitment(vehicles);
|
|
||||||
|
|
||||||
if (vehicleIdFitment.Any())
|
|
||||||
{
|
|
||||||
string vehicleIdString = string.Join('-', vehicleIdFitment.Select(j => $"v{j}"));
|
|
||||||
|
|
||||||
bodyHtml += $"<div id=\"vehicleIDs\" style=\"display:none;\">{vehicleIdString}</div>";
|
|
||||||
|
|
||||||
isFitment = true;
|
|
||||||
|
|
||||||
string json = JsonConvert.SerializeObject(vehicleIdFitment);
|
|
||||||
Metafield vehicleMetafield = new Metafield
|
|
||||||
{
|
|
||||||
Namespace = "fitment",
|
|
||||||
Key = "ids",
|
|
||||||
Value = json,
|
|
||||||
ValueType = "json_string",
|
|
||||||
OwnerResource = "product",
|
|
||||||
OwnerId = product.Id
|
|
||||||
};
|
|
||||||
|
|
||||||
await _shopifyClient.Metafields.Add(vehicleMetafield);
|
|
||||||
}
|
|
||||||
|
|
||||||
IList<string> ymmFitment = _vehicleService.GetYmmFitment(vehicles);
|
|
||||||
if (ymmFitment.Count > 0)
|
|
||||||
{
|
|
||||||
isFitment = true;
|
|
||||||
|
|
||||||
StringBuilder stringBuilder = new StringBuilder();
|
|
||||||
stringBuilder.AppendLine("<table><tr><th colspan=\"2\">This Part Fits</th></tr>");
|
|
||||||
|
|
||||||
foreach (string fitment in ymmFitment)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
string[] parts = fitment.Split(' ', 2);
|
|
||||||
|
|
||||||
stringBuilder.AppendLine($"<tr><td>{parts[1]}</td><td>{parts[0].Replace("-", ", ")}</td></tr>");
|
|
||||||
}
|
|
||||||
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
// This is still a POC at this point. Oh well...
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
stringBuilder.AppendLine("</table>");
|
|
||||||
|
|
||||||
bodyHtml += $"<div id=\"seoData\">{stringBuilder.ToString()}</div>";
|
|
||||||
|
|
||||||
string json = JsonConvert.SerializeObject(ymmFitment);
|
|
||||||
Metafield ymmMetafield = new Metafield
|
|
||||||
{
|
|
||||||
Namespace = "fitment",
|
|
||||||
Key = "seo",
|
|
||||||
Value = json,
|
|
||||||
ValueType = "json_string",
|
|
||||||
OwnerResource = "product",
|
|
||||||
OwnerId = product.Id
|
|
||||||
};
|
|
||||||
|
|
||||||
await _shopifyClient.Metafields.Add(ymmMetafield);
|
|
||||||
}
|
|
||||||
|
|
||||||
Metafield isFitmentMetafield = new Metafield
|
|
||||||
{
|
|
||||||
Namespace = "Flags",
|
|
||||||
Key = "IsFitment",
|
|
||||||
Value = isFitment.ToString(),
|
|
||||||
ValueType = "string",
|
|
||||||
OwnerResource = "product",
|
|
||||||
OwnerId = product.Id
|
|
||||||
};
|
|
||||||
|
|
||||||
await _shopifyClient.Metafields.Add(isFitmentMetafield);
|
|
||||||
|
|
||||||
Metafield lineCodeMetafield = new Metafield
|
|
||||||
{
|
|
||||||
Namespace = "google",
|
|
||||||
Key = "custom_label_0",
|
|
||||||
Value = importData.LineCode,
|
|
||||||
ValueType = "string",
|
|
||||||
OwnerResource = "product",
|
|
||||||
OwnerId = product.Id
|
|
||||||
};
|
|
||||||
|
|
||||||
// await _shopifyClient.Metafields.Add(lineCodeMetafield);
|
|
||||||
|
|
||||||
Metafield partNumberMetafield = new Metafield
|
|
||||||
{
|
|
||||||
Namespace = "google",
|
|
||||||
Key = "custom_label_1",
|
|
||||||
Value = importData.PartNumber,
|
|
||||||
ValueType = "string",
|
|
||||||
OwnerResource = "product",
|
|
||||||
OwnerId = product.Id
|
|
||||||
};
|
|
||||||
|
|
||||||
//await _shopifyClient.Metafields.Add(partNumberMetafield);
|
|
||||||
|
|
||||||
List<string> tags = new List<string>();
|
|
||||||
|
|
||||||
for (int j = 0; j < vehicleIdFitment.Count; j += 25)
|
|
||||||
{
|
|
||||||
tags.Add(string.Join('-', vehicleIdFitment.Skip(j).Take(25).Select(j => $"v{j}")));
|
|
||||||
}
|
|
||||||
|
|
||||||
tags.AddRange(ymmFitment);
|
|
||||||
|
|
||||||
if (tags.Count > 249)
|
|
||||||
{
|
|
||||||
tags = tags.Take(249).ToList();
|
|
||||||
}
|
|
||||||
|
|
||||||
string zzzIsFitment = isFitment
|
|
||||||
? "zzzIsFitment=true"
|
|
||||||
: "zzzIsFitment=false";
|
|
||||||
|
|
||||||
tags.Add(zzzIsFitment);
|
|
||||||
|
|
||||||
product.Tags = string.Join(',', tags);
|
|
||||||
product.BodyHtml = bodyHtml;
|
|
||||||
|
|
||||||
await _shopifyClient.Products.Update(product);
|
|
||||||
|
|
||||||
importData.IsFitment = isFitment;
|
|
||||||
importData.UpdatedAt = DateTime.Now;
|
|
||||||
importData.UpdateType = "Fitment";
|
|
||||||
}
|
|
||||||
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
_logger.LogError($"Failed to updated fitment data for SKU {importData?.VariantSku} - {ex.Message}", ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
IEnumerable<Product> products = null;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
Console.WriteLine(i);
|
products = await _shopifyClient.Products.Get(new Dictionary<string, object> { { "limit", 250 }, { "product_type", productType } });
|
||||||
|
//products = new List<Product>
|
||||||
_partSourceContext.SaveChanges();
|
//{
|
||||||
products = await _shopifyClient.Products.GetNext();
|
// await _shopifyClient.Products.GetById(7458071052335)
|
||||||
|
//};
|
||||||
i++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
_logger.LogWarning(ex, "Failed to get the next set of products. Retrying");
|
_logger.LogError("Failed to get products from Shopify", ex);
|
||||||
products = await _shopifyClient.Products.GetPrevious();
|
throw;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (products != null && products.Any())
|
||||||
|
{
|
||||||
|
foreach (Product product in products)
|
||||||
|
{
|
||||||
|
ImportData importData = null;
|
||||||
|
bool isFitment = false;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
IEnumerable<Metafield> metafields = await _shopifyClient.Metafields.Get(new Dictionary<string, object> { { "metafield[owner_id]", product.Id }, { "metafield[owner_resource]", "product" } });
|
||||||
|
importData = new ImportData
|
||||||
|
{
|
||||||
|
LineCode = metafields.FirstOrDefault(m => m.Key == "custom_label_0")?.Value ?? string.Empty,
|
||||||
|
PartNumber = metafields.FirstOrDefault(m => m.Key == "custom_label_1")?.Value ?? string.Empty,
|
||||||
|
VariantSku = product.Variants[0].Sku // They know we can't do fitment for variants
|
||||||
|
};
|
||||||
|
|
||||||
|
importData.PartNumber = importData.PartNumber.Replace("-", string.Empty);
|
||||||
|
|
||||||
|
//If the line code is numeric, it cannot have fitment data associated with it.
|
||||||
|
if (int.TryParse(importData.LineCode, out _))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extract Partsource bullet points if present.
|
||||||
|
string bodyHtml = string.IsNullOrEmpty(product.BodyHtml)
|
||||||
|
? string.Empty
|
||||||
|
: product.BodyHtml.Substring(0, product.BodyHtml.IndexOf("</ul>") + "</ul>".Length);
|
||||||
|
|
||||||
|
IList<Vehicle> vehicles = await _vehicleFitmentService.GetVehiclesForPart(importData.PartNumber, importData.LineCode);
|
||||||
|
IList<int> vehicleIdFitment = _vehicleFitmentService.GetVehicleIdFitment(vehicles);
|
||||||
|
|
||||||
|
if (!vehicleIdFitment.Any())
|
||||||
|
{
|
||||||
|
Console.WriteLine($"No fitment data for {importData.LineCode} {importData.PartNumber}");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
string vehicleIdString = string.Join(',', vehicleIdFitment.Select(j => $"v{j}"));
|
||||||
|
|
||||||
|
bodyHtml += $"<div id=\"vehicleIDs\" style=\"display:none;\">{vehicleIdString}</div>";
|
||||||
|
isFitment = true;
|
||||||
|
|
||||||
|
IList<string> ymmFitment = _vehicleFitmentService.GetYmmFitment(vehicles);
|
||||||
|
if (ymmFitment.Count > 0)
|
||||||
|
{
|
||||||
|
isFitment = true;
|
||||||
|
|
||||||
|
StringBuilder stringBuilder = new StringBuilder();
|
||||||
|
stringBuilder.AppendLine("<table><tr><th colspan=\"2\">This Part Fits</th></tr>");
|
||||||
|
|
||||||
|
foreach (string fitment in ymmFitment)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
string[] parts = fitment.Split(' ', 2);
|
||||||
|
stringBuilder.AppendLine($"<tr><td>{parts[1]}</td><td>{parts[0].Replace("-", ", ")}</td></tr>");
|
||||||
|
}
|
||||||
|
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogWarning(ex, "YMM fitment for {fitment} was in an invalid format", fitment);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
stringBuilder.AppendLine("</table>");
|
||||||
|
|
||||||
|
bodyHtml += $"<div id=\"seoData\">{stringBuilder}</div>";
|
||||||
|
}
|
||||||
|
|
||||||
|
List<string> tags = new List<string>();
|
||||||
|
|
||||||
|
for (int j = 0; j < vehicleIdFitment.Count; j += 25)
|
||||||
|
{
|
||||||
|
tags.Add(string.Join('-', vehicleIdFitment.Skip(j).Take(25).Select(j => $"v{j}")));
|
||||||
|
}
|
||||||
|
|
||||||
|
tags.AddRange(ymmFitment);
|
||||||
|
|
||||||
|
if (tags.Count > 249)
|
||||||
|
{
|
||||||
|
tags = tags.Take(249).ToList();
|
||||||
|
}
|
||||||
|
|
||||||
|
string zzzIsFitment = isFitment
|
||||||
|
? "zzzIsFitment=true"
|
||||||
|
: "zzzIsFitment=false";
|
||||||
|
|
||||||
|
tags.Add(zzzIsFitment);
|
||||||
|
|
||||||
|
product.Tags = string.Join(',', tags);
|
||||||
|
product.BodyHtml = bodyHtml;
|
||||||
|
await _shopifyClient.Products.Update(product);
|
||||||
|
|
||||||
|
importData.IsFitment = isFitment;
|
||||||
|
importData.UpdatedAt = DateTime.Now;
|
||||||
|
importData.UpdateType = "Fitment";
|
||||||
|
}
|
||||||
|
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError($"Failed to updated fitment data for SKU {importData?.VariantSku} - {ex.Message}", ex);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
try
|
||||||
|
{
|
||||||
|
products = await _shopifyClient.Products.GetNext();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogWarning(ex, "Failed to get the next set of products. Retrying");
|
||||||
|
products = await _shopifyClient.Products.GetPrevious();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
using PartSource.Automation.Models;
|
using PartSource.Automation.Models;
|
||||||
|
using PartSource.Automation.Services;
|
||||||
using PartSource.Data;
|
using PartSource.Data;
|
||||||
using PartSource.Data.Contexts;
|
using PartSource.Data.Contexts;
|
||||||
using PartSource.Data.Models;
|
using PartSource.Data.Models;
|
||||||
@@ -13,6 +14,7 @@ using System.Collections.Generic;
|
|||||||
using System.Diagnostics.CodeAnalysis;
|
using System.Diagnostics.CodeAnalysis;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace PartSource.Automation.Jobs
|
namespace PartSource.Automation.Jobs
|
||||||
@@ -22,17 +24,17 @@ namespace PartSource.Automation.Jobs
|
|||||||
private readonly ShopifyClient _shopifyClient;
|
private readonly ShopifyClient _shopifyClient;
|
||||||
private readonly PartSourceContext _partSourceContext;
|
private readonly PartSourceContext _partSourceContext;
|
||||||
private readonly FitmentContext _fitmentContext;
|
private readonly FitmentContext _fitmentContext;
|
||||||
private readonly VehicleService _vehicleService;
|
private readonly VehicleFitmentService _vehicleFitmentService;
|
||||||
|
|
||||||
public UpdatePositioning(PartSourceContext partSourceContext, FitmentContext fitmentContext, ShopifyClient shopifyClient, VehicleService vehicleService)
|
public UpdatePositioning(PartSourceContext partSourceContext, FitmentContext fitmentContext, ShopifyClient shopifyClient, VehicleFitmentService vehicleFitmentService)
|
||||||
{
|
{
|
||||||
_partSourceContext = partSourceContext;
|
_partSourceContext = partSourceContext;
|
||||||
_fitmentContext = fitmentContext;
|
_fitmentContext = fitmentContext;
|
||||||
_shopifyClient = shopifyClient;
|
_shopifyClient = shopifyClient;
|
||||||
_vehicleService = vehicleService;
|
_vehicleFitmentService = vehicleFitmentService;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task Run()
|
public async Task Run(CancellationToken token, params string[] arguments)
|
||||||
{
|
{
|
||||||
IDictionary<string, object> parameters = new Dictionary<string, object>
|
IDictionary<string, object> parameters = new Dictionary<string, object>
|
||||||
{
|
{
|
||||||
@@ -41,8 +43,6 @@ namespace PartSource.Automation.Jobs
|
|||||||
|
|
||||||
IEnumerable<Product> products = await _shopifyClient.Products.Get(parameters);
|
IEnumerable<Product> products = await _shopifyClient.Products.Get(parameters);
|
||||||
|
|
||||||
int i = 1;
|
|
||||||
|
|
||||||
while (products != null && products.Any())
|
while (products != null && products.Any())
|
||||||
{
|
{
|
||||||
foreach (Product product in products)
|
foreach (Product product in products)
|
||||||
@@ -64,7 +64,7 @@ namespace PartSource.Automation.Jobs
|
|||||||
}
|
}
|
||||||
|
|
||||||
IList<Fitment> fitments = GetPositionOrderedFitments(importData?.PartNumber, importData?.LineCode);
|
IList<Fitment> fitments = GetPositionOrderedFitments(importData?.PartNumber, importData?.LineCode);
|
||||||
IList<Vehicle> vehicles = _vehicleService.GetVehiclesForPart(importData?.PartNumber, importData?.LineCode);
|
IList<Vehicle> vehicles = await _vehicleFitmentService.GetVehiclesForPart(importData?.PartNumber, importData?.LineCode);
|
||||||
|
|
||||||
if (fitments.Count == 0 || vehicles.Count == 0)
|
if (fitments.Count == 0 || vehicles.Count == 0)
|
||||||
{
|
{
|
||||||
@@ -96,51 +96,45 @@ namespace PartSource.Automation.Jobs
|
|||||||
await SavePositionMetafield(product, vehicleIds, currentPosition);
|
await SavePositionMetafield(product, vehicleIds, currentPosition);
|
||||||
|
|
||||||
|
|
||||||
IList<string> notes = fitments.Select(f => f.FitmentNoteHash)
|
//IList<string> notes = fitments.Select(f => f.NoteText)
|
||||||
.Distinct()
|
|
||||||
.ToList();
|
|
||||||
|
|
||||||
IList<object> vehicleNotes = new List<object>();
|
// .Distinct()
|
||||||
|
// .ToList();
|
||||||
|
|
||||||
foreach (string noteHash in notes)
|
//IList<object> vehicleNotes = new List<object>();
|
||||||
{
|
|
||||||
FitmentNote fitmentNote = await _fitmentContext.FitmentNotes.FirstOrDefaultAsync(f => f.Hash == noteHash);
|
|
||||||
|
|
||||||
if (fitmentNote == null)
|
//foreach (string noteText in notes)
|
||||||
{
|
//{
|
||||||
continue;
|
// vehicleIds = fitments.Where(f => f.NoteText == noteText)
|
||||||
}
|
// .Select(f => new { f.EngineConfigId, f.BaseVehicleId })
|
||||||
|
// .SelectMany(f => vehicles.Where(v => v.BaseVehicleId == f.BaseVehicleId && v.EngineConfigId == f.EngineConfigId))
|
||||||
|
// .Select(v => v.VehicleToEngineConfigId)
|
||||||
|
// .ToList();
|
||||||
|
|
||||||
vehicleIds = fitments.Where(f => f.FitmentNoteHash == noteHash)
|
// vehicleNotes.Add(new { noteText, vehicleIds });
|
||||||
.Select(f => new { f.EngineConfigId, f.BaseVehicleId })
|
//}
|
||||||
.SelectMany(f => vehicles.Where(v => v.BaseVehicleId == f.BaseVehicleId && v.EngineConfigId == f.EngineConfigId))
|
|
||||||
.Select(v => v.VehicleToEngineConfigId)
|
|
||||||
.ToList();
|
|
||||||
|
|
||||||
vehicleNotes.Add(new { fitmentNote.NoteText, vehicleIds });
|
//string json = JsonConvert.SerializeObject(vehicleNotes);
|
||||||
}
|
//if (json.Length >= 100000)
|
||||||
|
//{
|
||||||
|
// continue;
|
||||||
|
//}
|
||||||
|
|
||||||
string json = JsonConvert.SerializeObject(vehicleNotes);
|
//Metafield vehicleMetafield = new Metafield
|
||||||
if (json.Length >= 100000)
|
//{
|
||||||
{
|
// Namespace = "fitment",
|
||||||
continue;
|
// Key = "note_text",
|
||||||
}
|
// Value = json,
|
||||||
|
// ValueType = "json_string",
|
||||||
|
// OwnerResource = "product",
|
||||||
|
// OwnerId = product.Id
|
||||||
|
//};
|
||||||
|
|
||||||
Metafield vehicleMetafield = new Metafield
|
//await _shopifyClient.Metafields.Add(vehicleMetafield);
|
||||||
{
|
|
||||||
Namespace = "fitment",
|
|
||||||
Key = "note_text",
|
|
||||||
Value = json,
|
|
||||||
ValueType = "json_string",
|
|
||||||
OwnerResource = "product",
|
|
||||||
OwnerId = product.Id
|
|
||||||
};
|
|
||||||
|
|
||||||
await _shopifyClient.Metafields.Add(vehicleMetafield);
|
//importData.UpdatedAt = DateTime.Now;
|
||||||
|
//importData.UpdateType = "Positioning";
|
||||||
//importData.UpdatedAt = DateTime.Now;
|
}
|
||||||
//importData.UpdateType = "Positioning";
|
|
||||||
}
|
|
||||||
|
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
@@ -149,8 +143,7 @@ namespace PartSource.Automation.Jobs
|
|||||||
}
|
}
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
Console.WriteLine(i);
|
|
||||||
products = await _shopifyClient.Products.GetNext();
|
products = await _shopifyClient.Products.GetNext();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -204,12 +197,12 @@ namespace PartSource.Automation.Jobs
|
|||||||
Namespace = "position",
|
Namespace = "position",
|
||||||
Key = key,
|
Key = key,
|
||||||
Value = json,
|
Value = json,
|
||||||
ValueType = "json_string",
|
Type = "json_string",
|
||||||
OwnerResource = "product",
|
OwnerResource = "product",
|
||||||
OwnerId = product.Id
|
OwnerId = product.Id
|
||||||
};
|
};
|
||||||
|
|
||||||
//System.Diagnostics.Debug.WriteLine(json);
|
System.Diagnostics.Debug.WriteLine(json);
|
||||||
|
|
||||||
await _shopifyClient.Metafields.Add(vehicleMetafield);
|
await _shopifyClient.Metafields.Add(vehicleMetafield);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,161 +13,108 @@ using System.Collections.Generic;
|
|||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Net.Mail;
|
using System.Net.Mail;
|
||||||
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace PartSource.Automation.Jobs
|
namespace PartSource.Automation.Jobs
|
||||||
{
|
{
|
||||||
public class UpdatePricing : IAutomationJob
|
public class UpdatePricing : IAutomationJob
|
||||||
{
|
{
|
||||||
private readonly ILogger<UpdatePricing> _logger;
|
private readonly ILogger<UpdatePricing> _logger;
|
||||||
private readonly PartSourceContext _partSourceContext;
|
private readonly PartSourceContext _partSourceContext;
|
||||||
private readonly ShopifyClient _shopifyClient;
|
private readonly ShopifyClient _shopifyClient;
|
||||||
private readonly EmailService _emailService;
|
private readonly EmailService _emailService;
|
||||||
|
|
||||||
public UpdatePricing(ILogger<UpdatePricing> logger, PartSourceContext partSourceContext, ShopifyClient shopifyClient, EmailService emailService)
|
public UpdatePricing(ILogger<UpdatePricing> logger, PartSourceContext partSourceContext, ShopifyClient shopifyClient, EmailService emailService)
|
||||||
{
|
{
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
_partSourceContext = partSourceContext;
|
_partSourceContext = partSourceContext;
|
||||||
_shopifyClient = shopifyClient;
|
_shopifyClient = shopifyClient;
|
||||||
_emailService = emailService;
|
_emailService = emailService;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task Run()
|
public async Task Run(CancellationToken token, params string[] arguments)
|
||||||
{
|
{
|
||||||
List<UpdatePricingResult> pricingReport = new List<UpdatePricingResult>();
|
IEnumerable<Product> products = null;
|
||||||
IEnumerable<Product> products = null;
|
IEnumerable<PartPrice> prices = null;
|
||||||
IEnumerable<PartPrice> prices = null;
|
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
products = await _shopifyClient.Products.Get(new Dictionary<string, object> { { "limit", 250 } });
|
products = await _shopifyClient.Products.Get(new Dictionary<string, object> { { "limit", 250 } });
|
||||||
prices = await _partSourceContext.PartPrices.AsNoTracking().ToListAsync();
|
prices = await _partSourceContext.PartPrices.AsNoTracking().ToListAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
_logger.LogError(ex, "Failed to get the initial set of products from Shopify.");
|
_logger.LogError(ex, "Failed to get the initial set of products from Shopify.");
|
||||||
|
|
||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
|
|
||||||
while (products != null && products.Any())
|
int count = 0;
|
||||||
{
|
while (products != null && products.Any())
|
||||||
foreach (Product product in products)
|
{
|
||||||
{
|
foreach (Product product in products)
|
||||||
List<UpdatePricingResult> productPricingUpdate = new List<UpdatePricingResult>();
|
{
|
||||||
|
if (product.Variants.Length > 0)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < product.Variants.Length; i++)
|
||||||
|
{
|
||||||
|
Variant variant = product.Variants[i];
|
||||||
|
PartPrice partPrice = prices.Where(p => p.SKU == variant.Sku).FirstOrDefault();
|
||||||
|
|
||||||
if (product.Variants.Length > 0)
|
if (partPrice == null || !partPrice.Your_Price.HasValue || !partPrice.Compare_Price.HasValue)
|
||||||
{
|
{
|
||||||
bool hasUpdate = false;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
for (int i = 0; i < product.Variants.Length; i++)
|
product.Variants[i].Price = partPrice.Your_Price.Value;
|
||||||
{
|
product.Variants[i].CompareAtPrice = partPrice.Compare_Price.Value;
|
||||||
Variant variant = product.Variants[i];
|
|
||||||
PartPrice partPrice = prices.Where(p => p.SKU == variant.Sku).FirstOrDefault();
|
|
||||||
|
|
||||||
if (partPrice == null || !partPrice.Your_Price.HasValue || !partPrice.Compare_Price.HasValue)
|
product.PublishedAt = partPrice.Active.Trim().ToUpperInvariant() == "Y" ? (DateTime?)DateTime.Now : null;
|
||||||
{
|
product.PublishedScope = PublishedScope.Global;
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (product.Variants[i].Price.ToString("G29") != partPrice.Your_Price.Value.ToString("G29") || product.Variants[i].CompareAtPrice.ToString("G29") != partPrice.Compare_Price.Value.ToString("G29"))
|
try
|
||||||
{
|
{
|
||||||
productPricingUpdate.Add(new UpdatePricingResult
|
|
||||||
{
|
|
||||||
Sku = variant.Sku,
|
|
||||||
OldPrice = product.Variants[i].Price,
|
|
||||||
NewPrice = partPrice.Your_Price.Value,
|
|
||||||
OldCompareAt = product.Variants[i].CompareAtPrice,
|
|
||||||
NewCompareAt = partPrice.Compare_Price.Value
|
|
||||||
});
|
|
||||||
|
|
||||||
product.Variants[i].Price = partPrice.Your_Price.Value;
|
await _shopifyClient.Metafields.Add(new Metafield
|
||||||
product.Variants[i].CompareAtPrice = partPrice.Compare_Price.Value;
|
{
|
||||||
|
Namespace = "Pricing",
|
||||||
|
Key = "CorePrice",
|
||||||
|
Value = partPrice.Core_Price.HasValue ? partPrice.Core_Price.Value.ToString() : "0.00",
|
||||||
|
Type = "string",
|
||||||
|
OwnerResource = "product",
|
||||||
|
OwnerId = product.Id
|
||||||
|
});
|
||||||
|
|
||||||
product.PublishedAt = partPrice.Active.Trim().ToUpperInvariant() == "Y" ? DateTime.Now : null;
|
await _shopifyClient.Products.Update(product);
|
||||||
product.PublishedScope = PublishedScope.Global;
|
|
||||||
|
|
||||||
//Metafield metafield = new Metafield
|
_logger.LogInformation("Updated product id {productId}", product.Id);
|
||||||
//{
|
}
|
||||||
// Namespace = "Pricing",
|
|
||||||
// Key = "CorePrice",
|
|
||||||
// Value = partPrice.Core_Price.HasValue ? partPrice.Core_Price.Value.ToString() : "0.00",
|
|
||||||
// ValueType = "string",
|
|
||||||
// OwnerResource = "product",
|
|
||||||
// OwnerId = product.Id
|
|
||||||
//};
|
|
||||||
|
|
||||||
hasUpdate = true;
|
catch (Exception ex)
|
||||||
}
|
{
|
||||||
}
|
_logger.LogWarning(ex, "Failed to update pricing for product ID {productId}", product.Id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (hasUpdate)
|
try
|
||||||
{
|
{
|
||||||
try
|
count += products.Count();
|
||||||
{
|
products = await _shopifyClient.Products.GetNext();
|
||||||
//await _shopifyClient.Metafields.Add(metafield);
|
_logger.LogInformation($"Total updated: {count}");
|
||||||
await _shopifyClient.Products.Update(product);
|
}
|
||||||
|
|
||||||
pricingReport.AddRange(productPricingUpdate);
|
|
||||||
}
|
|
||||||
|
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
_logger.LogWarning(ex, $"Failed to update pricing for product ID {product.Id}");
|
_logger.LogWarning(ex, "Failed to get the next set of products. Retrying");
|
||||||
}
|
products = await _shopifyClient.Products.GetPrevious();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
try
|
_emailService.Send("Pricing Update Completed", $"The pricing update has completed.");
|
||||||
{
|
}
|
||||||
products = await _shopifyClient.Products.GetNext();
|
}
|
||||||
|
}
|
||||||
_logger.LogInformation($"Total updated: {pricingReport.Count}");
|
|
||||||
}
|
|
||||||
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
_logger.LogWarning(ex, "Failed to get the next set of products. Retrying");
|
|
||||||
products = await _shopifyClient.Products.GetPrevious();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Attachment attachment = GetPricingReportAttachment(pricingReport);
|
|
||||||
|
|
||||||
_emailService.Send("Pricing Update Completed", $"The pricing update has completed. Total updated: {pricingReport.Count}", attachment);
|
|
||||||
}
|
|
||||||
|
|
||||||
private Attachment GetPricingReportAttachment(IList<UpdatePricingResult> pricingReport)
|
|
||||||
{
|
|
||||||
string directory = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop), "Pricing Reports");
|
|
||||||
string filename = Path.Combine(directory, $"Pricing Update {DateTime.Now.ToString("yyyy-MM-dd")}.csv");
|
|
||||||
|
|
||||||
if (!Directory.Exists(directory))
|
|
||||||
{
|
|
||||||
Directory.CreateDirectory(directory);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (File.Exists(filename))
|
|
||||||
{
|
|
||||||
File.Delete(filename);
|
|
||||||
}
|
|
||||||
|
|
||||||
using FileStream fileStream = File.OpenWrite(filename);
|
|
||||||
using StreamWriter streamWriter = new StreamWriter(fileStream, System.Text.Encoding.UTF8);
|
|
||||||
|
|
||||||
streamWriter.WriteLine("SKU, Old Price, New Price, Old Compare At, New Compare At");
|
|
||||||
|
|
||||||
foreach (UpdatePricingResult pricingResult in pricingReport)
|
|
||||||
{
|
|
||||||
streamWriter.WriteLine($"{pricingResult.Sku},{pricingResult.OldPrice},{pricingResult.NewPrice},{pricingResult.OldCompareAt},{pricingResult.NewCompareAt}");
|
|
||||||
}
|
|
||||||
|
|
||||||
streamWriter.Close();
|
|
||||||
fileStream.Close();
|
|
||||||
|
|
||||||
return new Attachment(filename);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -16,5 +16,7 @@ namespace PartSource.Automation.Models.Configuration
|
|||||||
public string Username { get; set; }
|
public string Username { get; set; }
|
||||||
|
|
||||||
public string Password { get; set; }
|
public string Password { get; set; }
|
||||||
|
|
||||||
|
public int Port { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
19
PartSource.Automation/Models/Ftp/FtpFileInfo.cs
Normal file
19
PartSource.Automation/Models/Ftp/FtpFileInfo.cs
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace PartSource.Automation.Models.Ftp
|
||||||
|
{
|
||||||
|
public class FtpFileInfo
|
||||||
|
{
|
||||||
|
public string Filename { get; set; }
|
||||||
|
|
||||||
|
public DateTime Modified { get; set; }
|
||||||
|
|
||||||
|
public long Size { get; set; }
|
||||||
|
|
||||||
|
public FtpFileType FileType { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
14
PartSource.Automation/Models/Ftp/FtpFileType.cs
Normal file
14
PartSource.Automation/Models/Ftp/FtpFileType.cs
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace PartSource.Automation.Models.Ftp
|
||||||
|
{
|
||||||
|
public enum FtpFileType
|
||||||
|
{
|
||||||
|
File,
|
||||||
|
Directory
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -18,9 +18,11 @@
|
|||||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="6.0.0" />
|
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="6.0.0" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Hosting" Version="6.0.1" />
|
<PackageReference Include="Microsoft.Extensions.Hosting" Version="6.0.1" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="6.0.0" />
|
<PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="6.0.0" />
|
||||||
<PackageReference Include="Ratermania.Automation" Version="1.0.0" />
|
<PackageReference Include="Ratermania.Automation" Version="6.16.9" />
|
||||||
<PackageReference Include="Ratermania.Automation.Common" Version="1.0.0" />
|
<PackageReference Include="Ratermania.Automation.Common" Version="6.16.9" />
|
||||||
<PackageReference Include="Ratermania.Shopify" Version="1.3.1" />
|
<PackageReference Include="Ratermania.JwtSpot" Version="6.16.9" />
|
||||||
|
<PackageReference Include="Ratermania.Shopify" Version="6.16.11" />
|
||||||
|
<PackageReference Include="System.Data.SqlClient" Version="4.8.5" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|||||||
@@ -1,19 +1,14 @@
|
|||||||
using AutoMapper;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using Microsoft.EntityFrameworkCore;
|
|
||||||
using Microsoft.Extensions.Configuration;
|
using Microsoft.Extensions.Configuration;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using Microsoft.Extensions.Hosting;
|
using Microsoft.Extensions.Hosting;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using PartSource.Automation.Jobs;
|
using PartSource.Automation.Jobs;
|
||||||
using PartSource.Automation.Jobs.POC;
|
|
||||||
using PartSource.Automation.Models.Configuration;
|
|
||||||
using PartSource.Automation.Services;
|
using PartSource.Automation.Services;
|
||||||
using PartSource.Data;
|
|
||||||
using PartSource.Data.AutoMapper;
|
using PartSource.Data.AutoMapper;
|
||||||
using PartSource.Data.Contexts;
|
using PartSource.Data.Contexts;
|
||||||
using PartSource.Services;
|
using PartSource.Services;
|
||||||
using Ratermania.Automation.DependencyInjection;
|
using Ratermania.Automation.DependencyInjection;
|
||||||
using Ratermania.Automation.Logging;
|
|
||||||
using Ratermania.Shopify.DependencyInjection;
|
using Ratermania.Shopify.DependencyInjection;
|
||||||
using System;
|
using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
@@ -68,44 +63,68 @@ namespace PartSource.Automation
|
|||||||
{
|
{
|
||||||
options.ApiKey = builder.Configuration["Shopify:ApiKey"];
|
options.ApiKey = builder.Configuration["Shopify:ApiKey"];
|
||||||
options.ApiSecret = builder.Configuration["Shopify:ApiSecret"];
|
options.ApiSecret = builder.Configuration["Shopify:ApiSecret"];
|
||||||
options.ApiVersion = "2021-01";
|
options.ApiVersion = "2024-10";
|
||||||
options.ShopDomain = builder.Configuration["Shopify:ShopDomain"];
|
options.ShopDomain = builder.Configuration["Shopify:ShopDomain"];
|
||||||
|
|
||||||
//options.ApiKey = "9a533dad460321c6ce8f30bf5b8691ed";
|
//options.ApiKey = "9a533dad460321c6ce8f30bf5b8691ed";
|
||||||
//options.ApiSecret = "dc9e28365d9858e544d57ac7af43fee7";
|
//options.ApiSecret = "dc9e28365d9858e544d57ac7af43fee7";
|
||||||
//options.ApiVersion = "2021-01";
|
//options.ApiVersion = "2022-10";
|
||||||
//options.ShopDomain = "dev-partsource.myshopify.com";
|
//options.ShopDomain = "dev-partsource.myshopify.com";
|
||||||
})
|
})
|
||||||
|
|
||||||
.AddAutomation(options =>
|
.AddAutomation(options =>
|
||||||
{
|
{
|
||||||
//options.HasBaseInterval(new TimeSpan(0, 15, 0))
|
options.HasBaseInterval(new TimeSpan(0, 5, 0))
|
||||||
// .HasMaxFailures(3)
|
.HasMaxFailures(5)
|
||||||
// .HasJob<ExecuteSsisPackages>(options =>
|
//.HasJob<TestJob>(options => options.HasInterval(new TimeSpan(7, 0, 0, 0)));
|
||||||
// options.HasInterval(new TimeSpan(24, 0, 0))
|
//
|
||||||
// .StartsAt(DateTime.Today.AddHours(26))
|
//.HasJob<SyncronizeProducts>(options => options.HasInterval(new TimeSpan(24, 0, 0)))
|
||||||
// )
|
// .HasJob<ProcessWhiFitment>(options => options.HasInterval(new TimeSpan(24, 0, 0)));
|
||||||
// .HasJob<UpdatePricing>(options =>
|
//.HasJob<ProcessWhiVehicles>(options => options.HasInterval(new TimeSpan(24, 0, 0))
|
||||||
// options.HasInterval(new TimeSpan(24, 0, 0))
|
//.HasDependency<SyncronizeProducts>()
|
||||||
// .StartsAt(DateTime.Today.AddHours(27))
|
//.HasJob<UpdateFitment>(options => options.HasInterval(new TimeSpan(24, 0, 0)));
|
||||||
// .HasDependency<ExecuteSsisPackages>()
|
//.HasJob<UpdatePositioning>(options => options.HasInterval(new TimeSpan(24, 0, 0))
|
||||||
// );
|
// .HasDependency<UpdateFitment>()
|
||||||
|
// .HasDependency<ProcessWhiFitment>()
|
||||||
options.HasBaseInterval(new TimeSpan(0, 15, 0))
|
// .HasDependency<SyncronizeProducts>()
|
||||||
.HasMaxFailures(3)
|
// .StartsAt(DateTime.Today.AddHours(8))
|
||||||
.HasJob<UpdateWiperFitment>(options =>
|
//) ;
|
||||||
|
//.HasJob<StatusCheck>(options => options.HasInterval(new TimeSpan(24, 0, 0))
|
||||||
|
// .StartsAt(DateTime.Parse("2021-04-01 08:00:00"))
|
||||||
|
//)
|
||||||
|
//.HasJob<ExecuteSsisPackages>(options =>
|
||||||
|
// options.HasInterval(new TimeSpan(24, 0, 0))
|
||||||
|
// .StartsAt(DateTime.Today.AddHours(-24))
|
||||||
|
// )
|
||||||
|
.HasJob<UpdatePricing>(options =>
|
||||||
options.HasInterval(new TimeSpan(24, 0, 0))
|
options.HasInterval(new TimeSpan(24, 0, 0))
|
||||||
);
|
.StartsAt(DateTime.Today.AddHours(-22))
|
||||||
|
//.HasDependency<ExecuteSsisPackages>()
|
||||||
|
);
|
||||||
|
//.HasJob<BulkUpdateInventory>(options =>
|
||||||
|
// options.HasInterval(new TimeSpan(1, 0, 0))
|
||||||
|
// .StartsAt(DateTime.Today.AddHours(-27))
|
||||||
|
// );
|
||||||
|
//.HasJob<TestJob>(options =>
|
||||||
|
// options.HasInterval(new TimeSpan(1, 0, 0))
|
||||||
|
// .StartsAt(DateTime.Today.AddHours(-27).AddMinutes(30))
|
||||||
|
//);
|
||||||
|
|
||||||
|
//.HasJob<PartialInventoryUpdate>(options => options.HasInterval(new TimeSpan(1, 0, 0))
|
||||||
|
//.HasDependency<ExecuteSsisPackages>()
|
||||||
|
// .StartsAt(DateTime.Today)
|
||||||
|
//);
|
||||||
|
//);
|
||||||
//.AddApiServer();
|
//.AddApiServer();
|
||||||
})
|
})
|
||||||
|
|
||||||
.AddSingleton(builder.Configuration.GetSection("FtpServers:AzureConfiguration").Get<FtpConfiguration>())
|
|
||||||
.AddSingleton<FtpService>()
|
|
||||||
.AddSingleton<EmailService>()
|
.AddSingleton<EmailService>()
|
||||||
.AddSingleton<SsisService>()
|
.AddSingleton<SsisService>()
|
||||||
.AddSingleton<WhiSeoService>()
|
.AddSingleton<WhiSeoService>()
|
||||||
.AddSingleton<VehicleService>()
|
.AddSingleton<VehicleService>()
|
||||||
|
.AddSingleton<VehicleFitmentService>()
|
||||||
.AddSingleton<NexpartService>()
|
.AddSingleton<NexpartService>()
|
||||||
|
.AddSingleton<PartService>()
|
||||||
|
|
||||||
.AddAutoMapper(typeof(PartSourceProfile));
|
.AddAutoMapper(typeof(PartSourceProfile));
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
using Microsoft.Extensions.Configuration;
|
using Microsoft.Extensions.Configuration;
|
||||||
using PartSource.Automation.Models.Configuration;
|
using PartSource.Automation.Models.Configuration;
|
||||||
|
using PartSource.Automation.Models.Ftp;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Configuration;
|
using System.Configuration;
|
||||||
@@ -9,44 +10,119 @@ using System.Threading.Tasks;
|
|||||||
|
|
||||||
namespace PartSource.Automation.Services
|
namespace PartSource.Automation.Services
|
||||||
{
|
{
|
||||||
public class FtpService
|
public class FtpService
|
||||||
{
|
{
|
||||||
private readonly FtpConfiguration _ftpConfiguration;
|
private readonly FtpConfiguration _ftpConfiguration;
|
||||||
|
|
||||||
public FtpService(FtpConfiguration ftpConfiguration)
|
public FtpService(FtpConfiguration ftpConfiguration)
|
||||||
{
|
{
|
||||||
_ftpConfiguration = ftpConfiguration;
|
_ftpConfiguration = ftpConfiguration;
|
||||||
}
|
}
|
||||||
|
|
||||||
public string[] ListFiles(string directory)
|
public IList<FtpFileInfo> ListFilesExtended(string directory = "")
|
||||||
{
|
{
|
||||||
FtpWebRequest request = (FtpWebRequest)WebRequest.Create(new Uri($"{_ftpConfiguration.Url}/{directory}"));
|
FtpWebRequest request = (FtpWebRequest)WebRequest.Create(new Uri($"{_ftpConfiguration.Url}/{directory}"));
|
||||||
request.Credentials = new NetworkCredential(_ftpConfiguration.Username, _ftpConfiguration.Password);
|
request.Credentials = new NetworkCredential(_ftpConfiguration.Username, _ftpConfiguration.Password);
|
||||||
request.Method = WebRequestMethods.Ftp.ListDirectory;
|
request.Method = WebRequestMethods.Ftp.ListDirectoryDetails;
|
||||||
|
|
||||||
using FtpWebResponse response = (FtpWebResponse)request.GetResponse();
|
using FtpWebResponse response = (FtpWebResponse)request.GetResponse();
|
||||||
using StreamReader reader = new StreamReader(response.GetResponseStream());
|
using StreamReader reader = new StreamReader(response.GetResponseStream());
|
||||||
|
|
||||||
string files = reader.ReadToEnd();
|
IList<FtpFileInfo> files = new List<FtpFileInfo>();
|
||||||
|
string[] fileStrings = reader.ReadToEnd().Split("\r\n");
|
||||||
|
|
||||||
return files.Length > 0
|
foreach (string fileString in fileStrings)
|
||||||
? files.Split("\r\n")
|
{
|
||||||
: Array.Empty<string>();
|
if (string.IsNullOrEmpty(fileString))
|
||||||
}
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
public void Download(string filename)
|
string dateString = fileString[..17];
|
||||||
{
|
string[] sizeAndName = fileString[18..].TrimStart().Split(" ", 2);
|
||||||
string file = $"{_ftpConfiguration.Destination}\\{filename.Replace("/", "\\")}";
|
|
||||||
|
|
||||||
FtpWebRequest request = (FtpWebRequest)WebRequest.Create(new Uri($"{_ftpConfiguration.Url}/{filename}"));
|
if (sizeAndName[0].ToUpperInvariant().IndexOf("DIR") > -1)
|
||||||
request.Credentials = new NetworkCredential(_ftpConfiguration.Username, _ftpConfiguration.Password);
|
{
|
||||||
request.Method = WebRequestMethods.Ftp.DownloadFile;
|
files.Add(new FtpFileInfo
|
||||||
|
{
|
||||||
using FtpWebResponse response = (FtpWebResponse)request.GetResponse();
|
Modified = DateTime.Parse(fileString[..17]),
|
||||||
using Stream responseStream = response.GetResponseStream();
|
Size = 0,
|
||||||
using FileStream fileStream = new FileStream($"{_ftpConfiguration.Destination}\\{filename.Replace("/", "\\")}", FileMode.Create);
|
Filename = sizeAndName[1].Trim(),
|
||||||
|
FileType = FtpFileType.Directory
|
||||||
responseStream.CopyTo(fileStream);
|
});
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
else
|
||||||
|
{
|
||||||
|
files.Add(new FtpFileInfo
|
||||||
|
{
|
||||||
|
Modified = DateTime.Parse(fileString[..17]),
|
||||||
|
Size = long.Parse(sizeAndName[0]),
|
||||||
|
Filename = sizeAndName[1].Trim(),
|
||||||
|
FileType = FtpFileType.File
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return files;
|
||||||
|
}
|
||||||
|
|
||||||
|
public string[] ListFiles(string directory = "")
|
||||||
|
{
|
||||||
|
FtpWebRequest request = (FtpWebRequest)WebRequest.Create(new Uri($"{_ftpConfiguration.Url}/{directory}"));
|
||||||
|
request.Credentials = new NetworkCredential(_ftpConfiguration.Username, _ftpConfiguration.Password);
|
||||||
|
request.Method = WebRequestMethods.Ftp.ListDirectory;
|
||||||
|
|
||||||
|
using FtpWebResponse response = (FtpWebResponse)request.GetResponse();
|
||||||
|
using StreamReader reader = new StreamReader(response.GetResponseStream());
|
||||||
|
|
||||||
|
string files = reader.ReadToEnd();
|
||||||
|
|
||||||
|
return files.Length > 0
|
||||||
|
? files.Split("\r\n")
|
||||||
|
: Array.Empty<string>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public string Download(string filename, string destination = null)
|
||||||
|
{
|
||||||
|
FtpWebRequest request = (FtpWebRequest)WebRequest.Create(new Uri($"{_ftpConfiguration.Url}/{filename}"));
|
||||||
|
request.Credentials = new NetworkCredential(_ftpConfiguration.Username, _ftpConfiguration.Password);
|
||||||
|
request.Method = WebRequestMethods.Ftp.DownloadFile;
|
||||||
|
|
||||||
|
if (string.IsNullOrEmpty(destination))
|
||||||
|
{
|
||||||
|
destination = _ftpConfiguration.Destination;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Path.DirectorySeparatorChar == '\\')
|
||||||
|
{
|
||||||
|
filename = filename.Replace("/", "\\");
|
||||||
|
}
|
||||||
|
|
||||||
|
destination = Path.Combine(destination, filename);
|
||||||
|
string destinationDirectory = Path.GetDirectoryName(destination);
|
||||||
|
if (!Directory.Exists(destinationDirectory))
|
||||||
|
{
|
||||||
|
Directory.CreateDirectory(destinationDirectory);
|
||||||
|
}
|
||||||
|
|
||||||
|
using FtpWebResponse response = (FtpWebResponse)request.GetResponse();
|
||||||
|
using Stream responseStream = response.GetResponseStream();
|
||||||
|
using FileStream fileStream = new FileStream(destination, FileMode.Create);
|
||||||
|
|
||||||
|
responseStream.CopyTo(fileStream);
|
||||||
|
|
||||||
|
return destination;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Delete(string filename)
|
||||||
|
{
|
||||||
|
FtpWebRequest request = (FtpWebRequest)WebRequest.Create(new Uri($"{_ftpConfiguration.Url}/{filename}"));
|
||||||
|
request.Credentials = new NetworkCredential(_ftpConfiguration.Username, _ftpConfiguration.Password);
|
||||||
|
request.Method = WebRequestMethods.Ftp.DeleteFile;
|
||||||
|
|
||||||
|
|
||||||
|
using FtpWebResponse response = (FtpWebResponse)request.GetResponse();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ namespace PartSource.Automation.Services
|
|||||||
{
|
{
|
||||||
StartInfo = new ProcessStartInfo
|
StartInfo = new ProcessStartInfo
|
||||||
{
|
{
|
||||||
FileName = "dtexec",
|
FileName = "C:\\Program Files\\Microsoft SQL Server\\150\\DTS\\Binn\\dtexec.exe",
|
||||||
Arguments = $"/file \"{_ssisConfiguration.Directory}\\{packageName}\"",
|
Arguments = $"/file \"{_ssisConfiguration.Directory}\\{packageName}\"",
|
||||||
UseShellExecute = false,
|
UseShellExecute = false,
|
||||||
CreateNoWindow = false,
|
CreateNoWindow = false,
|
||||||
|
|||||||
130
PartSource.Automation/Services/VehicleFitmentService.cs
Normal file
130
PartSource.Automation/Services/VehicleFitmentService.cs
Normal file
@@ -0,0 +1,130 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using PartSource.Data.Contexts;
|
||||||
|
using PartSource.Data.Dtos;
|
||||||
|
using PartSource.Data.Models;
|
||||||
|
|
||||||
|
namespace PartSource.Automation.Services
|
||||||
|
{
|
||||||
|
public class VehicleFitmentService
|
||||||
|
{
|
||||||
|
private readonly FitmentContext _fitmentContext;
|
||||||
|
|
||||||
|
public VehicleFitmentService(FitmentContext fitmentContext)
|
||||||
|
{
|
||||||
|
_fitmentContext = fitmentContext;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IList<string> GetYmmFitment(IList<Vehicle> vehicles)
|
||||||
|
{
|
||||||
|
if (vehicles.Count == 0)
|
||||||
|
{
|
||||||
|
return new string[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
IList<string> fitmentTags = new List<string>();
|
||||||
|
|
||||||
|
IList<string> makeModels = vehicles.OrderBy(v => v.MakeName).ThenBy(v => v.ModelName).Select(v => $"{v.MakeName},{v.ModelName}").Distinct().ToList();
|
||||||
|
|
||||||
|
foreach (string makeModel in makeModels)
|
||||||
|
{
|
||||||
|
string make = makeModel.Split(',')[0];
|
||||||
|
string model = makeModel.Split(',')[1];
|
||||||
|
|
||||||
|
List<string> years = vehicles
|
||||||
|
.Where(v => v.MakeName == make && v.ModelName == model)
|
||||||
|
.OrderBy(v => v.Year)
|
||||||
|
.Select(v => v.Year.ToString().Trim())
|
||||||
|
.Distinct()
|
||||||
|
.ToList();
|
||||||
|
|
||||||
|
string tag = $"{string.Join('-', years)} {make.Trim()} {model.Trim()}";
|
||||||
|
|
||||||
|
System.Diagnostics.Debug.WriteLine(tag);
|
||||||
|
|
||||||
|
fitmentTags.Add(tag);
|
||||||
|
}
|
||||||
|
|
||||||
|
return fitmentTags;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IList<string> GetYmmFitmentRange(IList<Vehicle> vehicles)
|
||||||
|
{
|
||||||
|
if (vehicles.Count == 0)
|
||||||
|
{
|
||||||
|
return new string[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
IList<string> fitmentTags = new List<string>();
|
||||||
|
|
||||||
|
IList<string> makeModels = vehicles.Select(v => $"{v.MakeName},{v.ModelName}").Distinct().ToList();
|
||||||
|
|
||||||
|
foreach (string makeModel in makeModels)
|
||||||
|
{
|
||||||
|
string make = makeModel.Split(',')[0];
|
||||||
|
string model = makeModel.Split(',')[1];
|
||||||
|
|
||||||
|
int minYear = vehicles
|
||||||
|
.Where(v => v.MakeName == make && v.ModelName == model)
|
||||||
|
.Min(v => v.Year);
|
||||||
|
|
||||||
|
int maxYear = vehicles
|
||||||
|
.Where(v => v.MakeName == make && v.ModelName == model)
|
||||||
|
.Max(v => v.Year);
|
||||||
|
|
||||||
|
string tag = minYear == maxYear
|
||||||
|
? $"{minYear} {make.Trim()} {model.Trim()}"
|
||||||
|
: $"{minYear}-{maxYear} {make.Trim()} {model.Trim()}";
|
||||||
|
|
||||||
|
System.Diagnostics.Debug.WriteLine(tag);
|
||||||
|
|
||||||
|
fitmentTags.Add(tag);
|
||||||
|
}
|
||||||
|
|
||||||
|
return fitmentTags;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IList<int> GetVehicleIdFitment(IList<Vehicle> vehicles)
|
||||||
|
{
|
||||||
|
return vehicles != null
|
||||||
|
? vehicles.Select(v => v.VehicleToEngineConfigId).Distinct().ToArray()
|
||||||
|
: new List<int>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<IList<Vehicle>> GetVehiclesForPart(string partNumber, string lineCode, int maxVehicles = 0)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(partNumber) || string.IsNullOrEmpty(lineCode))
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
partNumber = Regex.Replace(partNumber, "[^a-zA-Z0-9]", string.Empty);
|
||||||
|
|
||||||
|
IList<string> whiCodes = await _fitmentContext.DcfMappings
|
||||||
|
.Where(dcf => dcf.LineCode == lineCode)
|
||||||
|
.Select(dcf => dcf.WhiCode)
|
||||||
|
.ToListAsync();
|
||||||
|
|
||||||
|
IQueryable<Vehicle> vehicles = _fitmentContext.Fitments
|
||||||
|
.Where(f => f.PartNumber == partNumber && whiCodes.Contains(f.LineCode))
|
||||||
|
.Join(_fitmentContext.Vehicles,
|
||||||
|
f => new { f.BaseVehicleId, f.EngineConfigId },
|
||||||
|
v => new { v.BaseVehicleId, v.EngineConfigId },
|
||||||
|
(f, v) => v)
|
||||||
|
.Distinct()
|
||||||
|
.OrderByDescending(x => x.Year);
|
||||||
|
|
||||||
|
if (maxVehicles > 0)
|
||||||
|
{
|
||||||
|
vehicles = vehicles.Take(maxVehicles);
|
||||||
|
}
|
||||||
|
|
||||||
|
return vehicles.ToList();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,166 +1,158 @@
|
|||||||
#pragma warning disable CA2100 // Review SQL queries for security vulnerabilities
|
#pragma warning disable CA2100 // Review SQL queries for security vulnerabilities
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Data;
|
|
||||||
using Microsoft.Data.SqlClient;
|
|
||||||
using Microsoft.Extensions.Configuration;
|
using Microsoft.Extensions.Configuration;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using PartSource.Automation.Models.Configuration;
|
using PartSource.Automation.Models.Configuration;
|
||||||
using PartSource.Automation.Models.Enums;
|
using PartSource.Automation.Models.Enums;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Concurrent;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Data;
|
||||||
|
using System.Data.SqlClient;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace PartSource.Automation.Services
|
namespace PartSource.Automation.Services
|
||||||
{
|
{
|
||||||
public class WhiSeoService
|
public class WhiSeoService
|
||||||
{
|
{
|
||||||
private readonly FtpService _ftpService;
|
private readonly FtpService _ftpService;
|
||||||
private readonly string _connectionString;
|
private readonly string _connectionString;
|
||||||
private readonly ILogger<WhiSeoService> _logger;
|
private readonly ILogger<WhiSeoService> _logger;
|
||||||
|
|
||||||
public WhiSeoService(IConfiguration configuration, ILogger<WhiSeoService> logger)
|
public WhiSeoService(IConfiguration configuration, ILogger<WhiSeoService> logger)
|
||||||
{
|
{
|
||||||
FtpConfiguration ftpConfiguration = configuration.GetSection("FtpServers:WhiConfiguration").Get<FtpConfiguration>();
|
FtpConfiguration ftpConfiguration = configuration.GetSection("FtpServers:WhiConfiguration").Get<FtpConfiguration>();
|
||||||
_ftpService = new FtpService(ftpConfiguration);
|
_ftpService = new FtpService(ftpConfiguration);
|
||||||
|
|
||||||
_connectionString = configuration.GetConnectionString("FitmentDatabase");
|
_connectionString = configuration.GetConnectionString("FitmentDatabase");
|
||||||
|
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void GetFiles(SeoDataType seoDataType)
|
public void GetFiles(SeoDataType seoDataType)
|
||||||
{
|
{
|
||||||
string seoDataTypeString = seoDataType.ToString().ToLowerInvariant();
|
string seoDataTypeString = seoDataType.ToString().ToLowerInvariant();
|
||||||
string[] files = _ftpService.ListFiles(seoDataTypeString);
|
|
||||||
|
// WHI changed the transfer protocol to SFTP and then messed with the directory structure.
|
||||||
|
// Since fitment isn't really all that automated anyway, just download the files manually with an SFTP client.
|
||||||
|
Console.WriteLine($"Remember to manually download the {seoDataTypeString} files with an SFTP client. Press any key to continue.");
|
||||||
|
Console.ReadLine();
|
||||||
|
}
|
||||||
|
|
||||||
foreach (string file in files)
|
public void TruncateVehicleTable()
|
||||||
{
|
{
|
||||||
if (file.Contains(".csv"))
|
using SqlConnection connection = new SqlConnection(_connectionString);
|
||||||
{
|
connection.Open();
|
||||||
try
|
|
||||||
{
|
|
||||||
_ftpService.Download($"{seoDataTypeString}/{file}");
|
|
||||||
_logger.LogInformation($"Finished downloading {file}.");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
using SqlCommand command = new SqlCommand($"truncate table dbo.Vehicle", connection);
|
||||||
|
command.ExecuteNonQuery();
|
||||||
|
}
|
||||||
|
|
||||||
catch (Exception ex)
|
public void TruncateFitmentTables()
|
||||||
{
|
{
|
||||||
_logger.LogWarning($"Failed to download {file}, quitting", ex);
|
using SqlConnection connection = new SqlConnection(_connectionString);
|
||||||
throw;
|
connection.Open();
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void TruncateVehicleTables()
|
using SqlCommand command = new SqlCommand($"exec DropFitmentTables", connection);
|
||||||
{
|
command.ExecuteNonQuery();
|
||||||
using SqlConnection connection = new SqlConnection(_connectionString);
|
}
|
||||||
connection.Open();
|
|
||||||
|
|
||||||
using SqlCommand command = new SqlCommand($"exec DropVehicleTables", connection);
|
public void SaveNotes(IDictionary<string, string> notes)
|
||||||
command.ExecuteNonQuery();
|
{
|
||||||
}
|
using DataTable dataTable = new DataTable();
|
||||||
|
dataTable.Columns.Add("NoteText", typeof(string));
|
||||||
|
dataTable.Columns.Add("Hash", typeof(string));
|
||||||
|
|
||||||
public void TruncateFitmentTables()
|
foreach (KeyValuePair<string, string> note in notes)
|
||||||
{
|
{
|
||||||
using SqlConnection connection = new SqlConnection(_connectionString);
|
|
||||||
connection.Open();
|
|
||||||
|
|
||||||
using SqlCommand command = new SqlCommand($"exec DropFitmentTables", connection);
|
dataTable.Rows.Add(new string[] { note.Value, note.Key });
|
||||||
command.ExecuteNonQuery();
|
}
|
||||||
}
|
|
||||||
|
|
||||||
public void SaveNotes(IDictionary<string, string> notes)
|
using SqlConnection connection = new SqlConnection(_connectionString);
|
||||||
{
|
connection.Open();
|
||||||
using DataTable dataTable = new DataTable();
|
|
||||||
dataTable.Columns.Add("NoteText", typeof(string));
|
|
||||||
dataTable.Columns.Add("Hash", typeof(string));
|
|
||||||
|
|
||||||
foreach (KeyValuePair<string, string> note in notes)
|
using SqlBulkCopy bulk = new SqlBulkCopy(connection)
|
||||||
{
|
{
|
||||||
|
DestinationTableName = $"FitmentNote",
|
||||||
|
BulkCopyTimeout = 14400
|
||||||
|
};
|
||||||
|
|
||||||
dataTable.Rows.Add(new string[] { note.Value, note.Key });
|
bulk.WriteToServer(dataTable);
|
||||||
}
|
}
|
||||||
|
|
||||||
using SqlConnection connection = new SqlConnection(_connectionString);
|
public void BulkCopyFitment(DataTable dataTable, string tableName)
|
||||||
connection.Open();
|
{
|
||||||
|
using SqlConnection connection = new SqlConnection(_connectionString);
|
||||||
|
connection.Open();
|
||||||
|
|
||||||
using SqlBulkCopy bulk = new SqlBulkCopy(connection)
|
string sql = string.Empty;
|
||||||
{
|
|
||||||
DestinationTableName = $"FitmentNote",
|
|
||||||
BulkCopyTimeout = 14400
|
|
||||||
};
|
|
||||||
|
|
||||||
bulk.WriteToServer(dataTable);
|
using SqlCommand command = new SqlCommand($"EXEC CreateFitmentTempTable @tableName = '{tableName}'", connection);
|
||||||
}
|
command.ExecuteNonQuery();
|
||||||
|
|
||||||
public void BulkCopyFitment(DataTable dataTable, string tableName)
|
using SqlBulkCopy bulk = new SqlBulkCopy(connection)
|
||||||
{
|
{
|
||||||
using SqlConnection connection = new SqlConnection(_connectionString);
|
DestinationTableName = $"FitmentTemp.{tableName}",
|
||||||
connection.Open();
|
BulkCopyTimeout = 14400
|
||||||
|
};
|
||||||
|
|
||||||
string sql = string.Empty;
|
bulk.WriteToServer(dataTable);
|
||||||
|
}
|
||||||
|
|
||||||
using SqlCommand command = new SqlCommand($"EXEC CreateFitmentTempTable @tableName = '{tableName}'", connection);
|
public void BulkCopyVehicle(DataTable dataTable, string tableName)
|
||||||
command.ExecuteNonQuery();
|
{
|
||||||
|
using SqlConnection connection = new SqlConnection(_connectionString);
|
||||||
|
connection.Open();
|
||||||
|
|
||||||
using SqlBulkCopy bulk = new SqlBulkCopy(connection)
|
string sql = string.Empty;
|
||||||
{
|
|
||||||
DestinationTableName = $"FitmentTemp.{tableName}",
|
|
||||||
BulkCopyTimeout = 14400
|
|
||||||
};
|
|
||||||
|
|
||||||
bulk.WriteToServer(dataTable);
|
using SqlCommand command = new SqlCommand($"EXEC CreateVehicleTempTable @tableName = '{tableName}'", connection);
|
||||||
}
|
command.ExecuteNonQuery();
|
||||||
|
|
||||||
public void BulkCopyVehicle(DataTable dataTable, string tableName)
|
using SqlBulkCopy bulk = new SqlBulkCopy(connection)
|
||||||
{
|
{
|
||||||
using SqlConnection connection = new SqlConnection(_connectionString);
|
DestinationTableName = $"VehicleTemp.{tableName}",
|
||||||
connection.Open();
|
BulkCopyTimeout = 14400
|
||||||
|
};
|
||||||
|
|
||||||
string sql = string.Empty;
|
bulk.WriteToServer(dataTable);
|
||||||
|
}
|
||||||
|
|
||||||
using SqlCommand command = new SqlCommand($"EXEC CreateVehicleTempTable @tableName = '{tableName}'", connection);
|
public void CreateFitmentTable(string tableName)
|
||||||
command.ExecuteNonQuery();
|
{
|
||||||
|
using SqlConnection connection = new SqlConnection(_connectionString);
|
||||||
|
connection.Open();
|
||||||
|
|
||||||
using SqlBulkCopy bulk = new SqlBulkCopy(connection)
|
using SqlCommand command = new SqlCommand($"exec CreateFitmentTable @tableName = '{tableName}'", connection);
|
||||||
{
|
command.CommandTimeout = 1800;
|
||||||
DestinationTableName = $"VehicleTemp.{tableName}",
|
command.ExecuteNonQuery();
|
||||||
BulkCopyTimeout = 14400
|
}
|
||||||
};
|
|
||||||
|
|
||||||
bulk.WriteToServer(dataTable);
|
public void CreateFitmentView()
|
||||||
}
|
{
|
||||||
|
using SqlConnection connection = new SqlConnection(_connectionString);
|
||||||
|
connection.Open();
|
||||||
|
|
||||||
public void CreateFitmentTable(string tableName)
|
using SqlCommand command = new SqlCommand($"exec CreateFitmentView", connection);
|
||||||
{
|
command.CommandTimeout = 1800;
|
||||||
using SqlConnection connection = new SqlConnection(_connectionString);
|
command.ExecuteNonQuery();
|
||||||
connection.Open();
|
|
||||||
|
|
||||||
using SqlCommand command = new SqlCommand($"exec CreateFitmentTable @tableName = '{tableName}'", connection);
|
using SqlCommand command2 = new SqlCommand($"exec CreateFitmentIndexes", connection);
|
||||||
command.CommandTimeout = 1800;
|
command.CommandTimeout = 3600;
|
||||||
command.ExecuteNonQuery();
|
command2.ExecuteNonQuery();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void CreateFitmentView()
|
public void CreateVehicleTable()
|
||||||
{
|
{
|
||||||
using SqlConnection connection = new SqlConnection(_connectionString);
|
using SqlConnection connection = new SqlConnection(_connectionString);
|
||||||
connection.Open();
|
connection.Open();
|
||||||
|
|
||||||
using SqlCommand command = new SqlCommand($"exec CreateFitmentView", connection);
|
using SqlCommand command = new SqlCommand($"exec CreateVehicleTable", connection);
|
||||||
command.CommandTimeout = 1800;
|
command.CommandTimeout = 1800;
|
||||||
command.ExecuteNonQuery();
|
command.ExecuteNonQuery();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
public void CreateVehicleTable()
|
|
||||||
{
|
|
||||||
using SqlConnection connection = new SqlConnection(_connectionString);
|
|
||||||
connection.Open();
|
|
||||||
|
|
||||||
using SqlCommand command = new SqlCommand($"exec CreateVehicleTable", connection);
|
|
||||||
command.CommandTimeout = 1800;
|
|
||||||
command.ExecuteNonQuery();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
#pragma warning restore CA2100 // Review SQL queries for security vulnerabilities
|
#pragma warning restore CA2100 // Review SQL queries for security vulnerabilities
|
||||||
@@ -1,26 +1,28 @@
|
|||||||
{
|
{
|
||||||
"ConnectionStrings": {
|
"ConnectionStrings": {
|
||||||
"FitmentDatabase": "Data Source=localhost;Initial Catalog=WhiFitment;Integrated Security=true",
|
"FitmentDatabase": "Data Source=localhost;Initial Catalog=WhiFitment;Integrated Security=true;TrustServerCertificate=true",
|
||||||
|
//"FitmentDatabase": "Server=tcp:ps-automation.eastus2.cloudapp.azure.com,1433;Initial Catalog=WhiFitment;User ID=sa;Password=GZ0`-ekd~[2u;Encrypt=True;TrustServerCertificate=True;Connection Timeout=300",
|
||||||
"PartSourceDatabase": "Server=tcp:ps-whi.database.windows.net,1433;Initial Catalog=ps-whi-stage;Persist Security Info=False;User ID=ps-whi;Password=9-^*N5dw!6:|.5Q;MultipleActiveResultSets=True;Encrypt=True;TrustServerCertificate=False;Connection Timeout=30;"
|
"PartSourceDatabase": "Server=tcp:ps-whi.database.windows.net,1433;Initial Catalog=ps-whi-stage;Persist Security Info=False;User ID=ps-whi;Password=9-^*N5dw!6:|.5Q;MultipleActiveResultSets=True;Encrypt=True;TrustServerCertificate=False;Connection Timeout=30;"
|
||||||
},
|
},
|
||||||
"emailConfiguration": {
|
"emailConfiguration": {
|
||||||
"From": "alerts@ps-automation.eastus2.cloudapp.azure.com",
|
"From": "alerts@ps-automation.eastus2.cloudapp.azure.com",
|
||||||
"To": "tom@soundpress.com,Anas.Bajwa@Partsource.ca,josh@soundpress.com,alex.au@partsource.ca,michael.massara@partsource.ca",
|
"To": "tom@soundpress.com,josh@soundpress.com,alex.au@partsource.ca,michael.massara@partsource.ca",
|
||||||
//"To": "tom@tomraterman.com",
|
//"To": "tom@tomraterman.com,josh@soundpress.com",
|
||||||
"SmtpHost": "localhost"
|
"SmtpHost": "localhost"
|
||||||
},
|
},
|
||||||
"FtpServers": {
|
"FtpServers": {
|
||||||
"AzureConfiguration": {
|
|
||||||
"Username": "ps-ftp\\$ps-ftp",
|
|
||||||
"Password": "ycvXptffBxqkBXW4vuRYqn4Zi1soCvnvMMolTe5HNSeAlcl3bAyJYtNhG579",
|
|
||||||
"Url": "ftp://waws-prod-yq1-007.ftp.azurewebsites.windows.net/site/wwwroot",
|
|
||||||
"Destination": "C:\\Partsource.Automation\\Downloads"
|
|
||||||
},
|
|
||||||
"WhiConfiguration": {
|
"WhiConfiguration": {
|
||||||
"Username": "ctc_seo",
|
"Username": "ctc_seo",
|
||||||
"Password": "be34hz64e4",
|
"Password": "YD3gtaQ5kPdtNKs",
|
||||||
"Url": "ftp://ftp.whisolutions.com",
|
"Url": "ftp://ftp.whisolutions.com",
|
||||||
"Destination": "C:\\Partsource.Automation\\Downloads\\WHI"
|
"Destination": "C:\\Partsource.Automation\\Downloads\\WHI",
|
||||||
|
"Port": 3001
|
||||||
|
},
|
||||||
|
"AutomationConfiguration": {
|
||||||
|
"Username": "stageuser",
|
||||||
|
"Password": "FXepK^cFYS|[H<",
|
||||||
|
"Url": "ftp://localhost",
|
||||||
|
"Destination": "C:\\Partsource.Automation\\Downloads"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"ssisConfiguration": {
|
"ssisConfiguration": {
|
||||||
|
|||||||
@@ -13,13 +13,19 @@ namespace PartSource.Data.Contexts
|
|||||||
|
|
||||||
public DbSet<DcfMapping> DcfMappings { get; set; }
|
public DbSet<DcfMapping> DcfMappings { get; set; }
|
||||||
|
|
||||||
|
public DbSet<Part> Parts { get; set; }
|
||||||
|
|
||||||
public DbSet<Fitment> Fitments { get; set; }
|
public DbSet<Fitment> Fitments { get; set; }
|
||||||
|
|
||||||
public DbSet<FitmentNote> FitmentNotes { get; set; }
|
public DbSet<FitmentNote> FitmentNotes { get; set; }
|
||||||
|
|
||||||
|
public DbSet<ProductType> ProductTypes { get; set; }
|
||||||
|
|
||||||
public DbSet<Vehicle> Vehicles { get; set; }
|
public DbSet<Vehicle> Vehicles { get; set; }
|
||||||
|
|
||||||
public DbSet<Wiper> Wipers { get; set; }
|
public DbSet<VehicleFitment> VehicleFitments { get; set; }
|
||||||
|
|
||||||
|
public DbSet<Wiper> Wipers { get; set; }
|
||||||
|
|
||||||
protected override void OnModelCreating(ModelBuilder modelBuilder)
|
protected override void OnModelCreating(ModelBuilder modelBuilder)
|
||||||
{
|
{
|
||||||
@@ -28,8 +34,9 @@ namespace PartSource.Data.Contexts
|
|||||||
modelBuilder.Entity<DcfMapping>().HasKey(d => new { d.LineCode, d.WhiCode });
|
modelBuilder.Entity<DcfMapping>().HasKey(d => new { d.LineCode, d.WhiCode });
|
||||||
modelBuilder.Entity<Fitment>().HasKey(f => new { f.BaseVehicleId, f.EngineConfigId, f.LineCode, f.PartNumber });
|
modelBuilder.Entity<Fitment>().HasKey(f => new { f.BaseVehicleId, f.EngineConfigId, f.LineCode, f.PartNumber });
|
||||||
modelBuilder.Entity<Wiper>().HasKey(f => new { f.BaseVehicleId, f.PartNumber, f.LineCode, f.Position});
|
modelBuilder.Entity<Wiper>().HasKey(f => new { f.BaseVehicleId, f.PartNumber, f.LineCode, f.Position});
|
||||||
|
modelBuilder.Entity<VehicleFitment>().HasNoKey();
|
||||||
|
|
||||||
foreach (IMutableEntityType entityType in modelBuilder.Model.GetEntityTypes())
|
foreach (IMutableEntityType entityType in modelBuilder.Model.GetEntityTypes())
|
||||||
{
|
{
|
||||||
entityType.SetTableName(entityType.ClrType.Name);
|
entityType.SetTableName(entityType.ClrType.Name);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,13 +26,13 @@ namespace PartSource.Data.Contexts
|
|||||||
|
|
||||||
public DbSet<PartPrice> PartPrices { get; set; }
|
public DbSet<PartPrice> PartPrices { get; set; }
|
||||||
|
|
||||||
public DbSet<Part> Parts { get; set; }
|
// public DbSet<Part> Parts { get; set; }
|
||||||
|
|
||||||
public DbSet<ShopifyChangelog> ShopifyChangelogs { get; set; }
|
public DbSet<ShopifyChangelog> ShopifyChangelogs { get; set; }
|
||||||
|
|
||||||
public DbSet<Vehicle> Vehicles { get; set; }
|
public DbSet<Vehicle> Vehicles { get; set; }
|
||||||
|
|
||||||
public DbSet<PartsAvailability> PartAvailabilities { get; set; }
|
public DbSet<PartAvailability> PartAvailabilities { get; set; }
|
||||||
|
|
||||||
public DbSet<BaseVehicle> BaseVehicles { get; set; }
|
public DbSet<BaseVehicle> BaseVehicles { get; set; }
|
||||||
|
|
||||||
@@ -48,7 +48,7 @@ namespace PartSource.Data.Contexts
|
|||||||
{
|
{
|
||||||
base.OnModelCreating(modelBuilder);
|
base.OnModelCreating(modelBuilder);
|
||||||
|
|
||||||
modelBuilder.Entity<PartsAvailability>().HasKey(p => new { p.Store, p.SKU });
|
modelBuilder.Entity<PartAvailability>().HasKey(p => new { p.Store, p.SKU });
|
||||||
modelBuilder.Entity<DcfMapping>().HasKey(d => new { d.LineCode, d.WhiCode });
|
modelBuilder.Entity<DcfMapping>().HasKey(d => new { d.LineCode, d.WhiCode });
|
||||||
|
|
||||||
modelBuilder.Entity<ShopifyChangelog>()
|
modelBuilder.Entity<ShopifyChangelog>()
|
||||||
|
|||||||
@@ -5,10 +5,15 @@ using System.Text;
|
|||||||
|
|
||||||
namespace PartSource.Data.Dtos
|
namespace PartSource.Data.Dtos
|
||||||
{
|
{
|
||||||
public class VehicleFitmentDto
|
public class VehicleFitmentDto : VehicleFitment
|
||||||
{
|
{
|
||||||
public Fitment Fitment { get; set; }
|
public string PartDescription { get; set; }
|
||||||
|
|
||||||
|
// May not be needed, but don't remove just yet
|
||||||
|
public IList<string> SubmodelNames { get; set; }
|
||||||
|
|
||||||
public Vehicle Vehicle { get; set; }
|
public IList<string> DriveTypes { get; set; }
|
||||||
}
|
|
||||||
}
|
public IList<string> Notes { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,9 +1,10 @@
|
|||||||
using System.ComponentModel.DataAnnotations;
|
using System;
|
||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
using System.ComponentModel.DataAnnotations.Schema;
|
using System.ComponentModel.DataAnnotations.Schema;
|
||||||
|
|
||||||
namespace PartSource.Data.Models
|
namespace PartSource.Data.Models
|
||||||
{
|
{
|
||||||
public class PartsAvailability
|
public class PartAvailability
|
||||||
{
|
{
|
||||||
[Column(Order = 0)]
|
[Column(Order = 0)]
|
||||||
[DatabaseGenerated(DatabaseGeneratedOption.None)]
|
[DatabaseGenerated(DatabaseGeneratedOption.None)]
|
||||||
@@ -13,14 +14,8 @@ namespace PartSource.Data.Models
|
|||||||
[DatabaseGenerated(DatabaseGeneratedOption.None)]
|
[DatabaseGenerated(DatabaseGeneratedOption.None)]
|
||||||
public int SKU { get; set; }
|
public int SKU { get; set; }
|
||||||
|
|
||||||
[Column("Line Code")]
|
|
||||||
[StringLength(50)]
|
|
||||||
public string Line_Code { get; set; }
|
|
||||||
|
|
||||||
[Column("Part Number")]
|
|
||||||
[StringLength(50)]
|
|
||||||
public string Part_Number { get; set; }
|
|
||||||
|
|
||||||
public int? QTY { get; set; }
|
public int? QTY { get; set; }
|
||||||
|
|
||||||
|
public string Updated { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
17
PartSource.Data/Models/ProductType.cs
Normal file
17
PartSource.Data/Models/ProductType.cs
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace PartSource.Data.Models
|
||||||
|
{
|
||||||
|
public class ProductType
|
||||||
|
{
|
||||||
|
[Key]
|
||||||
|
public string Name { get; set; }
|
||||||
|
|
||||||
|
public bool Active { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
30
PartSource.Data/Models/VehicleFitment.cs
Normal file
30
PartSource.Data/Models/VehicleFitment.cs
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
|
namespace PartSource.Data.Models
|
||||||
|
{
|
||||||
|
public class VehicleFitment
|
||||||
|
{
|
||||||
|
public string Sku { get; set; }
|
||||||
|
|
||||||
|
public string LineCode { get; set; }
|
||||||
|
|
||||||
|
public string PartNumber { get; set; }
|
||||||
|
|
||||||
|
[JsonIgnore]
|
||||||
|
public string NoteText { get; set; }
|
||||||
|
|
||||||
|
public int Year { get; set; }
|
||||||
|
|
||||||
|
public string MakeName { get; set; }
|
||||||
|
|
||||||
|
public string ModelName { get; set; }
|
||||||
|
|
||||||
|
public string SubmodelName { get; set; }
|
||||||
|
|
||||||
|
public int BaseVehicleId { get; set; }
|
||||||
|
|
||||||
|
public int EngineConfigId { get; set; }
|
||||||
|
|
||||||
|
public int VehicleToEngineConfigId { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -5,7 +5,7 @@ using System.Xml.Serialization;
|
|||||||
|
|
||||||
namespace PartSource.Data.Nexpart
|
namespace PartSource.Data.Nexpart
|
||||||
{
|
{
|
||||||
[XmlType(AnonymousType = true, Namespace = "http://whisolutions.com/PartSelectServ/2011-07-21")]
|
[XmlType(AnonymousType = true, Namespace = "http://whisolutions.com/pss/common/helper/parts")]
|
||||||
public class AddImg
|
public class AddImg
|
||||||
{
|
{
|
||||||
[XmlAttribute]
|
[XmlAttribute]
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ using System.Xml.Serialization;
|
|||||||
|
|
||||||
namespace PartSource.Data.Nexpart
|
namespace PartSource.Data.Nexpart
|
||||||
{
|
{
|
||||||
[XmlType(AnonymousType = true, Namespace = "http://whisolutions.com/PartSelectServ/2011-07-21")]
|
[XmlType(AnonymousType = true, Namespace = "http://whisolutions.com/pss/common/helper/parts")]
|
||||||
public class AddImgs
|
public class AddImgs
|
||||||
{
|
{
|
||||||
[XmlElement]
|
[XmlElement]
|
||||||
|
|||||||
22
PartSource.Data/Nexpart/Answer.cs
Normal file
22
PartSource.Data/Nexpart/Answer.cs
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Xml.Serialization;
|
||||||
|
|
||||||
|
namespace PartSource.Data.Nexpart
|
||||||
|
{
|
||||||
|
[XmlType(Namespace = "http://whisolutions.com/pss/common/helper/parts")]
|
||||||
|
public class Answer
|
||||||
|
{
|
||||||
|
[XmlAttribute]
|
||||||
|
public int Id { get; set; }
|
||||||
|
|
||||||
|
[XmlAttribute]
|
||||||
|
public int Count { get; set; }
|
||||||
|
|
||||||
|
[XmlText]
|
||||||
|
public string Value { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -8,7 +8,7 @@ using Newtonsoft.Json;
|
|||||||
|
|
||||||
namespace PartSource.Data.Nexpart
|
namespace PartSource.Data.Nexpart
|
||||||
{
|
{
|
||||||
[XmlType(AnonymousType = true, Namespace = "http://whisolutions.com/PartSelectServ/2011-07-21")]
|
[XmlType(AnonymousType = true, Namespace = "http://whisolutions.com/pss/common/helper/parts")]
|
||||||
public class App
|
public class App
|
||||||
{
|
{
|
||||||
[XmlElement]
|
[XmlElement]
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ using System.Xml.Serialization;
|
|||||||
|
|
||||||
namespace PartSource.Data.Nexpart
|
namespace PartSource.Data.Nexpart
|
||||||
{
|
{
|
||||||
[XmlType(AnonymousType = true, Namespace = "http://whisolutions.com/PartSelectService-v1")]
|
[XmlType(AnonymousType = true, Namespace = "http://whisolutions.com/pss/common/model/parts")]
|
||||||
public class ApplicationSearch
|
public class ApplicationSearch
|
||||||
{
|
{
|
||||||
public ApplicationSearch()
|
public ApplicationSearch()
|
||||||
@@ -31,9 +31,15 @@ namespace PartSource.Data.Nexpart
|
|||||||
public bool SecondaryDCF => true;
|
public bool SecondaryDCF => true;
|
||||||
|
|
||||||
[XmlElement(Order = 6)]
|
[XmlElement(Order = 6)]
|
||||||
public Criterion[] Criterion { get; set; }
|
public string[] AppOption { get; set; }
|
||||||
|
|
||||||
[XmlElement(Order = 7)]
|
[XmlElement(Order = 7)]
|
||||||
|
public Criterion[] Criterion { get; set; }
|
||||||
|
|
||||||
|
[XmlElement(Order = 8)]
|
||||||
public string GroupBy { get; set; }
|
public string GroupBy { get; set; }
|
||||||
|
|
||||||
|
[XmlElement(Order = 9)]
|
||||||
|
public string QuestionOption { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,14 +8,14 @@ using PartSource.Data.Nexpart.Interfaces;
|
|||||||
|
|
||||||
namespace PartSource.Data.Nexpart
|
namespace PartSource.Data.Nexpart
|
||||||
{
|
{
|
||||||
[XmlType(AnonymousType = true, Namespace = "http://whisolutions.com/PartSelectService-v1")]
|
[XmlType(AnonymousType = true, Namespace = "http://whisolutions.com/pss/common/model/parts")]
|
||||||
public class ApplicationSearchResponse : IResponseElement<Apps>
|
public class ApplicationSearchResponse : IResponseElement<object>
|
||||||
{
|
{
|
||||||
|
|
||||||
[XmlElement]
|
[XmlElement]
|
||||||
public PSResponseHeader PSResponseHeader { get; set; }
|
public PSResponseHeader PSResponseHeader { get; set; }
|
||||||
|
|
||||||
[XmlElement(ElementName = nameof(Apps))]
|
[XmlElement(ElementName = nameof(Apps), Namespace = "http://whisolutions.com/pss/common/model/parts", Type = typeof(Apps))]
|
||||||
public Apps ResponseBody { get; set; }
|
[XmlElement(ElementName = nameof(Questions), Namespace = "http://whisolutions.com/pss/common/model/parts", Type = typeof(Questions))]
|
||||||
|
public object ResponseBody { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,10 +3,10 @@ using Newtonsoft.Json;
|
|||||||
|
|
||||||
namespace PartSource.Data.Nexpart
|
namespace PartSource.Data.Nexpart
|
||||||
{
|
{
|
||||||
[XmlType(AnonymousType = true, Namespace = "http://whisolutions.com/PartSelectServ/2011-07-21")]
|
[XmlType(AnonymousType = true, Namespace = "http://whisolutions.com/pss/common/helper/parts")]
|
||||||
public class Apps
|
public class Apps
|
||||||
{
|
{
|
||||||
[XmlElement(Namespace = "http://whisolutions.com/PartSelectServ/2011-07-21")]
|
[XmlElement(Namespace = "http://whisolutions.com/pss/common/helper/parts")]
|
||||||
[JsonProperty("wipers")]
|
[JsonProperty("wipers")]
|
||||||
public App[] App { get; set; }
|
public App[] App { get; set; }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ using System.Xml.Serialization;
|
|||||||
|
|
||||||
namespace PartSource.Data.Nexpart
|
namespace PartSource.Data.Nexpart
|
||||||
{
|
{
|
||||||
[XmlType(AnonymousType = true, Namespace = "http://whisolutions.com/PartSelectServ/2011-07-21")]
|
[XmlType(AnonymousType = true, Namespace = "http://whisolutions.com/pss/common/helper/parts")]
|
||||||
public class BaseVehicle
|
public class BaseVehicle
|
||||||
{
|
{
|
||||||
[XmlAttribute]
|
[XmlAttribute]
|
||||||
|
|||||||
@@ -8,22 +8,22 @@ using System.Xml.Serialization;
|
|||||||
|
|
||||||
namespace PartSource.Data.Nexpart
|
namespace PartSource.Data.Nexpart
|
||||||
{
|
{
|
||||||
[XmlType(AnonymousType = true, Namespace = "http://whisolutions.com/PartSelectService-v1")]
|
[XmlType(AnonymousType = true, Namespace = "http://whisolutions.com/pss/common/model/parts")]
|
||||||
public class BaseVehicleDetail
|
public class BaseVehicleDetail
|
||||||
{
|
{
|
||||||
[XmlAttribute]
|
[XmlAttribute]
|
||||||
public int WHIMakeId { get; set; }
|
public int WHIMakeId { get; set; }
|
||||||
|
|
||||||
[XmlElement(Namespace = "http://whisolutions.com/PartSelectServ/2011-07-21")]
|
[XmlElement(Namespace = "http://whisolutions.com/pss/common/helper/parts")]
|
||||||
public int BaseVehicleId { get; set; }
|
public int BaseVehicleId { get; set; }
|
||||||
|
|
||||||
[XmlElement(Namespace = "http://whisolutions.com/PartSelectServ/2011-07-21")]
|
[XmlElement(Namespace = "http://whisolutions.com/pss/common/helper/parts")]
|
||||||
public string MakeName { get; set; }
|
public string MakeName { get; set; }
|
||||||
|
|
||||||
[XmlElement(Namespace = "http://whisolutions.com/PartSelectServ/2011-07-21")]
|
[XmlElement(Namespace = "http://whisolutions.com/pss/common/helper/parts")]
|
||||||
public string ModelName { get; set; }
|
public string ModelName { get; set; }
|
||||||
|
|
||||||
[XmlElement(Namespace = "http://whisolutions.com/PartSelectServ/2011-07-21")]
|
[XmlElement(Namespace = "http://whisolutions.com/pss/common/helper/parts")]
|
||||||
public int Year { get; set; }
|
public int Year { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ using System.Xml.Serialization;
|
|||||||
|
|
||||||
namespace PartSource.Data.Nexpart
|
namespace PartSource.Data.Nexpart
|
||||||
{
|
{
|
||||||
[XmlType(AnonymousType = true, Namespace = "http://whisolutions.com/PartSelectService-v1")]
|
[XmlType(AnonymousType = true, Namespace = "http://whisolutions.com/pss/common/model/parts")]
|
||||||
public class BaseVehicleDetailLookup
|
public class BaseVehicleDetailLookup
|
||||||
{
|
{
|
||||||
public BaseVehicleDetailLookup()
|
public BaseVehicleDetailLookup()
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ using System.Xml.Serialization;
|
|||||||
|
|
||||||
namespace PartSource.Data.Nexpart
|
namespace PartSource.Data.Nexpart
|
||||||
{
|
{
|
||||||
[XmlType(AnonymousType = true, Namespace = "http://whisolutions.com/PartSelectService-v1")]
|
[XmlType(AnonymousType = true, Namespace = "http://whisolutions.com/pss/common/model/parts")]
|
||||||
public class BaseVehicleDetailLookupResponse : IResponseElement<BaseVehicleDetail>
|
public class BaseVehicleDetailLookupResponse : IResponseElement<BaseVehicleDetail>
|
||||||
{
|
{
|
||||||
[XmlElement]
|
[XmlElement]
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
namespace PartSource.Data.Nexpart
|
namespace PartSource.Data.Nexpart
|
||||||
{
|
{
|
||||||
[XmlType(AnonymousType = true, Namespace = "http://whisolutions.com/PartSelectService-v1")]
|
[XmlType(AnonymousType = true, Namespace = "http://whisolutions.com/pss/common/model/parts")]
|
||||||
public class BaseVehicleSearch
|
public class BaseVehicleSearch
|
||||||
{
|
{
|
||||||
public BaseVehicleSearch()
|
public BaseVehicleSearch()
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ using System.Xml.Serialization;
|
|||||||
|
|
||||||
namespace PartSource.Data.Nexpart
|
namespace PartSource.Data.Nexpart
|
||||||
{
|
{
|
||||||
[XmlType(AnonymousType = true, Namespace = "http://whisolutions.com/PartSelectService-v1")]
|
[XmlType(AnonymousType = true, Namespace = "http://whisolutions.com/pss/common/model/parts")]
|
||||||
public class BaseVehicleSearchResponse : IResponseElement<BaseVehicles>
|
public class BaseVehicleSearchResponse : IResponseElement<BaseVehicles>
|
||||||
{
|
{
|
||||||
[XmlElement]
|
[XmlElement]
|
||||||
|
|||||||
@@ -5,10 +5,10 @@ using System.Xml.Serialization;
|
|||||||
|
|
||||||
namespace PartSource.Data.Nexpart
|
namespace PartSource.Data.Nexpart
|
||||||
{
|
{
|
||||||
[XmlType(AnonymousType = true, Namespace = "http://whisolutions.com/PartSelectService-v1")]
|
[XmlType(AnonymousType = true, Namespace = "http://whisolutions.com/pss/common/model/parts")]
|
||||||
public class BaseVehicles
|
public class BaseVehicles
|
||||||
{
|
{
|
||||||
[XmlElement(Namespace = "http://whisolutions.com/PartSelectServ/2011-07-21")]
|
[XmlElement(Namespace = "http://whisolutions.com/pss/common/helper/parts")]
|
||||||
public BaseVehicle[] BaseVehicle { get; set; }
|
public BaseVehicle[] BaseVehicle { get; set; }
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -8,37 +8,37 @@ using System.Xml.Serialization;
|
|||||||
|
|
||||||
namespace PartSource.Data.Nexpart
|
namespace PartSource.Data.Nexpart
|
||||||
{
|
{
|
||||||
[XmlType(AnonymousType = true, Namespace = "http://whisolutions.com/PartSelectService-v1")]
|
[XmlType(AnonymousType = true, Namespace = "http://whisolutions.com/pss/common/model/parts")]
|
||||||
public class Body
|
public class Body
|
||||||
{
|
{
|
||||||
[XmlElement(ElementName = "ApplicationSearch", Namespace = "http://whisolutions.com/PartSelectService-v1", Type = typeof(ApplicationSearch))]
|
[XmlElement(ElementName = "ApplicationSearch", Namespace = "http://whisolutions.com/pss/common/model/parts", Type = typeof(ApplicationSearch))]
|
||||||
[XmlElement(ElementName = "ApplicationSearchResponse", Namespace = "http://whisolutions.com/PartSelectService-v1", Type = typeof(ApplicationSearchResponse))]
|
[XmlElement(ElementName = "ApplicationSearchResponse", Namespace = "http://whisolutions.com/pss/common/model/parts", Type = typeof(ApplicationSearchResponse))]
|
||||||
[XmlElement(ElementName = "BaseVehicleDetailLookup", Namespace = "http://whisolutions.com/PartSelectService-v1", Type = typeof(BaseVehicleDetailLookup))]
|
[XmlElement(ElementName = "BaseVehicleDetailLookup", Namespace = "http://whisolutions.com/pss/common/model/parts", Type = typeof(BaseVehicleDetailLookup))]
|
||||||
[XmlElement(ElementName = "BaseVehicleDetailLookupResponse", Namespace = "http://whisolutions.com/PartSelectService-v1", Type = typeof(BaseVehicleDetailLookupResponse))]
|
[XmlElement(ElementName = "BaseVehicleDetailLookupResponse", Namespace = "http://whisolutions.com/pss/common/model/parts", Type = typeof(BaseVehicleDetailLookupResponse))]
|
||||||
[XmlElement(ElementName = "BaseVehicleSearch", Namespace = "http://whisolutions.com/PartSelectService-v1", Type = typeof(BaseVehicleSearch))]
|
[XmlElement(ElementName = "BaseVehicleSearch", Namespace = "http://whisolutions.com/pss/common/model/parts", Type = typeof(BaseVehicleSearch))]
|
||||||
[XmlElement(ElementName = "BaseVehicleSearchResponse", Namespace = "http://whisolutions.com/PartSelectService-v1", Type = typeof(BaseVehicleSearchResponse))]
|
[XmlElement(ElementName = "BaseVehicleSearchResponse", Namespace = "http://whisolutions.com/pss/common/model/parts", Type = typeof(BaseVehicleSearchResponse))]
|
||||||
[XmlElement(ElementName = "EngineSearch", Namespace = "http://whisolutions.com/PartSelectService-v1", Type = typeof(EngineSearch))]
|
[XmlElement(ElementName = "EngineSearch", Namespace = "http://whisolutions.com/pss/common/model/parts", Type = typeof(EngineSearch))]
|
||||||
[XmlElement(ElementName = "EngineSearchResponse", Namespace = "http://whisolutions.com/PartSelectService-v1", Type = typeof(EngineSearchResponse))]
|
[XmlElement(ElementName = "EngineSearchResponse", Namespace = "http://whisolutions.com/pss/common/model/parts", Type = typeof(EngineSearchResponse))]
|
||||||
[XmlElement(ElementName = "MakeSearch", Namespace = "http://whisolutions.com/PartSelectService-v1", Type = typeof(MakeSearch))]
|
[XmlElement(ElementName = "MakeSearch", Namespace = "http://whisolutions.com/pss/common/model/parts", Type = typeof(MakeSearch))]
|
||||||
[XmlElement(ElementName = "MakeSearchResponse", Namespace = "http://whisolutions.com/PartSelectService-v1", Type = typeof(MakeSearchResponse))]
|
[XmlElement(ElementName = "MakeSearchResponse", Namespace = "http://whisolutions.com/pss/common/model/parts", Type = typeof(MakeSearchResponse))]
|
||||||
[XmlElement(ElementName = "ModelSearch", Namespace = "http://whisolutions.com/PartSelectService-v1", Type = typeof(ModelSearch))]
|
[XmlElement(ElementName = "ModelSearch", Namespace = "http://whisolutions.com/pss/common/model/parts", Type = typeof(ModelSearch))]
|
||||||
[XmlElement(ElementName = "ModelSearchResponse", Namespace = "http://whisolutions.com/PartSelectService-v1", Type = typeof(ModelSearchResponse))]
|
[XmlElement(ElementName = "ModelSearchResponse", Namespace = "http://whisolutions.com/pss/common/model/parts", Type = typeof(ModelSearchResponse))]
|
||||||
[XmlElement(ElementName = "MenuNodesLookup", Namespace = "http://whisolutions.com/PartSelectService-v1", Type = typeof(MenuNodesLookup))]
|
[XmlElement(ElementName = "MenuNodesLookup", Namespace = "http://whisolutions.com/pss/common/model/parts", Type = typeof(MenuNodesLookup))]
|
||||||
[XmlElement(ElementName = "MenuNodesLookupResponse", Namespace = "http://whisolutions.com/PartSelectService-v1", Type = typeof(MenuNodesLookupResponse))]
|
[XmlElement(ElementName = "MenuNodesLookupResponse", Namespace = "http://whisolutions.com/pss/common/model/parts", Type = typeof(MenuNodesLookupResponse))]
|
||||||
[XmlElement(ElementName = "PartTypeSearch", Namespace = "http://whisolutions.com/PartSelectService-v1", Type = typeof(PartTypeSearch))]
|
[XmlElement(ElementName = "PartTypeSearch", Namespace = "http://whisolutions.com/pss/common/model/parts", Type = typeof(PartTypeSearch))]
|
||||||
[XmlElement(ElementName = "PartTypeSearchResponse", Namespace = "http://whisolutions.com/PartSelectService-v1", Type = typeof(PartTypeSearchResponse))]
|
[XmlElement(ElementName = "PartTypeSearchResponse", Namespace = "http://whisolutions.com/pss/common/model/parts", Type = typeof(PartTypeSearchResponse))]
|
||||||
[XmlElement(ElementName = "PartTypesValidateLookup", Namespace = "http://whisolutions.com/PartSelectService-v1", Type = typeof(PartTypesValidateLookup))]
|
[XmlElement(ElementName = "PartTypesValidateLookup", Namespace = "http://whisolutions.com/pss/common/model/parts", Type = typeof(PartTypesValidateLookup))]
|
||||||
[XmlElement(ElementName = "PartTypesValidateLookupResponse", Namespace = "http://whisolutions.com/PartSelectService-v1", Type = typeof(PartTypesValidateLookupResponse))]
|
[XmlElement(ElementName = "PartTypesValidateLookupResponse", Namespace = "http://whisolutions.com/pss/common/model/parts", Type = typeof(PartTypesValidateLookupResponse))]
|
||||||
[XmlElement(ElementName = "SmartPageDataSearch", Namespace = "http://whisolutions.com/PartSelectService-v1", Type = typeof(SmartPageDataSearch))]
|
[XmlElement(ElementName = "SmartPageDataSearch", Namespace = "http://whisolutions.com/pss/common/model/parts", Type = typeof(SmartPageDataSearch))]
|
||||||
[XmlElement(ElementName = "SmartPageDataSearchResponse", Namespace = "http://whisolutions.com/PartSelectService-v1", Type = typeof(SmartPageDataSearchResponse))]
|
[XmlElement(ElementName = "SmartPageDataSearchResponse", Namespace = "http://whisolutions.com/pss/common/model/parts", Type = typeof(SmartPageDataSearchResponse))]
|
||||||
[XmlElement(ElementName = "SubModelSearch", Namespace = "http://whisolutions.com/PartSelectService-v1", Type = typeof(SubModelSearch))]
|
[XmlElement(ElementName = "SubModelSearch", Namespace = "http://whisolutions.com/pss/common/model/parts", Type = typeof(SubModelSearch))]
|
||||||
[XmlElement(ElementName = "SubModelSearchResponse", Namespace = "http://whisolutions.com/PartSelectService-v1", Type = typeof(SubModelSearchResponse))]
|
[XmlElement(ElementName = "SubModelSearchResponse", Namespace = "http://whisolutions.com/pss/common/model/parts", Type = typeof(SubModelSearchResponse))]
|
||||||
[XmlElement(ElementName = "VehicleIdSearch", Namespace = "http://whisolutions.com/PartSelectService-v1", Type = typeof(VehicleIdSearch))]
|
[XmlElement(ElementName = "VehicleIdSearch", Namespace = "http://whisolutions.com/pss/common/model/parts", Type = typeof(VehicleIdSearch))]
|
||||||
[XmlElement(ElementName = "VehicleIdSearchResponse", Namespace = "http://whisolutions.com/PartSelectService-v1", Type = typeof(VehicleIdSearchResponse))]
|
[XmlElement(ElementName = "VehicleIdSearchResponse", Namespace = "http://whisolutions.com/pss/common/model/parts", Type = typeof(VehicleIdSearchResponse))]
|
||||||
[XmlElement(ElementName = "VehicleTypesGet", Namespace = "http://whisolutions.com/PartSelectService-v1", Type = typeof(VehicleTypesGet))]
|
[XmlElement(ElementName = "VehicleTypesGet", Namespace = "http://whisolutions.com/pss/common/model/parts", Type = typeof(VehicleTypesGet))]
|
||||||
[XmlElement(ElementName = "VehicleTypesGetResponse", Namespace = "http://whisolutions.com/PartSelectService-v1", Type = typeof(VehicleTypesGetResponse))]
|
[XmlElement(ElementName = "VehicleTypesGetResponse", Namespace = "http://whisolutions.com/pss/common/model/parts", Type = typeof(VehicleTypesGetResponse))]
|
||||||
[XmlElement(ElementName = "WHIEngineSearch", Namespace = "http://whisolutions.com/PartSelectService-v1", Type = typeof(WHIEngineSearch))]
|
[XmlElement(ElementName = "WHIEngineSearch", Namespace = "http://whisolutions.com/pss/common/model/parts", Type = typeof(WHIEngineSearch))]
|
||||||
[XmlElement(ElementName = "WHIEngineSearchResponse", Namespace = "http://whisolutions.com/PartSelectService-v1", Type = typeof(WHIEngineSearchResponse))]
|
[XmlElement(ElementName = "WHIEngineSearchResponse", Namespace = "http://whisolutions.com/pss/common/model/parts", Type = typeof(WHIEngineSearchResponse))]
|
||||||
public object Content { get; set; }
|
public object Content { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ using System.Xml.Serialization;
|
|||||||
|
|
||||||
namespace PartSource.Data.Nexpart
|
namespace PartSource.Data.Nexpart
|
||||||
{
|
{
|
||||||
[XmlType(AnonymousType = true, Namespace = "http://whisolutions.com/PartSelectService-v1")]
|
[XmlType(AnonymousType = true, Namespace = "http://whisolutions.com/pss/common/model/parts")]
|
||||||
public class Criterion
|
public class Criterion
|
||||||
{
|
{
|
||||||
[XmlAttribute]
|
[XmlAttribute]
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ using System.Xml.Serialization;
|
|||||||
|
|
||||||
namespace PartSource.Data.Nexpart
|
namespace PartSource.Data.Nexpart
|
||||||
{
|
{
|
||||||
[XmlType(AnonymousType = true, Namespace = "http://whisolutions.com/PartSelectServ/2011-07-21")]
|
[XmlType(AnonymousType = true, Namespace = "http://whisolutions.com/pss/common/helper/parts")]
|
||||||
public class Engine
|
public class Engine
|
||||||
{
|
{
|
||||||
[XmlAttribute]
|
[XmlAttribute]
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ using System.Xml.Serialization;
|
|||||||
|
|
||||||
namespace PartSource.Data.Nexpart
|
namespace PartSource.Data.Nexpart
|
||||||
{
|
{
|
||||||
[XmlType(AnonymousType = true, Namespace = "http://whisolutions.com/PartSelectService-v1")]
|
[XmlType(AnonymousType = true, Namespace = "http://whisolutions.com/pss/common/model/parts")]
|
||||||
public class EngineSearch
|
public class EngineSearch
|
||||||
{
|
{
|
||||||
public EngineSearch()
|
public EngineSearch()
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ using System.Xml.Serialization;
|
|||||||
|
|
||||||
namespace PartSource.Data.Nexpart
|
namespace PartSource.Data.Nexpart
|
||||||
{
|
{
|
||||||
[XmlType(AnonymousType = true, Namespace = "http://whisolutions.com/PartSelectService-v1")]
|
[XmlType(AnonymousType = true, Namespace = "http://whisolutions.com/pss/common/model/parts")]
|
||||||
public class EngineSearchResponse : IResponseElement<Engines>
|
public class EngineSearchResponse : IResponseElement<Engines>
|
||||||
{
|
{
|
||||||
[XmlElement]
|
[XmlElement]
|
||||||
|
|||||||
@@ -8,10 +8,10 @@ using System.Xml.Serialization;
|
|||||||
|
|
||||||
namespace PartSource.Data.Nexpart
|
namespace PartSource.Data.Nexpart
|
||||||
{
|
{
|
||||||
[XmlType(AnonymousType = true, Namespace = "http://whisolutions.com/PartSelectService-v1")]
|
[XmlType(AnonymousType = true, Namespace = "http://whisolutions.com/pss/common/model/parts")]
|
||||||
public class Engines
|
public class Engines
|
||||||
{
|
{
|
||||||
[XmlElement(Namespace = "http://whisolutions.com/PartSelectServ/2011-07-21")]
|
[XmlElement(Namespace = "http://whisolutions.com/pss/common/helper/parts")]
|
||||||
public Engine[] Engine;
|
public Engine[] Engine;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ using System.Xml.Serialization;
|
|||||||
|
|
||||||
namespace PartSource.Data.Nexpart
|
namespace PartSource.Data.Nexpart
|
||||||
{
|
{
|
||||||
[XmlType(AnonymousType = true, Namespace = "http://whisolutions.com/PartSelectCommon/2011-07-21")]
|
[XmlType(AnonymousType = true, Namespace = "http://whisolutions.com/pss/common/header/parts")]
|
||||||
public class Exceptions
|
public class Exceptions
|
||||||
{
|
{
|
||||||
[XmlAttribute(AttributeName = "code")]
|
[XmlAttribute(AttributeName = "code")]
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ using System.Xml.Serialization;
|
|||||||
|
|
||||||
namespace PartSource.Data.Nexpart
|
namespace PartSource.Data.Nexpart
|
||||||
{
|
{
|
||||||
[XmlType(AnonymousType = true, Namespace = "http://whisolutions.com/PartSelectServ/2011-07-21")]
|
[XmlType(AnonymousType = true, Namespace = "http://whisolutions.com/pss/common/helper/parts")]
|
||||||
public class Item
|
public class Item
|
||||||
{
|
{
|
||||||
[XmlAttribute]
|
[XmlAttribute]
|
||||||
|
|||||||
@@ -8,10 +8,10 @@ using System.Xml.Serialization;
|
|||||||
|
|
||||||
namespace PartSource.Data.Nexpart
|
namespace PartSource.Data.Nexpart
|
||||||
{
|
{
|
||||||
[XmlType(AnonymousType = true, Namespace = "http://whisolutions.com/PartSelectService-v1")]
|
[XmlType(AnonymousType = true, Namespace = "http://whisolutions.com/pss/common/model/parts")]
|
||||||
public class Items
|
public class Items
|
||||||
{
|
{
|
||||||
[XmlElement(ElementName = "Item", Namespace = "http://whisolutions.com/PartSelectServ/2011-07-21", Order = 1)]
|
[XmlElement(ElementName = "Item", Namespace = "http://whisolutions.com/pss/common/helper/parts", Order = 1)]
|
||||||
public PartSource.Data.Nexpart.Item[] Item { get; set; }
|
public PartSource.Data.Nexpart.Item[] Item { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ using System.Xml.Serialization;
|
|||||||
|
|
||||||
namespace PartSource.Data.Nexpart
|
namespace PartSource.Data.Nexpart
|
||||||
{
|
{
|
||||||
[XmlType(AnonymousType = true, Namespace = "http://whisolutions.com/PartSelectServ/2011-07-21")]
|
[XmlType(AnonymousType = true, Namespace = "http://whisolutions.com/pss/common/helper/parts")]
|
||||||
public class Make
|
public class Make
|
||||||
{
|
{
|
||||||
[XmlText]
|
[XmlText]
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ using System.Xml.Serialization;
|
|||||||
|
|
||||||
namespace PartSource.Data.Nexpart
|
namespace PartSource.Data.Nexpart
|
||||||
{
|
{
|
||||||
[XmlType(AnonymousType = true, Namespace = "http://whisolutions.com/PartSelectService-v1")]
|
[XmlType(AnonymousType = true, Namespace = "http://whisolutions.com/pss/common/model/parts")]
|
||||||
public class MakeSearch
|
public class MakeSearch
|
||||||
{
|
{
|
||||||
public MakeSearch()
|
public MakeSearch()
|
||||||
@@ -18,16 +18,16 @@ namespace PartSource.Data.Nexpart
|
|||||||
this.RegionId = new int[]{ 2 };
|
this.RegionId = new int[]{ 2 };
|
||||||
}
|
}
|
||||||
|
|
||||||
[XmlElement(ElementName = "PSRequestHeader", Namespace = "http://whisolutions.com/PartSelectService-v1", Order = 1)]
|
[XmlElement(ElementName = "PSRequestHeader", Namespace = "http://whisolutions.com/pss/common/model/parts", Order = 1)]
|
||||||
public PSRequestHeader PSRequestHeader { get; set; }
|
public PSRequestHeader PSRequestHeader { get; set; }
|
||||||
|
|
||||||
[XmlElement(ElementName = "Years", Namespace = "http://whisolutions.com/PartSelectService-v1", Order = 2)]
|
[XmlElement(ElementName = "Years", Namespace = "http://whisolutions.com/pss/common/model/parts", Order = 2)]
|
||||||
public Years Years { get; set; }
|
public Years Years { get; set; }
|
||||||
|
|
||||||
[XmlElement(ElementName = "RegionId", Namespace = "http://whisolutions.com/PartSelectService-v1", Order = 3)]
|
[XmlElement(ElementName = "RegionId", Namespace = "http://whisolutions.com/pss/common/model/parts", Order = 3)]
|
||||||
public int[] RegionId { get; set; }
|
public int[] RegionId { get; set; }
|
||||||
|
|
||||||
[XmlElement(ElementName = "VehicleTypeId", Namespace = "http://whisolutions.com/PartSelectService-v1", Order = 4)]
|
[XmlElement(ElementName = "VehicleTypeId", Namespace = "http://whisolutions.com/pss/common/model/parts", Order = 4)]
|
||||||
public int[] VehicleTypeId { get; set; }
|
public int[] VehicleTypeId { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ using System.Xml.Serialization;
|
|||||||
|
|
||||||
namespace PartSource.Data.Nexpart
|
namespace PartSource.Data.Nexpart
|
||||||
{
|
{
|
||||||
[XmlType(AnonymousType = true, Namespace = "http://whisolutions.com/PartSelectService-v1")]
|
[XmlType(AnonymousType = true, Namespace = "http://whisolutions.com/pss/common/model/parts")]
|
||||||
public class MakeSearchResponse : IResponseElement<Makes>
|
public class MakeSearchResponse : IResponseElement<Makes>
|
||||||
{
|
{
|
||||||
[XmlElement]
|
[XmlElement]
|
||||||
|
|||||||
@@ -8,10 +8,10 @@ using System.Xml.Serialization;
|
|||||||
|
|
||||||
namespace PartSource.Data.Nexpart
|
namespace PartSource.Data.Nexpart
|
||||||
{
|
{
|
||||||
[XmlType(AnonymousType = true, Namespace = "http://whisolutions.com/PartSelectService-v1")]
|
[XmlType(AnonymousType = true, Namespace = "http://whisolutions.com/pss/common/model/parts")]
|
||||||
public class Makes
|
public class Makes
|
||||||
{
|
{
|
||||||
[XmlElement(ElementName = "Make", Namespace = "http://whisolutions.com/PartSelectServ/2011-07-21", Order = 1)]
|
[XmlElement(ElementName = "Make", Namespace = "http://whisolutions.com/pss/common/helper/parts", Order = 1)]
|
||||||
public PartSource.Data.Nexpart.Make[] Make { get; set; }
|
public PartSource.Data.Nexpart.Make[] Make { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ using System.Xml.Serialization;
|
|||||||
|
|
||||||
namespace PartSource.Data.Nexpart
|
namespace PartSource.Data.Nexpart
|
||||||
{
|
{
|
||||||
[XmlType(AnonymousType = true, Namespace = "http://whisolutions.com/PartSelectService-v1")]
|
[XmlType(AnonymousType = true, Namespace = "http://whisolutions.com/pss/common/model/parts")]
|
||||||
public class MenuNode
|
public class MenuNode
|
||||||
{
|
{
|
||||||
[XmlAttribute]
|
[XmlAttribute]
|
||||||
|
|||||||
@@ -8,10 +8,10 @@ using System.Xml.Serialization;
|
|||||||
|
|
||||||
namespace PartSource.Data.Nexpart
|
namespace PartSource.Data.Nexpart
|
||||||
{
|
{
|
||||||
[XmlType(AnonymousType = true, Namespace = "http://whisolutions.com/PartSelectService-v1")]
|
[XmlType(AnonymousType = true, Namespace = "http://whisolutions.com/pss/common/model/parts")]
|
||||||
public class MenuNodes
|
public class MenuNodes
|
||||||
{
|
{
|
||||||
[XmlElement(Namespace = "http://whisolutions.com/PartSelectServ/2011-07-21")]
|
[XmlElement(Namespace = "http://whisolutions.com/pss/common/helper/parts")]
|
||||||
public MenuNode[] MenuNode{ get; set; }
|
public MenuNode[] MenuNode{ get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ using System.Xml.Serialization;
|
|||||||
|
|
||||||
namespace PartSource.Data.Nexpart
|
namespace PartSource.Data.Nexpart
|
||||||
{
|
{
|
||||||
[XmlType(AnonymousType = true, Namespace = "http://whisolutions.com/PartSelectService-v1")]
|
[XmlType(AnonymousType = true, Namespace = "http://whisolutions.com/pss/common/model/parts")]
|
||||||
public class MenuNodesLookup
|
public class MenuNodesLookup
|
||||||
{
|
{
|
||||||
public MenuNodesLookup()
|
public MenuNodesLookup()
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ using System.Xml.Serialization;
|
|||||||
|
|
||||||
namespace PartSource.Data.Nexpart
|
namespace PartSource.Data.Nexpart
|
||||||
{
|
{
|
||||||
[XmlType(AnonymousType = true, Namespace = "http://whisolutions.com/PartSelectService-v1")]
|
[XmlType(AnonymousType = true, Namespace = "http://whisolutions.com/pss/common/model/parts")]
|
||||||
public class MenuNodesLookupResponse : IResponseElement<MenuNodes>
|
public class MenuNodesLookupResponse : IResponseElement<MenuNodes>
|
||||||
{
|
{
|
||||||
[XmlElement]
|
[XmlElement]
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ using System.Xml.Serialization;
|
|||||||
|
|
||||||
namespace PartSource.Data.Nexpart
|
namespace PartSource.Data.Nexpart
|
||||||
{
|
{
|
||||||
[XmlType(AnonymousType = true, Namespace = "http://whisolutions.com/PartSelectServ/2011-07-21")]
|
[XmlType(AnonymousType = true, Namespace = "http://whisolutions.com/pss/common/helper/parts")]
|
||||||
public class Model
|
public class Model
|
||||||
{
|
{
|
||||||
[XmlText]
|
[XmlText]
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ using System.Xml.Serialization;
|
|||||||
|
|
||||||
namespace PartSource.Data.Nexpart
|
namespace PartSource.Data.Nexpart
|
||||||
{
|
{
|
||||||
[XmlType(AnonymousType = true, Namespace = "http://whisolutions.com/PartSelectService-v1")]
|
[XmlType(AnonymousType = true, Namespace = "http://whisolutions.com/pss/common/model/parts")]
|
||||||
public class ModelSearch
|
public class ModelSearch
|
||||||
{
|
{
|
||||||
public ModelSearch()
|
public ModelSearch()
|
||||||
@@ -17,19 +17,19 @@ namespace PartSource.Data.Nexpart
|
|||||||
this.RegionId = new int[] { 2 };
|
this.RegionId = new int[] { 2 };
|
||||||
}
|
}
|
||||||
|
|
||||||
[XmlElement(ElementName = "PSRequestHeader", Namespace = "http://whisolutions.com/PartSelectService-v1", Order = 1)]
|
[XmlElement(ElementName = "PSRequestHeader", Namespace = "http://whisolutions.com/pss/common/model/parts", Order = 1)]
|
||||||
public PSRequestHeader PSRequestHeader { get; set; }
|
public PSRequestHeader PSRequestHeader { get; set; }
|
||||||
|
|
||||||
[XmlElement(ElementName = "Year", Namespace = "http://whisolutions.com/PartSelectService-v1", Order = 2)]
|
[XmlElement(ElementName = "Year", Namespace = "http://whisolutions.com/pss/common/model/parts", Order = 2)]
|
||||||
public int Year { get; set; }
|
public int Year { get; set; }
|
||||||
|
|
||||||
[XmlElement(ElementName = "MakeId", Namespace = "http://whisolutions.com/PartSelectService-v1", Order = 3)]
|
[XmlElement(ElementName = "MakeId", Namespace = "http://whisolutions.com/pss/common/model/parts", Order = 3)]
|
||||||
public int MakeId { get; set; }
|
public int MakeId { get; set; }
|
||||||
|
|
||||||
[XmlElement(ElementName = "RegionId", Namespace = "http://whisolutions.com/PartSelectService-v1", Order = 4)]
|
[XmlElement(ElementName = "RegionId", Namespace = "http://whisolutions.com/pss/common/model/parts", Order = 4)]
|
||||||
public int[] RegionId { get; set; }
|
public int[] RegionId { get; set; }
|
||||||
|
|
||||||
[XmlElement(ElementName = "VehicleTypeId", Namespace = "http://whisolutions.com/PartSelectService-v1", Order = 5)]
|
[XmlElement(ElementName = "VehicleTypeId", Namespace = "http://whisolutions.com/pss/common/model/parts", Order = 5)]
|
||||||
public int[] VehicleTypeId { get; set; }
|
public int[] VehicleTypeId { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,13 +9,13 @@ using System.Xml.Serialization;
|
|||||||
|
|
||||||
namespace PartSource.Data.Nexpart
|
namespace PartSource.Data.Nexpart
|
||||||
{
|
{
|
||||||
[XmlType(AnonymousType = true, Namespace = "http://whisolutions.com/PartSelectService-v1")]
|
[XmlType(AnonymousType = true, Namespace = "http://whisolutions.com/pss/common/model/parts")]
|
||||||
public class ModelSearchResponse : IResponseElement<Models[]>
|
public class ModelSearchResponse : IResponseElement<Models[]>
|
||||||
{
|
{
|
||||||
[XmlElement]
|
[XmlElement]
|
||||||
public PSResponseHeader PSResponseHeader { get; set; }
|
public PSResponseHeader PSResponseHeader { get; set; }
|
||||||
|
|
||||||
[XmlElement(ElementName = "Models", Namespace = "http://whisolutions.com/PartSelectService-v1")]
|
[XmlElement(ElementName = "Models", Namespace = "http://whisolutions.com/pss/common/model/parts")]
|
||||||
public Models[] ResponseBody { get; set; }
|
public Models[] ResponseBody { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ using System.Xml.Serialization;
|
|||||||
|
|
||||||
namespace PartSource.Data.Nexpart
|
namespace PartSource.Data.Nexpart
|
||||||
{
|
{
|
||||||
[XmlType(AnonymousType = true, Namespace = "http://whisolutions.com/PartSelectService-v1")]
|
[XmlType(AnonymousType = true, Namespace = "http://whisolutions.com/pss/common/model/parts")]
|
||||||
public class Models
|
public class Models
|
||||||
{
|
{
|
||||||
public Models()
|
public Models()
|
||||||
@@ -19,7 +19,7 @@ namespace PartSource.Data.Nexpart
|
|||||||
[XmlAttribute]
|
[XmlAttribute]
|
||||||
public int Region { get; set; }
|
public int Region { get; set; }
|
||||||
|
|
||||||
[XmlElement(ElementName = "Model", Namespace = "http://whisolutions.com/PartSelectServ/2011-07-21")]
|
[XmlElement(ElementName = "Model", Namespace = "http://whisolutions.com/pss/common/helper/parts")]
|
||||||
public PartSource.Data.Nexpart.Model[] Model { get; set; }
|
public PartSource.Data.Nexpart.Model[] Model { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,19 +8,19 @@ using System.Xml.Serialization;
|
|||||||
|
|
||||||
namespace PartSource.Data.Nexpart
|
namespace PartSource.Data.Nexpart
|
||||||
{
|
{
|
||||||
[XmlType(AnonymousType = true, Namespace = "http://whisolutions.com/PartSelectService-v1")]
|
[XmlType(AnonymousType = true, Namespace = "http://whisolutions.com/pss/common/model/parts")]
|
||||||
public class PSRequestHeader
|
public class PSRequestHeader
|
||||||
{
|
{
|
||||||
public PSRequestHeader()
|
public PSRequestHeader()
|
||||||
{
|
{
|
||||||
this.SvcVersion = "1.0";
|
this.SvcVersion = "2.0";
|
||||||
this.ReturnWarnings = "true";
|
this.ReturnWarnings = "true";
|
||||||
}
|
}
|
||||||
|
|
||||||
[XmlElement(ElementName = "SvcVersion", Namespace = "http://whisolutions.com/PartSelectCommon/2011-07-21")]
|
[XmlElement(ElementName = "SvcVersion", Namespace = "http://whisolutions.com/pss/common/header/parts")]
|
||||||
public string SvcVersion { get; set; }
|
public string SvcVersion { get; set; }
|
||||||
|
|
||||||
[XmlElement(ElementName = "ReturnWarnings", Namespace = "http://whisolutions.com/PartSelectCommon/2011-07-21")]
|
[XmlElement(ElementName = "ReturnWarnings", Namespace = "http://whisolutions.com/pss/common/header/parts")]
|
||||||
public string ReturnWarnings { get; set; }
|
public string ReturnWarnings { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,25 +8,25 @@ using System.Xml.Serialization;
|
|||||||
|
|
||||||
namespace PartSource.Data.Nexpart
|
namespace PartSource.Data.Nexpart
|
||||||
{
|
{
|
||||||
[XmlType(AnonymousType = true, Namespace = "http://whisolutions.com/PartSelectService-v1")]
|
[XmlType(AnonymousType = true, Namespace = "http://whisolutions.com/pss/common/model/parts")]
|
||||||
public class PSResponseHeader
|
public class PSResponseHeader
|
||||||
{
|
{
|
||||||
[XmlElement(ElementName = "RequestId", Namespace = "http://whisolutions.com/PartSelectCommon/2011-07-21")]
|
[XmlElement(ElementName = "RequestId", Namespace = "http://whisolutions.com/pss/common/header/parts")]
|
||||||
public string RequestId { get; set; }
|
public string RequestId { get; set; }
|
||||||
|
|
||||||
[XmlElement(ElementName = "RequestProcessingTime", Namespace = "http://whisolutions.com/PartSelectCommon/2011-07-21")]
|
[XmlElement(ElementName = "RequestProcessingTime", Namespace = "http://whisolutions.com/pss/common/header/parts")]
|
||||||
public string RequestProcessingTime { get; set; }
|
public string RequestProcessingTime { get; set; }
|
||||||
|
|
||||||
[XmlElement(ElementName = "Build", Namespace = "http://whisolutions.com/PartSelectCommon/2011-07-21")]
|
[XmlElement(ElementName = "Build", Namespace = "http://whisolutions.com/pss/common/header/parts")]
|
||||||
public string Build { get; set; }
|
public string Build { get; set; }
|
||||||
|
|
||||||
[XmlElement(ElementName = "TimeStamp", Namespace = "http://whisolutions.com/PartSelectCommon/2011-07-21")]
|
[XmlElement(ElementName = "TimeStamp", Namespace = "http://whisolutions.com/pss/common/header/parts")]
|
||||||
public string TimeStamp { get; set; }
|
public string TimeStamp { get; set; }
|
||||||
|
|
||||||
[XmlElement(ElementName = "StatusCode", Namespace = "http://whisolutions.com/PartSelectCommon/2011-07-21")]
|
[XmlElement(ElementName = "StatusCode", Namespace = "http://whisolutions.com/pss/common/header/parts")]
|
||||||
public string StatusCode { get; set; }
|
public string StatusCode { get; set; }
|
||||||
|
|
||||||
[XmlElement(ElementName = "Exceptions", Namespace = "http://whisolutions.com/PartSelectCommon/2011-07-21")]
|
[XmlElement(ElementName = "Exceptions", Namespace = "http://whisolutions.com/pss/common/header/parts")]
|
||||||
public PartSource.Data.Nexpart.Exceptions[] Exceptions { get; set; }
|
public PartSource.Data.Nexpart.Exceptions[] Exceptions { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ using System.Xml.Serialization;
|
|||||||
|
|
||||||
namespace PartSource.Data.Nexpart
|
namespace PartSource.Data.Nexpart
|
||||||
{
|
{
|
||||||
[XmlType(AnonymousType = true, Namespace = "http://whisolutions.com/PartSelectServ/2011-07-21")]
|
[XmlType(AnonymousType = true, Namespace = "http://whisolutions.com/pss/common/helper/parts")]
|
||||||
public class Part
|
public class Part
|
||||||
{
|
{
|
||||||
[XmlElement]
|
[XmlElement]
|
||||||
@@ -15,7 +15,7 @@ namespace PartSource.Data.Nexpart
|
|||||||
public PartPartType PartType { get; set; }
|
public PartPartType PartType { get; set; }
|
||||||
|
|
||||||
// There are two different kinds of PartType because of course there are...
|
// There are two different kinds of PartType because of course there are...
|
||||||
[XmlType(AnonymousType = true, Namespace = "http://whisolutions.com/PartSelectServ/2011-07-21")]
|
[XmlType(AnonymousType = true, Namespace = "http://whisolutions.com/pss/common/helper/parts")]
|
||||||
public class PartPartType
|
public class PartPartType
|
||||||
{
|
{
|
||||||
[XmlAttribute]
|
[XmlAttribute]
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ using System.Xml.Serialization;
|
|||||||
|
|
||||||
namespace PartSource.Data.Nexpart
|
namespace PartSource.Data.Nexpart
|
||||||
{
|
{
|
||||||
[XmlType(AnonymousType = true, Namespace = "http://whisolutions.com/PartSelectServ/2011-07-21")]
|
[XmlType(AnonymousType = true, Namespace = "http://whisolutions.com/pss/common/helper/parts")]
|
||||||
public class PartNumber
|
public class PartNumber
|
||||||
{
|
{
|
||||||
[XmlText]
|
[XmlText]
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ using System.Xml.Serialization;
|
|||||||
|
|
||||||
namespace PartSource.Data.Nexpart
|
namespace PartSource.Data.Nexpart
|
||||||
{
|
{
|
||||||
[XmlType(AnonymousType = true, Namespace = "http://whisolutions.com/PartSelectService-v1")]
|
[XmlType(AnonymousType = true, Namespace = "http://whisolutions.com/pss/common/model/parts")]
|
||||||
public class PartType
|
public class PartType
|
||||||
{
|
{
|
||||||
[XmlAttribute]
|
[XmlAttribute]
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ using System.Xml.Serialization;
|
|||||||
|
|
||||||
namespace PartSource.Data.Nexpart
|
namespace PartSource.Data.Nexpart
|
||||||
{
|
{
|
||||||
[XmlType(AnonymousType = true, Namespace = "http://whisolutions.com/PartSelectService-v1")]
|
[XmlType(AnonymousType = true, Namespace = "http://whisolutions.com/pss/common/model/parts")]
|
||||||
public class PartTypeSearch
|
public class PartTypeSearch
|
||||||
{
|
{
|
||||||
public PartTypeSearch()
|
public PartTypeSearch()
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ using System.Xml.Serialization;
|
|||||||
|
|
||||||
namespace PartSource.Data.Nexpart
|
namespace PartSource.Data.Nexpart
|
||||||
{
|
{
|
||||||
[XmlType(AnonymousType = true, Namespace = "http://whisolutions.com/PartSelectService-v1")]
|
[XmlType(AnonymousType = true, Namespace = "http://whisolutions.com/pss/common/model/parts")]
|
||||||
public class PartTypeSearchResponse : IResponseElement<PartTypes>
|
public class PartTypeSearchResponse : IResponseElement<PartTypes>
|
||||||
{
|
{
|
||||||
[XmlElement]
|
[XmlElement]
|
||||||
|
|||||||
@@ -8,10 +8,10 @@ using System.Xml.Serialization;
|
|||||||
|
|
||||||
namespace PartSource.Data.Nexpart
|
namespace PartSource.Data.Nexpart
|
||||||
{
|
{
|
||||||
[XmlType(AnonymousType = true, Namespace = "http://whisolutions.com/PartSelectService-v1")]
|
[XmlType(AnonymousType = true, Namespace = "http://whisolutions.com/pss/common/model/parts")]
|
||||||
public class PartTypes
|
public class PartTypes
|
||||||
{
|
{
|
||||||
[XmlElement(Namespace = "http://whisolutions.com/PartSelectServ/2011-07-21")]
|
[XmlElement(Namespace = "http://whisolutions.com/pss/common/helper/parts")]
|
||||||
public PartSource.Data.Nexpart.PartType[] PartType { get; set; }
|
public PartSource.Data.Nexpart.PartType[] PartType { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ using System.Xml.Serialization;
|
|||||||
|
|
||||||
namespace PartSource.Data.Nexpart
|
namespace PartSource.Data.Nexpart
|
||||||
{
|
{
|
||||||
[XmlType(AnonymousType = true, Namespace = "http://whisolutions.com/PartSelectService-v1")]
|
[XmlType(AnonymousType = true, Namespace = "http://whisolutions.com/pss/common/model/parts")]
|
||||||
public class PartTypesValidateLookup
|
public class PartTypesValidateLookup
|
||||||
{
|
{
|
||||||
public PartTypesValidateLookup()
|
public PartTypesValidateLookup()
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ using System.Xml.Serialization;
|
|||||||
|
|
||||||
namespace PartSource.Data.Nexpart
|
namespace PartSource.Data.Nexpart
|
||||||
{
|
{
|
||||||
[XmlType(AnonymousType = true, Namespace = "http://whisolutions.com/PartSelectService-v1")]
|
[XmlType(AnonymousType = true, Namespace = "http://whisolutions.com/pss/common/model/parts")]
|
||||||
public class PartTypesValidateLookupResponse : IResponseElement<PartTypes>
|
public class PartTypesValidateLookupResponse : IResponseElement<PartTypes>
|
||||||
{
|
{
|
||||||
[XmlElement]
|
[XmlElement]
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ using System.Xml.Serialization;
|
|||||||
|
|
||||||
namespace PartSource.Data.Nexpart
|
namespace PartSource.Data.Nexpart
|
||||||
{
|
{
|
||||||
[XmlType(AnonymousType = true, Namespace = "http://whisolutions.com/PartSelectServ/2011-07-21")]
|
[XmlType(AnonymousType = true, Namespace = "http://whisolutions.com/pss/common/helper/parts")]
|
||||||
public class PrimaryImg
|
public class PrimaryImg
|
||||||
{
|
{
|
||||||
[XmlElement]
|
[XmlElement]
|
||||||
|
|||||||
25
PartSource.Data/Nexpart/Question.cs
Normal file
25
PartSource.Data/Nexpart/Question.cs
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Xml.Serialization;
|
||||||
|
|
||||||
|
namespace PartSource.Data.Nexpart
|
||||||
|
{
|
||||||
|
[XmlType(Namespace = "http://whisolutions.com/pss/common/helper/parts")]
|
||||||
|
public class Question
|
||||||
|
{
|
||||||
|
[XmlAttribute(AttributeName = "Attrib")]
|
||||||
|
public string Attribute { get; set; }
|
||||||
|
|
||||||
|
[XmlAttribute]
|
||||||
|
public int Count { get; set; }
|
||||||
|
|
||||||
|
[XmlAttribute]
|
||||||
|
public string Text { get; set; }
|
||||||
|
|
||||||
|
[XmlElement]
|
||||||
|
public Answer[] Answer { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
19
PartSource.Data/Nexpart/Questions.cs
Normal file
19
PartSource.Data/Nexpart/Questions.cs
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Xml.Serialization;
|
||||||
|
|
||||||
|
namespace PartSource.Data.Nexpart
|
||||||
|
{
|
||||||
|
[XmlType(Namespace = "http://whisolutions.com/pss/common/model/parts")]
|
||||||
|
public class Questions
|
||||||
|
{
|
||||||
|
[XmlElement(Namespace = "http://whisolutions.com/pss/common/helper/parts")]
|
||||||
|
public Question[] Question { get; set; }
|
||||||
|
|
||||||
|
[XmlAttribute]
|
||||||
|
public int NumApps { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -5,7 +5,7 @@ using System.Xml.Serialization;
|
|||||||
|
|
||||||
namespace PartSource.Data.Nexpart
|
namespace PartSource.Data.Nexpart
|
||||||
{
|
{
|
||||||
[XmlType(AnonymousType = true, Namespace = "http://whisolutions.com/PartSelectService-v1")]
|
[XmlType(AnonymousType = true, Namespace = "http://whisolutions.com/pss/common/model/parts")]
|
||||||
public class Region
|
public class Region
|
||||||
{
|
{
|
||||||
[XmlAttribute]
|
[XmlAttribute]
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ using System.Xml.Serialization;
|
|||||||
|
|
||||||
namespace PartSource.Data.Nexpart
|
namespace PartSource.Data.Nexpart
|
||||||
{
|
{
|
||||||
[XmlType(AnonymousType = true, Namespace = "http://whisolutions.com/PartSelectService-v1")]
|
[XmlType(AnonymousType = true, Namespace = "http://whisolutions.com/pss/common/model/parts")]
|
||||||
public class RegionId
|
public class RegionId
|
||||||
{
|
{
|
||||||
[XmlText]
|
[XmlText]
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ using System.Xml.Serialization;
|
|||||||
|
|
||||||
namespace PartSource.Data.Nexpart
|
namespace PartSource.Data.Nexpart
|
||||||
{
|
{
|
||||||
[XmlType(AnonymousType = true, Namespace = "http://whisolutions.com/PartSelectService-v1")]
|
[XmlType(AnonymousType = true, Namespace = "http://whisolutions.com/pss/common/model/parts")]
|
||||||
public class ResultOption
|
public class ResultOption
|
||||||
{
|
{
|
||||||
[XmlText]
|
[XmlText]
|
||||||
|
|||||||
@@ -1,25 +1,24 @@
|
|||||||
// Decompiled with JetBrains decompiler
|
using System.Xml.Serialization;
|
||||||
// Type: PartSource.Data.Nexpart.SmartPageDataSearch
|
|
||||||
// Assembly: PartSource.Data, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
|
|
||||||
// MVID: 3EDAB3F5-83E7-4F65-906E-B40192014C57
|
|
||||||
// Assembly location: C:\Users\Tommy\Desktop\PS temp\PartSource.Data.dll
|
|
||||||
|
|
||||||
using System.Xml.Serialization;
|
|
||||||
|
|
||||||
namespace PartSource.Data.Nexpart
|
namespace PartSource.Data.Nexpart
|
||||||
{
|
{
|
||||||
[XmlType(AnonymousType = true, Namespace = "http://whisolutions.com/PartSelectService-v1")]
|
[XmlType(AnonymousType = true, Namespace = "http://whisolutions.com/pss/common/model/parts")]
|
||||||
public class SmartPageDataSearch
|
public class SmartPageDataSearch
|
||||||
{
|
|
||||||
public SmartPageDataSearch()
|
|
||||||
{
|
{
|
||||||
this.PSRequestHeader = new PSRequestHeader();
|
public SmartPageDataSearch()
|
||||||
|
{
|
||||||
|
PSRequestHeader = new PSRequestHeader();
|
||||||
|
}
|
||||||
|
|
||||||
|
[XmlElement(ElementName = "PSRequestHeader", Namespace = "http://whisolutions.com/pss/common/model/parts", Order = 1)]
|
||||||
|
public PSRequestHeader PSRequestHeader { get; set; }
|
||||||
|
|
||||||
|
|
||||||
|
[XmlElement(ElementName = "Item", Namespace = "http://whisolutions.com/pss/common/model/parts", Order = 2)]
|
||||||
|
public Item[] Items { get; set; }
|
||||||
|
|
||||||
|
|
||||||
|
[XmlElement(ElementName = "DataOption", Namespace = "http://whisolutions.com/pss/common/model/parts", Order = 3)]
|
||||||
|
public string[] DataOption { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
[XmlElement(ElementName = "PSRequestHeader", Namespace = "http://whisolutions.com/PartSelectService-v1", Order = 1)]
|
|
||||||
public PSRequestHeader PSRequestHeader { get; set; }
|
|
||||||
|
|
||||||
[XmlElement(ElementName = "Item", Namespace = "http://whisolutions.com/PartSelectService-v1", Order = 2)]
|
|
||||||
public Item[] Items { get; set; }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ using System.Xml.Serialization;
|
|||||||
|
|
||||||
namespace PartSource.Data.Nexpart
|
namespace PartSource.Data.Nexpart
|
||||||
{
|
{
|
||||||
[XmlType(AnonymousType = true, Namespace = "http://whisolutions.com/PartSelectService-v1")]
|
[XmlType(AnonymousType = true, Namespace = "http://whisolutions.com/pss/common/model/parts")]
|
||||||
public class SmartPageDataSearchResponse : IResponseElement<Items>
|
public class SmartPageDataSearchResponse : IResponseElement<Items>
|
||||||
{
|
{
|
||||||
[XmlElement]
|
[XmlElement]
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ using System.Xml.Serialization;
|
|||||||
|
|
||||||
namespace PartSource.Data.Nexpart
|
namespace PartSource.Data.Nexpart
|
||||||
{
|
{
|
||||||
[XmlType(AnonymousType = true, Namespace = "http://whisolutions.com/PartSelectServ/2011-07-21")]
|
[XmlType(AnonymousType = true, Namespace = "http://whisolutions.com/pss/common/helper/parts")]
|
||||||
public class SubModel
|
public class SubModel
|
||||||
{
|
{
|
||||||
[XmlAttribute]
|
[XmlAttribute]
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ using System.Xml.Serialization;
|
|||||||
|
|
||||||
namespace PartSource.Data.Nexpart
|
namespace PartSource.Data.Nexpart
|
||||||
{
|
{
|
||||||
[XmlType(AnonymousType = true, Namespace = "http://whisolutions.com/PartSelectService-v1")]
|
[XmlType(AnonymousType = true, Namespace = "http://whisolutions.com/pss/common/model/parts")]
|
||||||
public class SubModelSearchResponse : IResponseElement<SubModels>
|
public class SubModelSearchResponse : IResponseElement<SubModels>
|
||||||
{
|
{
|
||||||
[XmlElement]
|
[XmlElement]
|
||||||
|
|||||||
@@ -5,10 +5,10 @@ using System.Xml.Serialization;
|
|||||||
|
|
||||||
namespace PartSource.Data.Nexpart
|
namespace PartSource.Data.Nexpart
|
||||||
{
|
{
|
||||||
[XmlType(AnonymousType = true, Namespace = "http://whisolutions.com/PartSelectService-v1")]
|
[XmlType(AnonymousType = true, Namespace = "http://whisolutions.com/pss/common/model/parts")]
|
||||||
public class SubModels
|
public class SubModels
|
||||||
{
|
{
|
||||||
[XmlElement(ElementName = "SubModel", Namespace = "http://whisolutions.com/PartSelectServ/2011-07-21", Order = 1)]
|
[XmlElement(ElementName = "SubModel", Namespace = "http://whisolutions.com/pss/common/helper/parts", Order = 1)]
|
||||||
public SubModel[] SubModel { get; set; }
|
public SubModel[] SubModel { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user