From ef5e4422c08d756a06e685562a6460a2e2582af0 Mon Sep 17 00:00:00 2001 From: Tom Raterman Date: Tue, 14 Apr 2020 17:50:21 -0400 Subject: [PATCH] Finalized UpdatePositioning job --- PartSource.Automation/Factories/JobFactory.cs | 37 ++-- PartSource.Automation/Jobs/UpdateFitment.cs | 109 ++++++------ .../Jobs/UpdatePositioning.cs | 165 +++++++++++------- PartSource.Automation/Program.cs | 1 + .../Properties/launchSettings.json | 2 +- PartSource.Services/PartService.cs | 2 + 6 files changed, 181 insertions(+), 135 deletions(-) diff --git a/PartSource.Automation/Factories/JobFactory.cs b/PartSource.Automation/Factories/JobFactory.cs index 9107072..cb360a0 100644 --- a/PartSource.Automation/Factories/JobFactory.cs +++ b/PartSource.Automation/Factories/JobFactory.cs @@ -12,36 +12,39 @@ namespace PartSource.Automation.Factories { public class JobFactory { - public IServiceProvider _serviceProvider; + private readonly IServiceProvider _serviceProvider; - public JobFactory(IServiceProvider serviceProvider) - { - _serviceProvider = serviceProvider; - } + public JobFactory(IServiceProvider serviceProvider) + { + _serviceProvider = serviceProvider; + } public IAutomationJob Build(string jobName) { switch (jobName) { - case nameof(AddProducts): - return _serviceProvider.GetService(); + case nameof(AddProducts): + return _serviceProvider.GetService(); - case nameof(DeleteProducts): - return _serviceProvider.GetService(); + case nameof(DeleteProducts): + return _serviceProvider.GetService(); - case nameof(TestJob): - return new TestJob(); + case nameof(TestJob): + return new TestJob(); - case nameof(UpdateFitment): - return _serviceProvider.GetService(); + case nameof(UpdateFitment): + return _serviceProvider.GetService(); - case nameof(UpdatePricing): + case nameof(UpdatePricing): return _serviceProvider.GetService(); - case nameof(ExecuteSsisPackages): - return _serviceProvider.GetService(); + case nameof(UpdatePositioning): + return _serviceProvider.GetService(); - default: + case nameof(ExecuteSsisPackages): + return _serviceProvider.GetService(); + + default: throw new Exception($"The job {jobName} could not be found."); } } diff --git a/PartSource.Automation/Jobs/UpdateFitment.cs b/PartSource.Automation/Jobs/UpdateFitment.cs index 286ec75..591e440 100644 --- a/PartSource.Automation/Jobs/UpdateFitment.cs +++ b/PartSource.Automation/Jobs/UpdateFitment.cs @@ -53,72 +53,73 @@ namespace PartSource.Automation.Jobs ImportData importData = _partSourceContext.ImportData.FirstOrDefault(i => i.VariantSku == product.Variants[0].Sku); IList vehicles = _vehicleService.GetVehiclesForPart(importData?.PartNumber, importData?.LineCode); - if (vehicles.Count > 0) + if (vehicles.Count == 0) { - bool isFitment = false; + continue; + } - IList vehicleIdFitment = _vehicleService.GetVehicleIdFitment(vehicles); - if (vehicleIdFitment.Count > 0) + bool isFitment = false; + + IList vehicleIdFitment = _vehicleService.GetVehicleIdFitment(vehicles); + if (vehicleIdFitment.Count > 0) + { + isFitment = true; + + string json = JsonConvert.SerializeObject(vehicleIdFitment); + if (json.Length >= 100000) { - isFitment = true; - - string json = JsonConvert.SerializeObject(vehicleIdFitment); - if (json.Length >= 100000) - { - continue; - } - - Metafield vehicleMetafield = new Metafield - { - Namespace = "fitment", - Key = "ids", - Value = json, - ValueType = "json_string", - OwnerResource = "product", - OwnerId = product.Id - }; - - await _shopifyClient.Metafields.Add(vehicleMetafield); + continue; } - IList ymmFitment = _vehicleService.GetYmmFitment(vehicles); - if (ymmFitment.Count > 0) + Metafield vehicleMetafield = new Metafield { - isFitment = true; - - string json = JsonConvert.SerializeObject(ymmFitment); - if (json.Length >= 100000) - { - continue; - } - - 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", + Namespace = "fitment", + Key = "ids", + Value = json, + ValueType = "json_string", OwnerResource = "product", OwnerId = product.Id }; - await _shopifyClient.Metafields.Add(isFitmentMetafield); + await _shopifyClient.Metafields.Add(vehicleMetafield); } - } + IList ymmFitment = _vehicleService.GetYmmFitment(vehicles); + if (ymmFitment.Count > 0) + { + isFitment = true; + + string json = JsonConvert.SerializeObject(ymmFitment); + if (json.Length >= 100000) + { + continue; + } + + 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); + } catch { diff --git a/PartSource.Automation/Jobs/UpdatePositioning.cs b/PartSource.Automation/Jobs/UpdatePositioning.cs index 42f8bed..b09f29a 100644 --- a/PartSource.Automation/Jobs/UpdatePositioning.cs +++ b/PartSource.Automation/Jobs/UpdatePositioning.cs @@ -8,8 +8,10 @@ using PartSource.Services; using PartSource.Services.Integrations; using System; using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Text; +using System.Text.RegularExpressions; using System.Threading.Tasks; namespace PartSource.Automation.Jobs @@ -38,74 +40,46 @@ namespace PartSource.Automation.Jobs try { ImportData importData = _partSourceContext.ImportData.FirstOrDefault(i => i.VariantSku == product.Variants[0].Sku); + + if (importData?.LineCode == "SVG") // Headlights go in front, DUH + { + continue; + } + + IList fitments = GetPositionOrderedFitments(importData?.PartNumber, importData?.LineCode); IList vehicles = _vehicleService.GetVehiclesForPart(importData?.PartNumber, importData?.LineCode); - if (vehicles.Count > 0) + if (fitments.Count == 0 || vehicles.Count == 0) { - bool isFitment = false; - - IList vehicleIdFitment = _vehicleService.GetVehicleIdFitment(vehicles); - if (vehicleIdFitment.Count > 0) - { - isFitment = true; - - string json = JsonConvert.SerializeObject(vehicleIdFitment); - if (json.Length >= 100000) - { - continue; - } - - Metafield vehicleMetafield = new Metafield - { - Namespace = "fitment", - Key = "ids", - Value = json, - ValueType = "json_string", - OwnerResource = "product", - OwnerId = product.Id - }; - - await _shopifyClient.Metafields.Add(vehicleMetafield); - } - - IList ymmFitment = _vehicleService.GetYmmFitment(vehicles); - if (ymmFitment.Count > 0) - { - isFitment = true; - - string json = JsonConvert.SerializeObject(ymmFitment); - if (json.Length >= 100000) - { - continue; - } - - 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); + continue; } - } + await DeletePositionMetafields(product.Id); + + string currentPosition = fitments[0].Position; + List vehicleIds = new List(); + + foreach (Fitment fitment in fitments) + { + if (fitment.Position != currentPosition) + { + await SavePositionMetafield(product, vehicleIds, currentPosition); + + currentPosition = fitment.Position; + vehicleIds = new List(); + } + + // We don't need to DCF map because these are both sourced from WHI + IList fitmentVehicleIds = vehicles.Where(v => v.BaseVehicleId == fitment.BaseVehicleId && v.EngineConfigId == fitment.EngineConfigId) + .Select(v => v.VehicleToEngineConfigId) + .Distinct() + .ToList(); + + vehicleIds.AddRange(fitmentVehicleIds); + } + + await SavePositionMetafield(product, vehicleIds, currentPosition); + } catch { @@ -132,5 +106,70 @@ namespace PartSource.Automation.Jobs IsSuccess = true }; } + + private IList GetPositionOrderedFitments(string partNumber, string lineCode) + { + partNumber = Regex.Replace(partNumber, "[^a-zA-Z0-9]", string.Empty); + + IQueryable whiCodes = _partSourceContext.DcfMappings + .Where(d => d.LineCode == lineCode) + .Select(d => d.WhiCode); + + return _partSourceContext.Fitments + .Where(f => f.PartNumber == partNumber && whiCodes.Contains(f.LineCode) && !string.IsNullOrEmpty(f.Position)) + .OrderBy(f => f.Position) + .ToList(); + } + + [SuppressMessage("Globalization", "CA1308:Normalize strings to uppercase", Justification = "It's a Shopify metafield key")] + private async Task SavePositionMetafield(Product product, IList vehicleIds, string position) + { + if (vehicleIds.Count == 0) + { + return; + } + + string json = JsonConvert.SerializeObject(vehicleIds); + if (json.Length >= 100000) + { + // TODO: Logging + return; + } + + string key = position.ToLowerInvariant().Replace(" ", "_"); + if (key.Length > 20) + { + key = key.Substring(0, 20); + } + + Metafield vehicleMetafield = new Metafield + { + Namespace = "position", + Key = key, + Value = json, + ValueType = "json_string", + OwnerResource = "product", + OwnerId = product.Id + }; + + await _shopifyClient.Metafields.Add(vehicleMetafield); + } + + private async Task DeletePositionMetafields(long shopifyId) + { + IDictionary parameters = new Dictionary + { + { "metafield[owner_id]", shopifyId}, + { "metafield[owner_resource]", "product" }, + { "namespace", "position" }, + }; + + IEnumerable metafields = await _shopifyClient.Metafields.Get(parameters); + + foreach (Metafield metafield in metafields) + { + await _shopifyClient.Metafields.Delete(metafield); + } + } } } diff --git a/PartSource.Automation/Program.cs b/PartSource.Automation/Program.cs index a5114d6..4d607fb 100644 --- a/PartSource.Automation/Program.cs +++ b/PartSource.Automation/Program.cs @@ -110,6 +110,7 @@ namespace PartSource.Automation .AddSingleton() .AddSingleton() .AddSingleton() + .AddSingleton() .AddSingleton() .AddSingleton() .BuildServiceProvider(); diff --git a/PartSource.Automation/Properties/launchSettings.json b/PartSource.Automation/Properties/launchSettings.json index 85bfddd..4e4d7f7 100644 --- a/PartSource.Automation/Properties/launchSettings.json +++ b/PartSource.Automation/Properties/launchSettings.json @@ -2,7 +2,7 @@ "profiles": { "PartSource.Automation": { "commandName": "Project", - "commandLineArgs": "UpdatePricing", + "commandLineArgs": "UpdatePositioning", "environmentVariables": { "PS_AUTOMATION_ENVIRONMENT": "development" } diff --git a/PartSource.Services/PartService.cs b/PartSource.Services/PartService.cs index 3ef3128..0f549bb 100644 --- a/PartSource.Services/PartService.cs +++ b/PartSource.Services/PartService.cs @@ -1,11 +1,13 @@ using PartSource.Data; using PartSource.Data.Dtos; using PartSource.Data.Models; +using System; using System.Collections.Generic; using System.Linq; namespace PartSource.Services { + [Obsolete] public class PartService { private readonly PartSourceContext _context;