From cc2cbd09e1a5e52d672c4b06a9cf90c31da1e2ac Mon Sep 17 00:00:00 2001 From: Tom Raterman Date: Wed, 12 Feb 2025 18:12:19 -0500 Subject: [PATCH] Whatever this is --- PartSource.Api/Controllers/PartsController.cs | 68 +++-- PartSource.Api/appsettings.json | 2 +- PartSource.Automation/Jobs/POC/ImageList.cs | 69 ++--- PartSource.Automation/Jobs/PartsSync.cs | 89 +++++++ .../Jobs/ProcessWhiFitment.cs | 28 ++- PartSource.Automation/Jobs/UpdateFitment.cs | 172 +++---------- .../Models/Configuration/FtpConfiguration.cs | 2 + PartSource.Automation/Program.cs | 13 +- .../Services/VehicleFitmentService.cs | 6 +- .../Services/WhiSeoService.cs | 235 +++++++++--------- PartSource.Automation/appsettings.json | 11 +- PartSource.Data/Contexts/FitmentContext.cs | 4 + PartSource.Data/Contexts/PartSourceContext.cs | 2 +- PartSource.Data/Dtos/VehicleFitmentDto.cs | 5 + PartSource.Data/Models/ProductType.cs | 17 ++ PartSource.Data/Models/VehicleFitment.cs | 5 +- PartSource.Data/Nexpart/ApplicationSearch.cs | 7 +- PartSource.Services/FitmentService.cs | 169 ++++++------- PartSource.Services/NexpartService.cs | 12 +- PartSource.Services/PartService.cs | 14 +- 20 files changed, 496 insertions(+), 434 deletions(-) create mode 100644 PartSource.Automation/Jobs/PartsSync.cs create mode 100644 PartSource.Data/Models/ProductType.cs diff --git a/PartSource.Api/Controllers/PartsController.cs b/PartSource.Api/Controllers/PartsController.cs index 24d2942..cc9f5ad 100644 --- a/PartSource.Api/Controllers/PartsController.cs +++ b/PartSource.Api/Controllers/PartsController.cs @@ -4,6 +4,7 @@ using PartSource.Data.Dtos; using PartSource.Data.Models; using PartSource.Data.Nexpart; using PartSource.Services; +using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; @@ -41,14 +42,27 @@ namespace PartSource.Api.Controllers return NotFound(); } - Item[] items = new[] + try { - new Item { PartNumber = vehicleFitment.PartNumber, MfrCode = vehicleFitment.LineCode } - }; + 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 = items + Items = new[] + { + new Item { PartNumber = vehicleFitment.PartNumber, MfrCode = vehicleFitment.LineCode } + } }; SmartPageDataSearchResponse smartPageResponse = await _nexpartService.SendRequest(smartPageDataSearch); @@ -74,10 +88,8 @@ namespace PartSource.Api.Controllers }; ApplicationSearchResponse response = await _nexpartService.SendRequest(applicationSearch); - if (response.ResponseBody != null) + if (response.ResponseBody != null && response.ResponseBody is Questions) { - vehicleFitment.DriveTypes = new List(); - Question driveTypeQuestion = ((Questions)response.ResponseBody).Question .Where(q => q.Attribute == "DRIVE_TYPE") .FirstOrDefault(); @@ -124,7 +136,7 @@ namespace PartSource.Api.Controllers { 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" }); } @@ -167,13 +179,13 @@ namespace PartSource.Api.Controllers MfrCode = mappings.Select(m => m.WhiCode).ToArray(), PartType = new[] { new PartType { Id = smartPageResponse.ResponseBody.Item[0].Part.PartType.Id } }, Criterion = new[] + { + new Criterion { - new Criterion - { - Attribute = "REGION", - Id = 2 - } - }, + Attribute = "REGION", + Id = 2 + } + }, GroupBy = "PARTTYPE" }; @@ -205,5 +217,33 @@ namespace PartSource.Api.Controllers }); } + private IList GetDriveTypesFromNote(string fitmentNote) + { + fitmentNote = fitmentNote.ToUpperInvariant(); + IList driveTypes = new List(); + + 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; + } + } } diff --git a/PartSource.Api/appsettings.json b/PartSource.Api/appsettings.json index b609459..fe5b261 100644 --- a/PartSource.Api/appsettings.json +++ b/PartSource.Api/appsettings.json @@ -2,7 +2,7 @@ "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;", //"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=automation;Password=)6L)XP%m(x-UU#M;Encrypt=True;TrustServerCertificate=True;Connection Timeout=300" + "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": { "LogLevel": { diff --git a/PartSource.Automation/Jobs/POC/ImageList.cs b/PartSource.Automation/Jobs/POC/ImageList.cs index 77ec44e..556dc3a 100644 --- a/PartSource.Automation/Jobs/POC/ImageList.cs +++ b/PartSource.Automation/Jobs/POC/ImageList.cs @@ -22,11 +22,13 @@ namespace PartSource.Automation.Jobs.POC { private readonly NexpartService _nexpartService; private readonly PartSourceContext _partSourceContext; + private readonly FitmentContext _fitmentContext; - public GetImageUrls(NexpartService nexpartService, PartSourceContext partSourceContext) + public GetImageUrls(NexpartService nexpartService, PartSourceContext partSourceContext, FitmentContext fitmentContext) { _nexpartService = nexpartService; _partSourceContext = partSourceContext; + _fitmentContext = fitmentContext; } public async Task Run(CancellationToken token, params string[] arguments) @@ -34,45 +36,54 @@ namespace PartSource.Automation.Jobs.POC IList rows = new List { "\"Line Code\", \"Part Number\", \"Image URL(s)\"" }; - - IList importData = await _partSourceContext.ImportData - //.Take(5000) - .ToListAsync(); - foreach (ImportData item in importData) + IList parts = await _fitmentContext.Parts.ToListAsync(); + string oldLineCode = string.Empty; + IList mappings = new List(); + + foreach (Data.Models.Part part in parts) { - SmartPageDataSearch dataSearch = new SmartPageDataSearch + if (part.LineCode != oldLineCode) { - Items = new Item[] + 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 = item.LineCode, - PartNumber = item.PartNumber + MfrCode = mapping.WhiCode, + PartNumber = part.PartNumber } - }, - DataOption = new[] { "DIST_LINE", "ALL" } - }; - - SmartPageDataSearchResponse response = await _nexpartService.SendRequest(dataSearch); - - if (response.ResponseBody.Item?.Length > 0) - { - List urls = new List(); - - if (!string.IsNullOrEmpty(response.ResponseBody.Item[0].PrimaryImg?.ImgUrl)) - { - urls.Add(response.ResponseBody.Item[0].PrimaryImg?.ImgUrl); + }, + DataOption = new[] { "ALL" } }; - if (response.ResponseBody.Item[0].AddImgs?.AddImg?.Length > 0) - { - urls.AddRange(response.ResponseBody.Item[0].AddImgs.AddImg.Select(i => i.AddImgUrl)); - } + SmartPageDataSearchResponse response = await _nexpartService.SendRequest(dataSearch); - if (urls.Count > 0) + if (response.ResponseBody.Item?.Length > 0) { - rows.Add($"\"{item.LineCode}\", \"{item.PartNumber}\", \"{string.Join(";", urls)}\""); + List urls = new List(); + + 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)}\""); + } } } diff --git a/PartSource.Automation/Jobs/PartsSync.cs b/PartSource.Automation/Jobs/PartsSync.cs new file mode 100644 index 0000000..34e1cee --- /dev/null +++ b/PartSource.Automation/Jobs/PartsSync.cs @@ -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 _logger; + private readonly FitmentContext _fitmentContext; + private readonly ShopifyClient _shopifyClient; + + public PartsSync(ILogger logger, FitmentContext fitmentContext, ShopifyClient shopifyClient) + { + _logger = logger; + _fitmentContext = fitmentContext; + _shopifyClient = shopifyClient; + } + + public async Task Run(CancellationToken token, params string[] arguments) + { + IEnumerable products = await _shopifyClient.Products.Get(new Dictionary { { "limit", 250 } }); + + while (products != null && products.Any()) + { + + foreach (Product product in products) + { + try + { + IEnumerable metafields = await _shopifyClient.Metafields.Get(new Dictionary { { "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); + } + } + } + } +} \ No newline at end of file diff --git a/PartSource.Automation/Jobs/ProcessWhiFitment.cs b/PartSource.Automation/Jobs/ProcessWhiFitment.cs index ea34942..44e601c 100644 --- a/PartSource.Automation/Jobs/ProcessWhiFitment.cs +++ b/PartSource.Automation/Jobs/ProcessWhiFitment.cs @@ -56,24 +56,25 @@ namespace PartSource.Automation.Jobs fileGroups.Enqueue(fileGroup); } - Task[] taskArray = new Task[12]; - + Task[] taskArray = new Task[18]; for (int i = 0; i < taskArray.Length; i++) { taskArray[i] = Task.Factory.StartNew(() => { while (fileGroups.TryDequeue(out IGrouping fileGroup)) { + string tableName = string.Empty; + foreach (FileInfo fileInfo in fileGroup) { try { string filename = Decompress(fileInfo); - string tableName = fileInfo.Name.Substring(0, fileInfo.Name.IndexOf('.')); + DataTable dataTable = GetDataTable(filename, out tableName); - 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."); File.Delete(filename); @@ -85,10 +86,9 @@ namespace PartSource.Automation.Jobs } } - string fitmentTable = fileGroup.Key.Substring(0, fileGroup.Key.IndexOf('.')); - _whiSeoService.CreateFitmentTable(fitmentTable); + _whiSeoService.CreateFitmentTable(tableName); - _logger.LogInformation($"Created fitment table for part group {fitmentTable}."); + _logger.LogInformation($"Created fitment table for part group {tableName}."); } }); @@ -112,8 +112,10 @@ namespace PartSource.Automation.Jobs return decompressedFile; } - private DataTable GetDataTable(string filename) + private DataTable GetDataTable(string filename, out string lineCode) { + lineCode = string.Empty; + using DataTable dataTable = new DataTable(); dataTable.Columns.Add("LineCode", typeof(string)); dataTable.Columns.Add("PartNumber", typeof(string)); @@ -121,8 +123,9 @@ namespace PartSource.Automation.Jobs dataTable.Columns.Add("EngineConfigId", typeof(int)); dataTable.Columns.Add("Position", typeof(string)); dataTable.Columns.Add("FitmentNoteHash", typeof(string)); + dataTable.Columns.Add("PartTerminologyId", typeof(int)); - using StreamReader reader = new StreamReader(filename); + using StreamReader reader = new StreamReader(filename); string line = reader.ReadLine(); // Burn the header row while (reader.Peek() > 0) @@ -135,7 +138,7 @@ namespace PartSource.Automation.Jobs 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 position = columns[7].Trim(); @@ -149,10 +152,11 @@ namespace PartSource.Automation.Jobs if (!string.IsNullOrEmpty(lineCode) && !string.IsNullOrEmpty(partNumber) + && int.TryParse(columns[2], out int partTerminologyId) && 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 }); } } diff --git a/PartSource.Automation/Jobs/UpdateFitment.cs b/PartSource.Automation/Jobs/UpdateFitment.cs index 8b1f9de..b08ae3b 100644 --- a/PartSource.Automation/Jobs/UpdateFitment.cs +++ b/PartSource.Automation/Jobs/UpdateFitment.cs @@ -5,6 +5,7 @@ using System.Linq; using System.Text; using System.Threading; using System.Threading.Tasks; +using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Logging; using Newtonsoft.Json; using PartSource.Automation.Services; @@ -13,6 +14,7 @@ using PartSource.Data.Models; using Ratermania.Automation.Interfaces; using Ratermania.Shopify; using Ratermania.Shopify.Resources; +using System.Web; namespace PartSource.Automation.Jobs { @@ -36,52 +38,22 @@ namespace PartSource.Automation.Jobs public async Task Run(CancellationToken token, params string[] arguments) { - IEnumerable products = null; + IList productTypes = await _fitmentContext.ProductTypes + .Where(p => p.Active) + .Select(p => HttpUtility.UrlEncode(p.Name)) + .ToListAsync(); - IList partTypes = new List + foreach (string productType in productTypes) { - "CA115-SC118-FL11803_Custom Lighting Accessories", - "CA117-SC141-FL14106_Jeep Accessories", - "CA117-SC141-FL14134_Truck Running Board and Steps", - "CA117-SC141-FL14199_Bumpers, Bull Bars & Brush Guards", - "CA117-SC157-FL15704_Headache Rack Frames", - "CA117-SC158-FL15802_Salters and Plow Accessories", - "CA117-SC699-FL69902_Crossover Boxes", - "CA117-SC699-FL69903_Specialty Boxes", - "CA117-SC699-FL69904_Transfer Tanks", - "CA135-SC176-FL17601_Trailer Lighting, Stop, Turn, Tail", - "CA135-SC186-FL18607_Roof Racks", - "CA135-SC186-FL18608_Bike Carriers", - "CA135-SC186-FL18609_Cargo Accessories", - "CA135-SC186-FL18610_Cargo Carriers", - "CA135-SC186-FL18611_Watersport Carriers", - "CA135-SC192-FL19201_Class 1 Hitches", - "CA135-SC192-FL19202_Class 2 Hitches", - "CA135-SC192-FL19203_Class 3 Hitches", - "CA135-SC192-FL19204_Towing, Heavy Duty", - "CA135-SC192-FL19205_Towing Electrical, Vehicle Specific", - "CA135-SC192-FL19206_Trailer Parts & Accessories", - "CA135-SC192-FL19207_Trailer Winches, Jacks & Couplers", - "CA135-SC192-FL19208_Class 5 Hitches", - "CA135-SC192-FL19221_Towing Electrical, Connectors & Adapters", - "CA135-SC192-FL19230_Towing Electrical, Controls & Converters", - "CA135-SC192-FL19235_Towing Electrical, Harnesses", - "CA135-SC192-FL19240_Towing Security, Non-Locking", - "CA135-SC192-FL19245_Towing Class V", - "CA135-SC192-FL19280_Towing Balls", - "CA135-SC192-FL19281_Towing Ball Mounts", - "CA135-SC192-FL19282_Towing Security, Locking", - "CA135-SC192-FL19283_Towing Kits & Acc" - }; + _logger.LogInformation("Processing {productType}", HttpUtility.UrlDecode(productType)); - foreach (string partType in partTypes) - { + IEnumerable products = null; try { - products = await _shopifyClient.Products.Get(new Dictionary { { "limit", 250 }, { "product_type", partType } }); + products = await _shopifyClient.Products.Get(new Dictionary { { "limit", 250 }, { "product_type", productType } }); //products = new List //{ - // await _shopifyClient.Products.GetById(4388919574575) + // await _shopifyClient.Products.GetById(7458071052335) //}; } @@ -91,13 +63,12 @@ namespace PartSource.Automation.Jobs throw; } - int i = 1; - while (products != null && products.Any()) { foreach (Product product in products) { ImportData importData = null; + bool isFitment = false; try { @@ -109,48 +80,32 @@ namespace PartSource.Automation.Jobs VariantSku = product.Variants[0].Sku // They know we can't do fitment for variants }; - bool isFitment = false; - string bodyHtml = product.BodyHtml.Substring(0, product.BodyHtml.IndexOf("") + "".Length); + 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("") + "".Length); IList vehicles = _vehicleFitmentService.GetVehiclesForPart(importData.PartNumber, importData.LineCode); IList vehicleIdFitment = _vehicleFitmentService.GetVehicleIdFitment(vehicles); if (!vehicleIdFitment.Any()) { - Console.WriteLine($"No fitment data for SKU {importData.VariantSku}"); + Console.WriteLine($"No fitment data for {importData.LineCode} {importData.PartNumber}"); continue; } - if (vehicleIdFitment.Count > 0) - { - string vehicleIdString = string.Join(',', vehicleIdFitment.Select(j => $"v{j}")); + string vehicleIdString = string.Join(',', vehicleIdFitment.Select(j => $"v{j}")); - bodyHtml += $"
{vehicleIdString}
"; - - isFitment = true; - - string json = JsonConvert.SerializeObject(vehicleIdFitment); - if (json.Length < 100000) - { - Metafield vehicleMetafield = new Metafield - { - Namespace = "fitment", - Key = "ids", - Value = json, - Type = "json_string", - OwnerResource = "product", - OwnerId = product.Id - }; - - await _shopifyClient.Metafields.Add(vehicleMetafield); - } - - else - { - _logger.LogWarning($"Vehicle ID fitment data for SKU {importData.VariantSku} is too large for Shopify and cannot be added."); - continue; - } - } + bodyHtml += $"
{vehicleIdString}
"; + isFitment = true; IList ymmFitment = _vehicleFitmentService.GetYmmFitment(vehicles); if (ymmFitment.Count > 0) @@ -165,79 +120,20 @@ namespace PartSource.Automation.Jobs try { string[] parts = fitment.Split(' ', 2); - stringBuilder.AppendLine($"{parts[1]}{parts[0].Replace("-", ", ")}"); } - catch + catch (Exception ex) { - // This is still a POC at this point. Oh well... + _logger.LogWarning(ex, "YMM fitment for {fitment} was in an invalid format", fitment); } } stringBuilder.AppendLine(""); - bodyHtml += $"
{stringBuilder.ToString()}
"; - - string json = JsonConvert.SerializeObject(ymmFitment); - if (json.Length < 100000) - { - Metafield ymmMetafield = new Metafield - { - Namespace = "fitment", - Key = "seo", - Value = json, - Type = "json_string", - OwnerResource = "product", - OwnerId = product.Id - }; - - await _shopifyClient.Metafields.Add(ymmMetafield); - } - - else - { - _logger.LogWarning($"Year/make/model fitment data for SKU {importData.VariantSku} is too large for Shopify and cannot be added."); - continue; - } + bodyHtml += $"
{stringBuilder}
"; } - Metafield isFitmentMetafield = new Metafield - { - Namespace = "Flags", - Key = "IsFitment", - Value = isFitment.ToString(), - Type = "string", - OwnerResource = "product", - OwnerId = product.Id - }; - - await _shopifyClient.Metafields.Add(isFitmentMetafield); - - //Metafield lineCodeMetafield = new Metafield - //{ - // Namespace = "google", - // Key = "custom_label_0", - // Value = importData.LineCode, - // Type = "string", - // OwnerResource = "product", - // OwnerId = product.Id - //}; - - //await _shopifyClient.Metafields.Add(lineCodeMetafield); - - //Metafield partNumberMetafield = new Metafield - //{ - // Namespace = "google", - // Key = "custom_label_1", - // Value = importData.PartNumber, - // Type = "string", - // OwnerResource = "product", - // OwnerId = product.Id - //}; - - //await _shopifyClient.Metafields.Add(partNumberMetafield); - List tags = new List(); for (int j = 0; j < vehicleIdFitment.Count; j += 25) @@ -275,12 +171,8 @@ namespace PartSource.Automation.Jobs } try { - Console.WriteLine(i); - - _partSourceContext.SaveChanges(); products = await _shopifyClient.Products.GetNext(); - i++; } catch (Exception ex) @@ -289,8 +181,6 @@ namespace PartSource.Automation.Jobs products = await _shopifyClient.Products.GetPrevious(); } } - - Console.WriteLine($"Finished {partType}"); } } } diff --git a/PartSource.Automation/Models/Configuration/FtpConfiguration.cs b/PartSource.Automation/Models/Configuration/FtpConfiguration.cs index 7feee23..cceef98 100644 --- a/PartSource.Automation/Models/Configuration/FtpConfiguration.cs +++ b/PartSource.Automation/Models/Configuration/FtpConfiguration.cs @@ -16,5 +16,7 @@ namespace PartSource.Automation.Models.Configuration public string Username { get; set; } public string Password { get; set; } + + public int Port { get; set; } } } diff --git a/PartSource.Automation/Program.cs b/PartSource.Automation/Program.cs index 01cc20a..3020c37 100644 --- a/PartSource.Automation/Program.cs +++ b/PartSource.Automation/Program.cs @@ -77,7 +77,7 @@ namespace PartSource.Automation .AddAutomation(options => { - options.HasBaseInterval(new TimeSpan(0, 1, 0)) + options.HasBaseInterval(new TimeSpan(0, 15, 0)) .HasMaxFailures(1) //.HasJob(options => options.HasInterval(new TimeSpan(7, 0, 0, 0))); // @@ -95,15 +95,16 @@ namespace PartSource.Automation //.HasJob(options => options.HasInterval(new TimeSpan(24, 0, 0)) // .StartsAt(DateTime.Parse("2021-04-01 08:00:00")) //) - .HasJob(options => + + .HasJob(options => options.HasInterval(new TimeSpan(24, 0, 0)) - //.StartsAt(DateTime.Today.AddHours(25)) + // .StartsAt(DateTime.Today.AddMinutes(15)) // ) //.HasJob(options => options.HasInterval(new TimeSpan(24, 0, 0)) - // .HasDependency() - // // .StartsAt(DateTime.Today.AddHours(28)) - ); + // .HasDependency() + // // .StartsAt(DateTime.Today.AddHours(28)) + ); //); //.AddApiServer(); }) diff --git a/PartSource.Automation/Services/VehicleFitmentService.cs b/PartSource.Automation/Services/VehicleFitmentService.cs index b082315..7e7c59e 100644 --- a/PartSource.Automation/Services/VehicleFitmentService.cs +++ b/PartSource.Automation/Services/VehicleFitmentService.cs @@ -90,7 +90,9 @@ namespace PartSource.Automation.Services public IList GetVehicleIdFitment(IList vehicles) { - return vehicles.Select(v => v.VehicleToEngineConfigId).Distinct().ToArray(); + return vehicles != null + ? vehicles.Select(v => v.VehicleToEngineConfigId).Distinct().ToArray() + : new List(); } public IList GetVehiclesForPart(string partNumber, string lineCode, int maxVehicles = 0) @@ -100,7 +102,7 @@ namespace PartSource.Automation.Services return null; } - partNumber = Regex.Replace(partNumber, "[^a-zA-Z0-9\\-]", string.Empty); + partNumber = Regex.Replace(partNumber, "[^a-zA-Z0-9]", string.Empty); IQueryable whiCodes = _fitmentContext.DcfMappings .Where(d => d.LineCode == lineCode) diff --git a/PartSource.Automation/Services/WhiSeoService.cs b/PartSource.Automation/Services/WhiSeoService.cs index a086b13..0f35c91 100644 --- a/PartSource.Automation/Services/WhiSeoService.cs +++ b/PartSource.Automation/Services/WhiSeoService.cs @@ -5,167 +5,154 @@ using Microsoft.Extensions.Logging; using PartSource.Automation.Models.Configuration; 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 { - public class WhiSeoService - { - private readonly FtpService _ftpService; - private readonly string _connectionString; - private readonly ILogger _logger; + public class WhiSeoService + { + private readonly FtpService _ftpService; + private readonly string _connectionString; + private readonly ILogger _logger; - public WhiSeoService(IConfiguration configuration, ILogger logger) - { - FtpConfiguration ftpConfiguration = configuration.GetSection("FtpServers:WhiConfiguration").Get(); - _ftpService = new FtpService(ftpConfiguration); + public WhiSeoService(IConfiguration configuration, ILogger logger) + { + FtpConfiguration ftpConfiguration = configuration.GetSection("FtpServers:WhiConfiguration").Get(); + _ftpService = new FtpService(ftpConfiguration); - _connectionString = configuration.GetConnectionString("FitmentDatabase"); + _connectionString = configuration.GetConnectionString("FitmentDatabase"); - _logger = logger; - } + _logger = logger; + } - public void GetFiles(SeoDataType seoDataType) - { - string seoDataTypeString = seoDataType.ToString().ToLowerInvariant(); - string[] files = _ftpService.ListFiles(seoDataTypeString); + public void GetFiles(SeoDataType seoDataType) + { + string seoDataTypeString = seoDataType.ToString().ToLowerInvariant(); + + // 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) - { - if (file.Contains(".csv")) - { - try - { - _ftpService.Download($"{seoDataTypeString}/{file}"); - _logger.LogInformation($"Finished downloading {file}."); - } + public void TruncateVehicleTable() + { + using SqlConnection connection = new SqlConnection(_connectionString); + connection.Open(); + using SqlCommand command = new SqlCommand($"truncate table dbo.Vehicle", connection); + command.ExecuteNonQuery(); + } - catch (Exception ex) - { - _logger.LogWarning($"Failed to download {file}, quitting", ex); - throw; - } - } - } - } + public void TruncateFitmentTables() + { + using SqlConnection connection = new SqlConnection(_connectionString); + connection.Open(); - public void TruncateVehicleTable() - { - using SqlConnection connection = new SqlConnection(_connectionString); - connection.Open(); + using SqlCommand command = new SqlCommand($"exec DropFitmentTables", connection); + command.ExecuteNonQuery(); + } - using SqlCommand command = new SqlCommand($"truncate table dbo.Vehicle", connection); - command.ExecuteNonQuery(); - } + public void SaveNotes(IDictionary notes) + { + using DataTable dataTable = new DataTable(); + dataTable.Columns.Add("NoteText", typeof(string)); + dataTable.Columns.Add("Hash", typeof(string)); - public void TruncateFitmentTables() - { - using SqlConnection connection = new SqlConnection(_connectionString); - connection.Open(); + foreach (KeyValuePair note in notes) + { - using SqlCommand command = new SqlCommand($"exec DropFitmentTables", connection); - command.ExecuteNonQuery(); - } + dataTable.Rows.Add(new string[] { note.Value, note.Key }); + } - public void SaveNotes(IDictionary notes) - { - using DataTable dataTable = new DataTable(); - dataTable.Columns.Add("NoteText", typeof(string)); - dataTable.Columns.Add("Hash", typeof(string)); + using SqlConnection connection = new SqlConnection(_connectionString); + connection.Open(); - foreach (KeyValuePair 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); - connection.Open(); + public void BulkCopyFitment(DataTable dataTable, string tableName) + { + using SqlConnection connection = new SqlConnection(_connectionString); + connection.Open(); - using SqlBulkCopy bulk = new SqlBulkCopy(connection) - { - DestinationTableName = $"FitmentNote", - BulkCopyTimeout = 14400 - }; + string sql = string.Empty; - bulk.WriteToServer(dataTable); - } + using SqlCommand command = new SqlCommand($"EXEC CreateFitmentTempTable @tableName = '{tableName}'", connection); + command.ExecuteNonQuery(); - public void BulkCopyFitment(DataTable dataTable, string tableName) - { - using SqlConnection connection = new SqlConnection(_connectionString); - connection.Open(); + using SqlBulkCopy bulk = new SqlBulkCopy(connection) + { + DestinationTableName = $"FitmentTemp.{tableName}", + BulkCopyTimeout = 14400 + }; - string sql = string.Empty; + bulk.WriteToServer(dataTable); + } - using SqlCommand command = new SqlCommand($"EXEC CreateFitmentTempTable @tableName = '{tableName}'", connection); - command.ExecuteNonQuery(); + public void BulkCopyVehicle(DataTable dataTable, string tableName) + { + using SqlConnection connection = new SqlConnection(_connectionString); + connection.Open(); - using SqlBulkCopy bulk = new SqlBulkCopy(connection) - { - DestinationTableName = $"FitmentTemp.{tableName}", - BulkCopyTimeout = 14400 - }; + string sql = string.Empty; - bulk.WriteToServer(dataTable); - } + using SqlCommand command = new SqlCommand($"EXEC CreateVehicleTempTable @tableName = '{tableName}'", connection); + command.ExecuteNonQuery(); - public void BulkCopyVehicle(DataTable dataTable, string tableName) - { - using SqlConnection connection = new SqlConnection(_connectionString); - connection.Open(); + using SqlBulkCopy bulk = new SqlBulkCopy(connection) + { + DestinationTableName = $"VehicleTemp.{tableName}", + BulkCopyTimeout = 14400 + }; - string sql = string.Empty; + bulk.WriteToServer(dataTable); + } - using SqlCommand command = new SqlCommand($"EXEC CreateVehicleTempTable @tableName = '{tableName}'", connection); - command.ExecuteNonQuery(); + public void CreateFitmentTable(string tableName) + { + using SqlConnection connection = new SqlConnection(_connectionString); + connection.Open(); - using SqlBulkCopy bulk = new SqlBulkCopy(connection) - { - DestinationTableName = $"VehicleTemp.{tableName}", - BulkCopyTimeout = 14400 - }; + using SqlCommand command = new SqlCommand($"exec CreateFitmentTable @tableName = '{tableName}'", connection); + command.CommandTimeout = 1800; + command.ExecuteNonQuery(); + } - bulk.WriteToServer(dataTable); - } + public void CreateFitmentView() + { + using SqlConnection connection = new SqlConnection(_connectionString); + connection.Open(); - public void CreateFitmentTable(string tableName) - { - using SqlConnection connection = new SqlConnection(_connectionString); - connection.Open(); + using SqlCommand command = new SqlCommand($"exec CreateFitmentView", connection); + command.CommandTimeout = 1800; + command.ExecuteNonQuery(); - using SqlCommand command = new SqlCommand($"exec CreateFitmentTable @tableName = '{tableName}'", connection); - command.CommandTimeout = 1800; - command.ExecuteNonQuery(); - } + using SqlCommand command2 = new SqlCommand($"exec CreateFitmentIndexes", connection); + command.CommandTimeout = 3600; + command2.ExecuteNonQuery(); + } - public void CreateFitmentView() - { - using SqlConnection connection = new SqlConnection(_connectionString); - connection.Open(); + public void CreateVehicleTable() + { + using SqlConnection connection = new SqlConnection(_connectionString); + connection.Open(); - using SqlCommand command = new SqlCommand($"exec CreateFitmentView", connection); - command.CommandTimeout = 1800; - command.ExecuteNonQuery(); - - using SqlCommand command2 = new SqlCommand($"exec CreateFitmentIndexes", connection); - command.CommandTimeout = 3600; - command2.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(); - } - } + using SqlCommand command = new SqlCommand($"exec CreateVehicleTable", connection); + command.CommandTimeout = 1800; + command.ExecuteNonQuery(); + } + } } #pragma warning restore CA2100 // Review SQL queries for security vulnerabilities \ No newline at end of file diff --git a/PartSource.Automation/appsettings.json b/PartSource.Automation/appsettings.json index ec663d7..4fe295c 100644 --- a/PartSource.Automation/appsettings.json +++ b/PartSource.Automation/appsettings.json @@ -1,6 +1,7 @@ { "ConnectionStrings": { - "FitmentDatabase": "Data Source=omg-optiplex;Initial Catalog=WhiFitment;User ID=sa;Password=TNG497us?4TW!;TrustServerCertificate=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;" }, "emailConfiguration": { @@ -14,13 +15,15 @@ "Username": "ps-ftp\\$ps-ftp", "Password": "ycvXptffBxqkBXW4vuRYqn4Zi1soCvnvMMolTe5HNSeAlcl3bAyJYtNhG579", "Url": "ftp://waws-prod-yq1-007.ftp.azurewebsites.windows.net/site/wwwroot", - "Destination": "C:\\Partsource.Automation\\Downloads" + "Destination": "C:\\Partsource.Automation\\Downloads", + "Port": 21 }, "WhiConfiguration": { "Username": "ctc_seo", - "Password": "be34hz64e4", + "Password": "YD3gtaQ5kPdtNKs", "Url": "ftp://ftp.whisolutions.com", - "Destination": "C:\\Partsource.Automation\\Downloads\\WHI" + "Destination": "C:\\Partsource.Automation\\Downloads\\WHI", + "Port": 3001 } }, "ssisConfiguration": { diff --git a/PartSource.Data/Contexts/FitmentContext.cs b/PartSource.Data/Contexts/FitmentContext.cs index d55c722..a46169c 100644 --- a/PartSource.Data/Contexts/FitmentContext.cs +++ b/PartSource.Data/Contexts/FitmentContext.cs @@ -13,10 +13,14 @@ namespace PartSource.Data.Contexts public DbSet DcfMappings { get; set; } + public DbSet Parts { get; set; } + public DbSet Fitments { get; set; } public DbSet FitmentNotes { get; set; } + public DbSet ProductTypes { get; set; } + public DbSet Vehicles { get; set; } public DbSet VehicleFitments { get; set; } diff --git a/PartSource.Data/Contexts/PartSourceContext.cs b/PartSource.Data/Contexts/PartSourceContext.cs index 6fc0e76..1ec414e 100644 --- a/PartSource.Data/Contexts/PartSourceContext.cs +++ b/PartSource.Data/Contexts/PartSourceContext.cs @@ -26,7 +26,7 @@ namespace PartSource.Data.Contexts public DbSet PartPrices { get; set; } - public DbSet Parts { get; set; } + // public DbSet Parts { get; set; } public DbSet ShopifyChangelogs { get; set; } diff --git a/PartSource.Data/Dtos/VehicleFitmentDto.cs b/PartSource.Data/Dtos/VehicleFitmentDto.cs index 66819ed..de558db 100644 --- a/PartSource.Data/Dtos/VehicleFitmentDto.cs +++ b/PartSource.Data/Dtos/VehicleFitmentDto.cs @@ -7,8 +7,13 @@ namespace PartSource.Data.Dtos { public class VehicleFitmentDto : VehicleFitment { + public string PartDescription { get; set; } + + // May not be needed, but don't remove just yet public IList SubmodelNames { get; set; } public IList DriveTypes { get; set; } + + public IList Notes { get; set; } } } \ No newline at end of file diff --git a/PartSource.Data/Models/ProductType.cs b/PartSource.Data/Models/ProductType.cs new file mode 100644 index 0000000..844b618 --- /dev/null +++ b/PartSource.Data/Models/ProductType.cs @@ -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; } + } +} diff --git a/PartSource.Data/Models/VehicleFitment.cs b/PartSource.Data/Models/VehicleFitment.cs index ed55446..7e39a58 100644 --- a/PartSource.Data/Models/VehicleFitment.cs +++ b/PartSource.Data/Models/VehicleFitment.cs @@ -1,4 +1,6 @@ -namespace PartSource.Data.Models +using Newtonsoft.Json; + +namespace PartSource.Data.Models { public class VehicleFitment { @@ -8,6 +10,7 @@ public string PartNumber { get; set; } + [JsonIgnore] public string NoteText { get; set; } public int Year { get; set; } diff --git a/PartSource.Data/Nexpart/ApplicationSearch.cs b/PartSource.Data/Nexpart/ApplicationSearch.cs index db4111c..174031c 100644 --- a/PartSource.Data/Nexpart/ApplicationSearch.cs +++ b/PartSource.Data/Nexpart/ApplicationSearch.cs @@ -31,12 +31,15 @@ namespace PartSource.Data.Nexpart public bool SecondaryDCF => true; [XmlElement(Order = 6)] - public Criterion[] Criterion { get; set; } + public string[] AppOption { get; set; } [XmlElement(Order = 7)] - public string GroupBy { get; set; } + public Criterion[] Criterion { get; set; } [XmlElement(Order = 8)] + public string GroupBy { get; set; } + + [XmlElement(Order = 9)] public string QuestionOption { get; set; } } } diff --git a/PartSource.Services/FitmentService.cs b/PartSource.Services/FitmentService.cs index f0903bb..264d6d0 100644 --- a/PartSource.Services/FitmentService.cs +++ b/PartSource.Services/FitmentService.cs @@ -13,11 +13,11 @@ namespace PartSource.Services { public class FitmentService { - private readonly FitmentContext _fitmentContext; + private readonly FitmentContext _fitmentContext; - public FitmentService(FitmentContext fitmentContext) + public FitmentService(FitmentContext fitmentContext) { - _fitmentContext = fitmentContext; + _fitmentContext = fitmentContext; } public async Task GetFitmentNotes(string sku, int vehicleId) @@ -36,120 +36,115 @@ namespace PartSource.Services BaseVehicleId = vf.BaseVehicleId, EngineConfigId = vf.EngineConfigId, VehicleToEngineConfigId = vf.VehicleToEngineConfigId, - SubmodelName = vf.SubmodelName + SubmodelName = vf.SubmodelName }) .FirstOrDefaultAsync(); - if (vehicleFitment == null) - { - return null; - } - return vehicleFitment; } public IList GetYmmFitment(IList vehicles) - { - if (vehicles.Count == 0) - { - return new string[0]; - } + { + if (vehicles.Count == 0) + { + return new string[0]; + } - IList fitmentTags = new List(); + IList fitmentTags = new List(); - IList makeModels = vehicles.OrderBy(v => v.MakeName).ThenBy(v => v.ModelName).Select(v => $"{v.MakeName},{v.ModelName}").Distinct().ToList(); + IList 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]; + foreach (string makeModel in makeModels) + { + string make = makeModel.Split(',')[0]; + string model = makeModel.Split(',')[1]; - List years = vehicles - .Where(v => v.MakeName == make && v.ModelName == model) - .OrderBy(v => v.Year) - .Select(v => v.Year.ToString().Trim()) - .Distinct() - .ToList(); + List 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()}"; + string tag = $"{string.Join('-', years)} {make.Trim()} {model.Trim()}"; - System.Diagnostics.Debug.WriteLine(tag); + System.Diagnostics.Debug.WriteLine(tag); - fitmentTags.Add(tag); - } + fitmentTags.Add(tag); + } - return fitmentTags; - } + return fitmentTags; + } - public IList GetYmmFitmentRange(IList vehicles) - { - if (vehicles.Count == 0) - { - return new string[0]; - } + public IList GetYmmFitmentRange(IList vehicles) + { + if (vehicles.Count == 0) + { + return new string[0]; + } - IList fitmentTags = new List(); + IList fitmentTags = new List(); - IList makeModels = vehicles.Select(v => $"{v.MakeName},{v.ModelName}").Distinct().ToList(); + IList 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]; + 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 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); + 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()}"; + string tag = minYear == maxYear + ? $"{minYear} {make.Trim()} {model.Trim()}" + : $"{minYear}-{maxYear} {make.Trim()} {model.Trim()}"; - System.Diagnostics.Debug.WriteLine(tag); + System.Diagnostics.Debug.WriteLine(tag); - fitmentTags.Add(tag); - } + fitmentTags.Add(tag); + } - return fitmentTags; - } + return fitmentTags; + } - public IList GetVehicleIdFitment(IList vehicles) - { - return vehicles.Select(v => v.VehicleToEngineConfigId).Distinct().ToList(); - } + public IList GetVehicleIdFitment(IList vehicles) + { + return vehicles.Select(v => v.VehicleToEngineConfigId).Distinct().ToList(); + } - public IList GetVehiclesForPart(string partNumber, string lineCode, int maxVehicles = 0) - { - if (string.IsNullOrEmpty(partNumber) || string.IsNullOrEmpty(lineCode)) - { - return null; - } + public IList 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); + partNumber = Regex.Replace(partNumber, "[^a-zA-Z0-9]", string.Empty); - IQueryable whiCodes = _fitmentContext.DcfMappings - .Where(d => d.LineCode == lineCode) - .Select(d => d.WhiCode); + IQueryable whiCodes = _fitmentContext.DcfMappings + .Where(d => d.LineCode == lineCode) + .Select(d => d.WhiCode); - IQueryable 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); + IQueryable 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); - } + if (maxVehicles > 0) + { + vehicles = vehicles.Take(maxVehicles); + } - return vehicles.ToList(); - } - } + return vehicles.ToList(); + } + } } diff --git a/PartSource.Services/NexpartService.cs b/PartSource.Services/NexpartService.cs index 8e5641c..0bf411b 100644 --- a/PartSource.Services/NexpartService.cs +++ b/PartSource.Services/NexpartService.cs @@ -25,17 +25,20 @@ namespace PartSource.Services U content; string x = textWriter.ToString(); - - using (HttpClient client = new HttpClient()) + System.Diagnostics.Debug.WriteLine(x); + + using (HttpClient client = new HttpClient()) { client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", "QjM4ODAyMzM3QjQxNEM2QTk4M0RFMjM0Mjk4Rjk4M0UtOUIzNUUxNzNBQUYxNEE2QjhCQjI2RjZDOUY2ODk1NDU6MkMzOUVCOTYtRDBBRS00QkVBLTlCMzItMUYyNTA5MDJGQTE0"); try { //HttpResponseMessage response = await client.PostAsync(ConfigurationManager.AppSettings["NexpartUrl"], (HttpContent)new StringContent(sb.ToString(), Encoding.UTF8, "text/xml")); - HttpResponseMessage response = await client.PostAsync("https://acespssprod.nexpart.com:4085/partselect/2.0/services/PartSelectService.PartSelectHttpSoap11Endpoint", new StringContent(textWriter.ToString(), Encoding.UTF8, "text/xml")); + HttpResponseMessage response = await client.PostAsync("http://acespssprod.nexpart.com:8085/partselect/2.0/services/PartSelectService.PartSelectHttpSoap11Endpoint", new StringContent(textWriter.ToString(), Encoding.UTF8, "text/xml")); Stream result = await response.Content.ReadAsStreamAsync(); + string str = await response.Content.ReadAsStringAsync(); - + System.Diagnostics.Debug.WriteLine(str); + content = (U)((Envelope)serializer.Deserialize(result)).Body.Content; ; } @@ -44,6 +47,7 @@ namespace PartSource.Services throw; } } + return content; } } diff --git a/PartSource.Services/PartService.cs b/PartSource.Services/PartService.cs index 4162a3d..fda4ffb 100644 --- a/PartSource.Services/PartService.cs +++ b/PartSource.Services/PartService.cs @@ -12,26 +12,28 @@ namespace PartSource.Services { public class PartService { - private readonly PartSourceContext _context; + private readonly PartSourceContext _partSourceContext; + private readonly FitmentContext _fitmentContext; - public PartService(PartSourceContext context) + public PartService(PartSourceContext partSourceContext, FitmentContext fitmentContext) { - _context = context; + _partSourceContext = partSourceContext; + _fitmentContext = fitmentContext; } public async Task GetInventory(int sku, int storeNumber) { - return await _context.PartAvailabilities.FirstOrDefaultAsync(s => s.Store == storeNumber && s.SKU == sku); + return await _partSourceContext.PartAvailabilities.FirstOrDefaultAsync(s => s.Store == storeNumber && s.SKU == sku); } public async Task GetPartBySku(string sku) { - return await _context.Parts.SingleOrDefaultAsync(p => p.Sku == sku); + return await _fitmentContext.Parts.SingleOrDefaultAsync(p => p.Sku == sku); } public async Task> GetDcfMapping(string partsourceLineCode) { - return await _context.DcfMappings + return await _fitmentContext.DcfMappings .Where(dcf => dcf.LineCode == partsourceLineCode) .ToListAsync(); }