using Microsoft.EntityFrameworkCore; using Newtonsoft.Json; using PartSource.Automation.Models; using PartSource.Automation.Services; using PartSource.Data; using PartSource.Data.Contexts; using PartSource.Data.Models; using PartSource.Services; using Ratermania.Automation.Interfaces; using Ratermania.Shopify; using Ratermania.Shopify.Resources; using System; using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Text.RegularExpressions; using System.Threading; using System.Threading.Tasks; namespace PartSource.Automation.Jobs { public class UpdatePositioning : IAutomationJob { private readonly ShopifyClient _shopifyClient; private readonly PartSourceContext _partSourceContext; private readonly FitmentContext _fitmentContext; private readonly VehicleFitmentService _vehicleFitmentService; public UpdatePositioning(PartSourceContext partSourceContext, FitmentContext fitmentContext, ShopifyClient shopifyClient, VehicleFitmentService vehicleFitmentService) { _partSourceContext = partSourceContext; _fitmentContext = fitmentContext; _shopifyClient = shopifyClient; _vehicleFitmentService = vehicleFitmentService; } public async Task Run(CancellationToken token, params string[] arguments) { IDictionary parameters = new Dictionary { { "limit", 250 } }; IEnumerable products = await _shopifyClient.Products.Get(parameters); 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" } }); ImportData 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 }; if (importData == null || importData?.LineCode == "SVG") // Headlights go in front, DUH { continue; } IList fitments = GetPositionOrderedFitments(importData?.PartNumber, importData?.LineCode); IList vehicles = _vehicleFitmentService.GetVehiclesForPart(importData?.PartNumber, importData?.LineCode); if (fitments.Count == 0 || vehicles.Count == 0) { continue; } 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); //IList notes = fitments.Select(f => f.NoteText) // .Distinct() // .ToList(); //IList vehicleNotes = new List(); //foreach (string noteText in notes) //{ // 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(); // vehicleNotes.Add(new { noteText, vehicleIds }); //} //string json = JsonConvert.SerializeObject(vehicleNotes); //if (json.Length >= 100000) //{ // continue; //} //Metafield vehicleMetafield = new Metafield //{ // 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"; } catch (Exception ex) { Console.WriteLine($"{product.Id}: {ex.Message}"); } } try { products = await _shopifyClient.Products.GetNext(); } catch (Exception ex) { Console.WriteLine($"Retrying: {ex.Message}"); products = await _shopifyClient.Products.GetPrevious(); } } } private IList GetPositionOrderedFitments(string partNumber, string lineCode) { partNumber = Regex.Replace(partNumber, "[^a-zA-Z0-9]\\-", string.Empty); IQueryable whiCodes = _fitmentContext.DcfMappings .Where(d => d.LineCode == lineCode) .Select(d => d.WhiCode); return _fitmentContext.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, Type = "json_string", OwnerResource = "product", OwnerId = product.Id }; System.Diagnostics.Debug.WriteLine(json); await _shopifyClient.Metafields.Add(vehicleMetafield); } } }