From f2ca3419b007d8cad25a66bfe3d2baa3fa1146c5 Mon Sep 17 00:00:00 2001 From: Tom Raterman Date: Sun, 26 Jul 2020 21:52:36 -0400 Subject: [PATCH] Code-complete v2 vehicle API --- PartSource.Api/.config/dotnet-tools.json | 12 + .../Controllers/BaseApiController.cs | 35 + .../Controllers/LegacyVehiclesController.cs | 152 ++++ .../Controllers/VehiclesController.cs | 181 +++-- PartSource.Api/PartSource.Api.csproj | 1 + PartSource.Api/Startup.cs | 12 +- PartSource.Api/appsettings.development.json | 6 +- PartSource.Automation/Factories/JobFactory.cs | 4 +- .../Jobs/AddAndUpdateProducts.cs | 320 ++++++++ PartSource.Automation/Jobs/AddProducts.cs | 152 ---- .../Jobs/UpdateFitment - Copy.cs | 727 +++++------------- PartSource.Automation/Jobs/UpdateFitment.cs | 324 ++++---- .../Jobs/UpdatePositioning.cs | 2 +- PartSource.Automation/Program.cs | 2 +- .../Properties/launchSettings.json | 2 +- PartSource.Automation/appsettings.json | 4 +- PartSource.Data/Dtos/EngineDto.cs | 17 + PartSource.Data/Dtos/SubmodelDto.cs | 17 + PartSource.Data/Models/BaseVehicle.cs | 18 +- PartSource.Data/Models/Engine.cs | 9 + PartSource.Data/Models/Fitment.cs | 4 +- PartSource.Data/Models/Submodel.cs | 8 +- PartSource.Data/Models/VehicleData.cs | 17 +- PartSource.Data/Models/VehicleMake.cs | 2 +- PartSource.Data/Models/VehicleModel.cs | 7 +- PartSource.Data/PartSourceContext.cs | 16 +- .../Extensions/IQueryableExtensions.cs | 83 ++ PartSource.Services/VehicleService.cs | 159 +++- 28 files changed, 1292 insertions(+), 1001 deletions(-) create mode 100644 PartSource.Api/.config/dotnet-tools.json create mode 100644 PartSource.Api/Controllers/BaseApiController.cs create mode 100644 PartSource.Api/Controllers/LegacyVehiclesController.cs create mode 100644 PartSource.Automation/Jobs/AddAndUpdateProducts.cs delete mode 100644 PartSource.Automation/Jobs/AddProducts.cs create mode 100644 PartSource.Data/Dtos/EngineDto.cs create mode 100644 PartSource.Data/Dtos/SubmodelDto.cs create mode 100644 PartSource.Services/Extensions/IQueryableExtensions.cs diff --git a/PartSource.Api/.config/dotnet-tools.json b/PartSource.Api/.config/dotnet-tools.json new file mode 100644 index 0000000..4947a30 --- /dev/null +++ b/PartSource.Api/.config/dotnet-tools.json @@ -0,0 +1,12 @@ +{ + "version": 1, + "isRoot": true, + "tools": { + "dotnet-ef": { + "version": "3.1.6", + "commands": [ + "dotnet-ef" + ] + } + } +} \ No newline at end of file diff --git a/PartSource.Api/Controllers/BaseApiController.cs b/PartSource.Api/Controllers/BaseApiController.cs new file mode 100644 index 0000000..e6be382 --- /dev/null +++ b/PartSource.Api/Controllers/BaseApiController.cs @@ -0,0 +1,35 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; + +namespace PartSource.Api.Controllers +{ + public class BaseApiController : ControllerBase + { + public ActionResult ApiResponse(T response) + { + switch (response) + { + case IList list: + if (list.Count == 0) + { + return NoContent(); + } + break; + + default: + if (response == null) + { + return NotFound(); + } + break; + } + + return Ok(response); + } + } +} \ No newline at end of file diff --git a/PartSource.Api/Controllers/LegacyVehiclesController.cs b/PartSource.Api/Controllers/LegacyVehiclesController.cs new file mode 100644 index 0000000..6bbfd28 --- /dev/null +++ b/PartSource.Api/Controllers/LegacyVehiclesController.cs @@ -0,0 +1,152 @@ +using Microsoft.AspNetCore.Mvc; +using PartSource.Data.Models; +using PartSource.Services; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net; +using System.Threading.Tasks; + +using NexpartMake = PartSource.Data.Nexpart.Make; +using NexpartModel = PartSource.Data.Nexpart.Model; +using NexpartEngine = PartSource.Data.Nexpart.Engine; +using NexpartSubmodel = PartSource.Data.Nexpart.SubModel; + +namespace PartSource.Api.Controllers +{ + /// + /// This controller exists to enable legacy support for the old Nexpart-based vehicle lookup. + /// + [Obsolete] + [Route("vehicles")] + [ApiController] + public class LegacyVehiclesController : BaseNexpartController + { + private readonly VehicleService _vehicleService; + + public LegacyVehiclesController(VehicleService vehicleService) + { + _vehicleService = vehicleService; + } + + [HttpGet] + [Route("makes")] + public async Task GetMakes() + { + IList vehicleMakes = await _vehicleService.GetMakes(); + IList nexpartMakes = new List(); + + foreach (VehicleMake make in vehicleMakes) + { + nexpartMakes.Add(new NexpartMake + { + Id = make.MakeId, + Value = make.Name.Trim() + }); + } + + return Ok(new { data = new { make = nexpartMakes } }); + } + + [HttpGet] + [Route("models/makeid/{makeId}/modelyear/{year}")] + public async Task GetModels(int makeId, int year) + { + IList vehicleModels = await _vehicleService.GetModels(makeId, year); + IList nexpartModels = new List(); + + foreach (VehicleModel model in vehicleModels) + { + nexpartModels.Add(new NexpartModel + { + Id = model.ModelId, + Value = model.Name.Trim() + }); + } + + return Ok(new { data = new[] { new { model = nexpartModels } } }); + } + + [HttpGet] + [Route("basevehicle/makeid/{makeId}/modelid/{modelId}/modelyear/{year}")] + [Route("basevehicles/makeid/{makeId}/modelid/{modelId}/modelyear/{year}")] + public async Task GetBaseVehicle(int makeId, int modelId, int year) + { + BaseVehicle baseVehicle = await _vehicleService.GetBaseVehicle(makeId, modelId, year); + + return Ok(new { data = baseVehicle }); + } + + [HttpGet] + [Route("engines/basevehicleid/{baseVehicleId}")] + [Route("engines/basevehicleid/{baseVehicleId}/submodelid/{subModelId}")] + public async Task GetEngines(int baseVehicleId, int? submodelId = null) + { + IList nexpartEngines = new List(); + IList engines = submodelId == null + ? await _vehicleService.GetEngines(baseVehicleId) + : await _vehicleService.GetEngines(baseVehicleId, (int)submodelId); + + foreach(Engine engine in engines) + { + nexpartEngines.Add(new NexpartEngine + { + Id = engine.EngineConfigId, + Value = engine.Description.Trim() + }); + } + + return Ok(new { data = new { engine = nexpartEngines } }); + } + + [HttpGet] + [Route("trim/makeid/{makeId}/modelid/{modelId}/modelyear/{year}")] + [Route("submodels/makeid/{makeId}/modelid/{modelId}/modelyear/{year}")] + public async Task GetSubmodels(int makeId, int modelId, int year) + { + IList submodels = await _vehicleService.GetSubmodels(makeId, modelId, year); + IList nexpartSubmodels = new List(); + + foreach (Submodel submodel in submodels) + { + nexpartSubmodels.Add(new NexpartSubmodel + { + Id = submodel.SubmodelId.ToString(), + Description = submodel.Name.Trim() + }); + } + + return Ok(new { data = new { subModel = submodels } }); + } + + [HttpGet] + [Route("detail/basevehicleid/{baseVehicleId}/submodelid/{submodelId}/engineconfigid/{engineConfigId}")] + public async Task GetVehicleDetail(int baseVehicleId, int submodelId, int engineConfigId) + { + Vehicle vehicle = await _vehicleService.GetVehicle(baseVehicleId, engineConfigId, submodelId); + + return Ok(new { data = vehicle }); + } + + [HttpGet] + [Route("types")] + public ActionResult GetVehicleTypes() + { + return new StatusCodeResult((int)HttpStatusCode.Gone); + } + + [HttpGet] + [Route("makes/vehicletypeid/{vehicleTypeId}")] + public ActionResult GetMakes(int vehicleTypeId) + { + return new StatusCodeResult((int)HttpStatusCode.Gone); + } + + [HttpGet] + [Route("models/makeid/{makeId}/modelyear/{year}/vehicletypeid/{vehicleTypeId}")] + public ActionResult GetModels(int makeId, int year, int vehicleTypeId) + { + return new StatusCodeResult((int)HttpStatusCode.Gone); + } + } +} diff --git a/PartSource.Api/Controllers/VehiclesController.cs b/PartSource.Api/Controllers/VehiclesController.cs index 0307ed4..a17de05 100644 --- a/PartSource.Api/Controllers/VehiclesController.cs +++ b/PartSource.Api/Controllers/VehiclesController.cs @@ -1,101 +1,132 @@ using Microsoft.AspNetCore.Mvc; +using Microsoft.EntityFrameworkCore.Metadata.Internal; +using PartSource.Data.Dtos; using PartSource.Data.Models; using PartSource.Services; using System.Collections.Generic; +using System.Linq; using System.Net; using System.Threading.Tasks; namespace PartSource.Api.Controllers { - [Route("[controller]")] - [ApiController] - public class VehiclesController : BaseNexpartController - { - private readonly VehicleService _vehicleService; + [Route("v2/[controller]")] + [ApiController] + public class VehiclesController : BaseApiController + { + private readonly VehicleService _vehicleService; - public VehiclesController(VehicleService vehicleService) - { - this._vehicleService = vehicleService; - } + public VehiclesController(VehicleService vehicleService) + { + _vehicleService = vehicleService; + } - [HttpGet] - [Route("makes")] - public async Task GetMakes() - { - IList makes = await _vehicleService.GetAllMakes(); + [HttpGet] + [Route("")] + public async Task GetVehicles([FromQuery] Vehicle vehicleQuery) + { + IList vehicles = await _vehicleService.GetVehicles(vehicleQuery); - return Ok(makes); - } + return ApiResponse(vehicles); + } - [HttpGet] - [Route("models/makeid/{makeId}/modelyear/{year}")] - public async Task GetModels(int makeId, int year) - { - IList models = await _vehicleService.GetModels(makeId, year); + [HttpGet] + [Route("{id}")] + public async Task GetVehicleById(int id) + { + Vehicle vehicle = await _vehicleService.GetVehicleById(id); - return Ok(models); - } + return ApiResponse(vehicle); + } - [HttpGet] - [Route("basevehicle/makeid/{makeId}/modelid/{modelId}/modelyear/{year}")] - [Route("basevehicles/makeid/{makeId}/modelid/{modelId}/modelyear/{year}")] - public async Task GetBaseVehicle(int makeId, int modelId, int year) - { - IList baseVehicles = await _vehicleService.GetBaseVehicles(makeId, modelId, year); + [HttpGet] + [Route("makes")] + public async Task GetMakes([FromQuery] VehicleMake vehicleMake) + { + IList makes = await _vehicleService.GetMakes(vehicleMake); - return Ok(baseVehicles); - } + return ApiResponse(makes); + } - [HttpGet] - [Route("engines/basevehicleid/{baseVehicleId}")] - [Route("engines/basevehicleid/{baseVehicleId}/submodelid/{subModelId}")] - public async Task GetEngines(int baseVehicleId, int? submodelId = null) - { - IList engines = submodelId == null - ? await _vehicleService.GetEngines(baseVehicleId) - : await _vehicleService.GetEngines(baseVehicleId, (int)submodelId); + [HttpGet] + [Route("makes/{id}")] + public async Task GetMakeById(int id) + { + VehicleMake make = await _vehicleService.GetMakeById(id); - return Ok(engines); - } + return ApiResponse(make); + } - [HttpGet] - [Route("trim/makeid/{makeId}/modelid/{modelId}/modelyear/{year}")] - [Route("submodels/makeid/{makeId}/modelid/{modelId}/modelyear/{year}")] - public async Task GetSubmodels(int makeId, int modelId, int year) - { - IList submodels = await _vehicleService.GetSubmodels(makeId, modelId, year); + [HttpGet] + [Route("models")] + public async Task GetModels([FromQuery] VehicleModel vehicleModel) + { + IList models = await _vehicleService.GetModels(vehicleModel); - return Ok(submodels); - } + return ApiResponse(models); + } - [HttpGet] - [Route("/detail/basevehicleid/{baseVehicleId}/submodelid/{submodelId}/engineconfigid/{engineConfigId}")] - public async Task GetVehicleDetail(int baseVehicleId, int submodelId, int engineConfigId) - { - VehicleData vehicle = await _vehicleService.GetVehicle(baseVehicleId, engineConfigId, submodelId); + [HttpGet] + [Route("models/{id}")] + public async Task GetModelById(int id) + { + VehicleModel model = await _vehicleService.GetModelById(id); - return Ok(vehicle); - } + return ApiResponse(model); + } - [HttpGet] - [Route("types")] - public ActionResult GetVehicleTypes() - { - return new StatusCodeResult((int)HttpStatusCode.Gone); - } + [HttpGet] + [Route("basevehicles")] + public async Task GetBaseVehicles([FromQuery] BaseVehicle baseVehicle) + { + IList baseVehicles = await _vehicleService.GetBaseVehicles(baseVehicle); - [HttpGet] - [Route("makes/vehicletypeid/{vehicleTypeId}")] - public ActionResult GetMakes(int vehicleTypeId) - { - return new StatusCodeResult((int)HttpStatusCode.Gone); - } + return ApiResponse(baseVehicles); + } - [HttpGet] - [Route("models/makeid/{makeId}/modelyear/{year}/vehicletypeid/{vehicleTypeId}")] - public ActionResult GetModels(int makeId, int year, int vehicleTypeId) - { - return new StatusCodeResult((int)HttpStatusCode.Gone); - } - } + [HttpGet] + [Route("basevehicles/{id}")] + public async Task GetBaseVehicleById(int id) + { + BaseVehicle baseVehicle = await _vehicleService.GetBaseVehicleById(id); + + return ApiResponse(baseVehicle); + } + + [HttpGet] + [Route("engines")] + public async Task GetEngines([FromQuery] Engine engine) + { + IList engines = await _vehicleService.GetEngines(engine); + + return ApiResponse(engines); + } + + [HttpGet] + [Route("engines/{id}")] + public async Task GetEngineById(int id) + { + EngineDto engine = await _vehicleService.GetEngineById(id); + + return ApiResponse(engine); + } + + [HttpGet] + [Route("submodels")] + public async Task GetSubmodels([FromQuery] Submodel submodelQuery) + { + IList submodels = await _vehicleService.GetSubmodels(submodelQuery); + + return ApiResponse(submodels); + } + + [HttpGet] + [Route("submodels/{id}")] + public async Task GetSubmodels(int id) + { + SubmodelDto submodel = await _vehicleService.GetSubmodelById(id); + + return ApiResponse(submodel); + } + } } diff --git a/PartSource.Api/PartSource.Api.csproj b/PartSource.Api/PartSource.Api.csproj index 2f70119..7e08a9e 100644 --- a/PartSource.Api/PartSource.Api.csproj +++ b/PartSource.Api/PartSource.Api.csproj @@ -23,6 +23,7 @@ + diff --git a/PartSource.Api/Startup.cs b/PartSource.Api/Startup.cs index 6ea5bd1..00f7484 100644 --- a/PartSource.Api/Startup.cs +++ b/PartSource.Api/Startup.cs @@ -24,11 +24,13 @@ namespace PartSource.Api services.AddMvc(options => { options.OutputFormatters.Add(new LiquidTemplateOutputFormatter()); + options.EnableEndpointRouting = false; }); services.AddTransient(); services.AddTransient(); services.AddTransient(); + services.AddTransient(); services.AddCors(o => o.AddPolicy("Default", builder => { @@ -45,10 +47,10 @@ namespace PartSource.Api // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. public void Configure(IApplicationBuilder app, IHostingEnvironment env) { - //if (env.IsDevelopment()) - //{ - // app.UseDeveloperExceptionPage(); - //} + if (env.IsDevelopment()) + { + app.UseDeveloperExceptionPage(); + } //else //{ // app.UseHsts(); @@ -56,7 +58,7 @@ namespace PartSource.Api app.UseCors("Default"); - app.UseExceptionHandler("/Error"); + // app.UseExceptionHandler("/Error"); // app.UseHttpsRedirection(); app.UseMvc(); } diff --git a/PartSource.Api/appsettings.development.json b/PartSource.Api/appsettings.development.json index 307ae89..856dd81 100644 --- a/PartSource.Api/appsettings.development.json +++ b/PartSource.Api/appsettings.development.json @@ -1,6 +1,6 @@ { - "ConnectionStrings": { - "PartSourceDatabase": "Server=(localdb)\\mssqllocaldb;Database=PartSource;Trusted_Connection=True;" - } + "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;" + } } diff --git a/PartSource.Automation/Factories/JobFactory.cs b/PartSource.Automation/Factories/JobFactory.cs index 77c7851..11428f1 100644 --- a/PartSource.Automation/Factories/JobFactory.cs +++ b/PartSource.Automation/Factories/JobFactory.cs @@ -23,8 +23,8 @@ namespace PartSource.Automation.Factories { switch (jobName) { - case nameof(AddProducts): - return _serviceProvider.GetService(); + case nameof(AddAndUpdateProducts): + return _serviceProvider.GetService(); case nameof(DeleteProducts): return _serviceProvider.GetService(); diff --git a/PartSource.Automation/Jobs/AddAndUpdateProducts.cs b/PartSource.Automation/Jobs/AddAndUpdateProducts.cs new file mode 100644 index 0000000..190b7e3 --- /dev/null +++ b/PartSource.Automation/Jobs/AddAndUpdateProducts.cs @@ -0,0 +1,320 @@ +using Microsoft.EntityFrameworkCore; +using PartSource.Automation.Jobs.Interfaces; +using PartSource.Automation.Models; +using PartSource.Data; +using PartSource.Data.Models; +using PartSource.Services.Integrations; +using Ratermania.Shopify.Entities; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace PartSource.Automation.Jobs +{ + public class AddAndUpdateProducts : IAutomationJob + { + private readonly PartSourceContext _partSourceContext; + private readonly ShopifyClient _shopifyClient; + + public AddAndUpdateProducts(PartSourceContext partSourceContext, ShopifyClient shopifyClient) + { + _partSourceContext = partSourceContext; + _shopifyClient = shopifyClient; + } + + + public async Task Run() + { + //await SyncronizeIdsAndSkus(); + //await AddSkus(); + await AddVariants(); + + return new AutomationJobResult + { + IsSuccess = true + }; + } + + /// + /// Ensures syncronization between Shopify IDs and Partsource SKUs + /// + private async Task SyncronizeIdsAndSkus() + { + IEnumerable products = await _shopifyClient.Products.Get(); + + _partSourceContext.Database.ExecuteSqlCommand("UPDATE ImportData SET ShopifyId = NULL"); + + while (products != null && products.Any()) + { + foreach (Product product in products) + { + foreach (ProductVariant variant in product.Variants) + { + ImportData importData = _partSourceContext.ImportData.FirstOrDefault(i => i.VariantSku == variant.Sku); + + if (importData != null) + { + importData.ShopifyId = product.Id; + } + } + } + + await _partSourceContext.SaveChangesAsync(); + + try + { + products = await _shopifyClient.Products.GetNext(); + } + + catch + { + products = await _shopifyClient.Products.GetPrevious(); + } + } + } + + + public async Task AddSkus() + { + IList items = _partSourceContext.ImportData + .Where(i => i.IsVariant == null && i.ShopifyId == null) + // .OrderBy(i => i.Title) + .ToList(); + + // items = items.Where(i => i.Title == items.First().Title).ToList(); + // + foreach (ImportData importData in items) + { + try + { + // Images + IList productImages = new List(); + + if (!string.IsNullOrEmpty(importData.ImageSrc)) + { + foreach (string src in importData?.ImageSrc.Split(',')) + { + productImages.Add(new ProductImage + { + Src = src, + Alt = importData.ImageAltText + }); + } + + if (productImages.Count > 0) + { + productImages.Add(new ProductImage + { + Src = "https://cdn.shopify.com/s/files/1/2239/4255/files/No_Image_Found.jpg", + Alt = "No Image Found" + }); + } + } + + // Product Tags + List productTags = new List + { + items[0].LineCode, + items[0].PartNumber, + }; + + List productVariants = new List(); + + //foreach (ImportData itemVariant in items) + //{ + productVariants.Add(new ProductVariant + { + InventoryPolicy = "Deny", + CompareAtPrice = importData.CompareAt, + Price = importData.Price, + Sku = importData.VariantSku, + Title = importData.VariantTitle ?? importData.Title, + Option1 = importData.VariantTitle, + RequiresShipping = false, + }); + //} + + + + Product requestData = new Product + { + BodyHtml = importData.BodyHtml, + Title = importData.Title, + Vendor = importData.Vendor, + Tags = string.Join(",", productTags), + Published = true, + //ProductType = importData.FINELINE_NM, + Images = productImages.ToArray(), + Variants = productVariants.ToArray(), + CreatedAt = DateTime.Now, + UpdatedAt = DateTime.Now + }; + + requestData = await _shopifyClient.Products.Add(requestData); + + if (requestData.Id > 0) + { + //foreach (ImportData variant in items) + //{ + // variant.ShopifyId = requestData.Id; + //} + + importData.ShopifyId = requestData.Id; + _partSourceContext.SaveChanges(); + + + Console.WriteLine($"{importData.VariantSku}"); + } + + else + { + Console.WriteLine($"SHOPIFY ID WAS 0 - {importData.VariantSku}"); + } + } + + catch (Exception ex) + { + Console.WriteLine($"Failed to add SKU {importData.VariantSku}: {ex.StackTrace}"); + } + + //items = _partSourceContext.ImportData + // .Where(i => i.Title == _partSourceContext.ImportData.First(d => d.ShopifyId == null).Title) + // .ToList(); + } + } + + public async Task AddVariants() + { + IList items = _partSourceContext.ImportData + .Where(i => i.IsVariant.Value && i.ShopifyId == null) + .OrderBy(i => i.Title) + .ToList(); + + items = items.Where(i => i.Title == items.First().Title).ToList(); + + while (items != null && items.Count > 0) + { + // Images + IList productImages = new List(); + + if (!string.IsNullOrEmpty(items[0].ImageSrc)) + { + productImages = items.SelectMany(v => + { + IList images = new List(); + + foreach (string src in v.ImageSrc?.Split(',')) + { + images.Add(new ProductImage + { + Src = src, + Alt = v.ImageAltText + }); + } + + return images; + }).ToList(); + + if (productImages.Count > 0) + { + productImages.Add(new ProductImage + { + Src = "https://cdn.shopify.com/s/files/1/2239/4255/files/No_Image_Found.jpg", + Alt = "No Image Found" + }); + } + } + + + // Product Tags + List productTags = new List + { + items[0].LineCode, + items[0].PartNumber, + }; + + List productVariants = new List(); + + foreach (ImportData itemVariant in items) + { + productVariants.Add(new ProductVariant + { + InventoryPolicy = "Deny", + CompareAtPrice = itemVariant.CompareAt, + Price = itemVariant.Price, + Sku = itemVariant.VariantSku, + Title = itemVariant.VariantTitle, + Option1 = itemVariant.VariantTitle, + RequiresShipping = false, + }); + } + + + Product requestData = new Product + { + BodyHtml = items[0].BodyHtml, + Title = items[0].Title, + Vendor = items[0].Vendor, + Tags = string.Join(",", productTags), + Published = true, + //ProductType = importData.FINELINE_NM, + Images = productImages.ToArray(), + Variants = productVariants.ToArray(), + CreatedAt = DateTime.Now, + UpdatedAt = DateTime.Now + }; + + requestData = await _shopifyClient.Products.Add(requestData); + + if (requestData.Id > 0) + { + foreach (ImportData variant in items) + { + variant.ShopifyId = requestData.Id; + } + + _partSourceContext.SaveChanges(); + + Console.WriteLine($"{items[0].VariantSku}"); + } + + else + { + Console.WriteLine($"SHOPIFY ID WAS 0 - {items[0].VariantSku}"); + } + + ImportData next = _partSourceContext.ImportData.FirstOrDefault(i => i.IsVariant != null && i.ShopifyId == null); + + if (next != null) + { + items = _partSourceContext.ImportData + .Where(i => i.Title == next.Title) + .ToList(); + } + + else + { + items = null; + } + } + } + } + + //private void Log(string message) + //{ + // try + // { + // using (FileStream fileStream = File.OpenWrite(@"C:\users\tommy\desktop\log.txt")) + // { + // fileStream.Write(Encoding.UTF8.GetBytes(message + "\n")); + // } + // } + + // catch + // { + // // LOL Fix this + // Log(message); + // } + //} +} diff --git a/PartSource.Automation/Jobs/AddProducts.cs b/PartSource.Automation/Jobs/AddProducts.cs deleted file mode 100644 index 94bbce6..0000000 --- a/PartSource.Automation/Jobs/AddProducts.cs +++ /dev/null @@ -1,152 +0,0 @@ -using PartSource.Automation.Jobs.Interfaces; -using PartSource.Automation.Models; -using PartSource.Data; -using PartSource.Data.Models; -using PartSource.Services.Integrations; -using Ratermania.Shopify.Entities; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; - -namespace PartSource.Automation.Jobs -{ - public class AddProducts : IAutomationJob - { - private readonly PartSourceContext _partSourceContext; - private readonly ShopifyClient _shopifyClient; - - public AddProducts(PartSourceContext partSourceContext, ShopifyClient shopifyClient) - { - _partSourceContext = partSourceContext; - _shopifyClient = shopifyClient; - } - - - public async Task Run() - { - await AddSkus(); - - return new AutomationJobResult - { - IsSuccess = true - }; - } - - public async Task AddSkus() - { - IList items = _partSourceContext.ImportData - .Where(i => i.IsVariant.Value) - .OrderBy(i => i.Title) - .ToList(); - - items = items.Where(i => i.Title == items.First().Title).ToList(); - - while (items != null && items.Count > 0) - { - // Images - IList productImages = items.SelectMany(v => { - IList images = new List(); - - foreach (string src in v.ImageSrc?.Split(',')) - { - images.Add(new ProductImage - { - Src = src, - Alt = v.ImageAltText - }); - } - - return images; - }).ToList(); - - if (productImages.Count > 0) - { - productImages.Add(new ProductImage - { - Src = "https://cdn.shopify.com/s/files/1/2239/4255/files/No_Image_Found.jpg", - Alt = "No Image Found" - }); - } - - // Product Tags - List productTags = new List - { - items[0].LineCode, - items[0].PartNumber, - }; - - List productVariants = new List(); - - foreach (ImportData itemVariant in items) - { - productVariants.Add(new ProductVariant - { - InventoryPolicy = "Deny", - CompareAtPrice = itemVariant.CompareAt, - Price = itemVariant.Price, - Sku = itemVariant.VariantSku, - Title = itemVariant.VariantTitle, - Option1 = itemVariant.VariantTitle, - RequiresShipping = false, - }); - } - - - Product requestData = new Product - { - BodyHtml = items[0].BodyHtml, - Title = items[0].Title, - Vendor = items[0].Vendor, - Tags = string.Join(",", productTags), - Published = true, - //ProductType = importData.FINELINE_NM, - Images = productImages.ToArray(), - Variants = productVariants.ToArray(), - CreatedAt = DateTime.Now, - UpdatedAt = DateTime.Now - }; - - requestData = await _shopifyClient.Products.Add(requestData); - - if (requestData.Id > 0) - { - foreach (ImportData variant in items) - { - variant.ShopifyId = requestData.Id; - } - - _partSourceContext.SaveChanges(); - - Console.WriteLine($"{items[0].VariantSku}"); - } - - else - { - Console.WriteLine($"SHOPIFY ID WAS 0 - {items[0].VariantSku}"); - } - - items = _partSourceContext.ImportData - .Where(i => i.Title == _partSourceContext.ImportData.First(d => d.ShopifyId == null).Title) - .ToList(); - } - } - } - - //private void Log(string message) - //{ - // try - // { - // using (FileStream fileStream = File.OpenWrite(@"C:\users\tommy\desktop\log.txt")) - // { - // fileStream.Write(Encoding.UTF8.GetBytes(message + "\n")); - // } - // } - - // catch - // { - // // LOL Fix this - // Log(message); - // } - //} -} diff --git a/PartSource.Automation/Jobs/UpdateFitment - Copy.cs b/PartSource.Automation/Jobs/UpdateFitment - Copy.cs index 960bcff..7394b1d 100644 --- a/PartSource.Automation/Jobs/UpdateFitment - Copy.cs +++ b/PartSource.Automation/Jobs/UpdateFitment - Copy.cs @@ -1,535 +1,192 @@ -//using Microsoft.EntityFrameworkCore; -//using PartSource.Automation.Jobs.Interfaces; -//using PartSource.Automation.Services; -//using PartSource.Data; -//using PartSource.Data.Models; -//using PartSource.Data.Nexpart; -//using PartSource.Data.Shopify; -//using PartSource.Services; -//using System; -//using System.Collections.Concurrent; -//using System.Collections.Generic; -//using System.Data; -//using System.Data.SqlClient; -//using System.IO; -//using System.Linq; -//using System.Text; -//using System.Text.RegularExpressions; -//using System.Threading.Tasks; - -//namespace PartSource.Automation.Jobs -//{ -// public class UpdateFitmentCopy : AddProducts, IAutomationJob -// { -// private readonly IServiceProvider _serviceProvider; -// private readonly SuperOldShopifyService _shopifyService; -// private readonly PartSourceContext _partSourceContext; -// private readonly NexpartService _nexpartService; - - -// private ConcurrentQueue _shopifyIdQueue; -// private string _connectionString = "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=3600;"; - -// private readonly int _threadCount = 1; - -// public UpdateFitmentCopy(IServiceProvider serviceProvider, PartSourceContext partSourceContext, SuperOldShopifyService shopifyService, NexpartService nexpartService) : base(serviceProvider, partSourceContext, nexpartService, shopifyService) -// { -// _serviceProvider = serviceProvider; -// _nexpartService = nexpartService; -// _shopifyService = shopifyService; -// _partSourceContext = partSourceContext; - -// } - -// new public void Run() -// { -// Console.WriteLine(""); - - -// UpdateMetafields(26); - - - - -// //UpdatePublished(); - - -// //FitmentReport(); - -// // List shopifyIds = _partSourceContext.ImportData.Where(s => s.IsFitment.Value && s.ShopifyId != null).Select(s => (long)s.ShopifyId).ToList(); -// //List shopifyIds = _partSourceContext.ImportData.Where(s => s.ShopifyId != null).Select(s => (long)s.ShopifyId).ToList(); - -// //_shopifyIdQueue = new ConcurrentQueue(shopifyIds); - -// //Parallel.For(0, _threadCount, i => -// // { - - -// // //Categorize(); -// // }); -// // }); -// } - - -// private IList GetYmmFitmentTags(BuyersGuideSearchResponse response) -// { -// BuyersGuideMake[] makes = response?.ResponseBody?.Apps?.Make; -// if (makes == null) -// { -// return new List(); -// } - -// IList fitmentTags = new List(); - -// foreach (BuyersGuideMake make in makes) -// { -// foreach (BuyersGuideModel model in make.Model) -// { -// IList years = new List(); -// for (int year = model.FromYear; year <= model.ToYear; year++) -// { -// years.Add(year); -// } - -// string tag = $"{string.Join('-', years)} {make.Name} {model.Name}"; - -// fitmentTags.Add(tag); -// } -// } - -// return fitmentTags; -// } - -// //private IList GetVehicleIdFitmentTags(BuyersGuideSearchResponse response) -// //{ -// // BuyersGuideMake[] makes = response?.ResponseBody?.Apps?.Make; -// // if (makes == null) -// // { -// // return new List(); -// // } - -// // IList fitmentTags = new List(); - -// // foreach (BuyersGuideMake make in makes) -// // { -// // foreach (BuyersGuideModel model in make.Model) -// // { -// // foreach (BuyersGuideEngine engine in model.Engine) -// // { -// // IList vehicleIds = _partSourceContext.VehicleData.Where(d => -// // d.EngineDescription == engine.Desc -// // && d.Year == engine.Year -// // && d.MakeName == make.Name -// // && d.ModelName == model.Name -// // ) -// // .Select(d => d.VehicleToEngineConfigId) -// // .ToList(); - -// // foreach (int id in vehicleIds) -// // { -// // string tag = $"v{id}"; - -// // fitmentTags.Add(tag); -// // } -// // } -// // } -// // } - -// // return fitmentTags; -// //} - -// /* public void UpdateFitmentViaBuyersGuideSearch() -// { -// int i = 0; -// IList products = _shopifyService.GetManyProducts(250, i).Result; - -// while (products.Count > 0) -// { -// foreach (Product product in products) -// { -// try -// { -// //if (product.Tags.Contains("-v") || product.Tags.ToLowerInvariant().Contains("zzzisfitment=false")) -// //{ -// // continue; -// //} - -// ImportData importData = _partSourceContext.ImportData.FirstOrDefault(p => p.ShopifyId == product.Id); -// if (importData == null || !importData.IsFitment.Value) -// { -// continue; -// } - -// importData.DcfMappings = _partSourceContext.DcfMappings.Where(d => d.LineCode == importData.LineCode).ToList(); - -// BuyersGuideSearch buyersGuideSearch = new BuyersGuideSearch(); -// List ymmFitmentTags = new List(); -// List vehicleIdFitmentTags = new List(); - -// foreach (DcfMapping mapping in importData.DcfMappings) -// { -// buyersGuideSearch = new BuyersGuideSearch -// { -// Part = new BuyersGuidePart -// { -// PartNumber = importData.PartNumber, -// MfrCode = mapping.WhiCode -// } -// }; - -// BuyersGuideSearchResponse response = _nexpartService.SendRequest(buyersGuideSearch).Result; - -// if (response.ResponseBody != null) -// { -// ymmFitmentTags.AddRange(GetYmmFitmentTags(response)); -// //vehicleIdFitmentTags.AddRange(GetVehicleIdFitmentTags(response)); -// } -// } - -// bool published = true; -// List productTags = new List -// { -// importData.LineCode, -// importData.PartNumber -// }; - -// published = (ymmFitmentTags.Count > 0 || vehicleIdFitmentTags.Count > 0); - -// productTags.Add($"zzzisFitment={importData.IsFitment}"); -// productTags.AddRange(vehicleIdFitmentTags); -// productTags.AddRange(ymmFitmentTags); - - -// if (productTags.Count > 249) -// { -// string message = $"Truncating {importData.VariantSku} - {productTags.Count} product tags"; - -// // Console.WriteLine(message); - -// productTags = productTags.Take(249).ToList(); -// } - -// published = (ymmFitmentTags.Count > 0 || vehicleIdFitmentTags.Count > 0); - - -// product.Tags = string.Join(",", productTags); -// product.PublishedAt = published ? (DateTime?)DateTime.Now : null; - -// bool updateResult = _shopifyService.UpdateProduct(product).Result; - -// if (updateResult) -// { -// if (published) -// { -// Console.WriteLine($"{product.Id}"); -// } -// } - -// else -// { -// Console.WriteLine($"Failed to update product {product.Id}"); -// } -// } - -// catch (Exception ex) -// { -// Console.WriteLine($"{ex.Message}"); -// } -// } - -// i++; -// products = _shopifyService.GetManyProducts(250, i).Result; -// } - -// } */ - -// /* private void UpdatePublished() -// { -// DbContextOptionsBuilder optionsBuilder = new DbContextOptionsBuilder(); -// optionsBuilder.UseSqlServer(_connectionString); - -// PartSourceContext threadDbContext = new PartSourceContext(optionsBuilder.Options); - -// int i = 0; -// int updated = 0; -// IList products = _shopifyService.GetManyProducts(250, i).Result; - -// while (products.Count > 0) -// { -// foreach (Product product in products) -// { -// try -// { -// ImportData importData = threadDbContext.ImportData.FirstOrDefault(p => p.ShopifyId == product.Id); - -// if (importData == null || !importData.IsFitment.Value) -// { -// continue; -// } - -// if (product.PublishedAt == null) -// { -// if (product.Tags.Contains("-v")) -// { -// IList tags = product.Tags.Split(','); - -// string fitmentTag = tags.Where(t => t.ToLowerInvariant().Contains("zzzisfitment")).FirstOrDefault(); -// tags.Remove(fitmentTag); -// tags.Add("zzzisFitment=True"); - -// product.Tags = string.Join(',', tags); -// product.PublishedAt = DateTime.Now; - -// bool result = _shopifyService.UpdateProduct(product).Result; - -// updated++; -// } -// } - -// } - -// catch (Exception ex) -// { -// continue; -// } -// } - -// i++; -// products = _shopifyService.GetManyProducts(250, i).Result; - -// Console.Write($"\ri={i}"); -// } -// } */ - -// private void FitmentReport() -// { -// IList importCache = _partSourceContext.ImportData.Where(s => s.IsFitment.Value && s.ShopifyId != null).ToList(); -// IList mappingCache = _partSourceContext.DcfMappings.ToList(); - -// Regex regex = new Regex("v[0-9]{6}"); - -// using (StreamWriter writer = File.AppendText("c:\\users\\tommy\\desktop\\fitment report.csv")) -// { - -// writer.WriteLine("Line Code,Part Number,WHI Match"); - -// int i = 0; -// IList products = _shopifyService.GetManyProducts(250, i).Result; - - -// while (products.Count > 0) -// { -// try -// { -// foreach (Product product in products) -// { -// ImportData importData = importCache.Join( -// mappingCache, -// d => d.LineCode, -// m => m.LineCode, -// (d, m) => d -// ) -// .FirstOrDefault(p => p.ShopifyId == product.Id); - -// if (importData == null || !importData.IsFitment.Value || product.Variants.Length == 0) -// { -// continue; -// } - -// bool tagged = regex.IsMatch(product.Tags); - -// if (!tagged) -// { -// // IList whiCodes = mappingCache.Where(d => d.LineCode == importData.LineCode).Select(d => d.WhiCode).ToList(); -// writer.WriteLine($"{importData.LineCode},{importData.PartNumber},{tagged}"); -// } -// } - -// i++; -// products = _shopifyService.GetManyProducts(250, i).Result; -// } - -// catch (Exception ex) -// { -// Console.WriteLine("whoops"); -// } -// } -// } -// } - - - -// private void UpdateMetafields(int i) -// { -// DbContextOptionsBuilder optionsBuilder = new DbContextOptionsBuilder(); -// optionsBuilder.UseSqlServer(_connectionString); - -// ShopifyClient shopifyClient = new ShopifyClient(new Ratermania.Shopify.ShopifyOptionsBuilder -// { -// ShopDomain = "partsource.myshopify.com", -// ApiVersion = "2020-01", -// ApiKey = "88f931933b566ade1fc92c6a39f04b34", -// ApiSecret = "527a3b4213c2c7ecb214728a899052df" -// }); - -// PartSourceContext threadDbContext = new PartSourceContext(optionsBuilder.Options); -// threadDbContext.Database.SetCommandTimeout(1440); - -// IList products = _shopifyService.GetManyProducts(250, i).Result; - -// while (products.Count > 0) -// { -// try -// { -// foreach (Product product in products) -// { -// try -// { -// if (product.Tags.Contains("-v") || product.Tags.ToLowerInvariant().Contains("zzzisfitment=false")) -// { -// continue; -// } - -// ImportData test = threadDbContext.ImportData.First(); - -// ImportData importData = threadDbContext.ImportData.FirstOrDefault(p => p.ShopifyId == product.Id); - -// if (importData == null) -// { -// continue; -// } - -// bool published = true; -// List productTags = new List -// { -// importData.LineCode, -// importData.PartNumber -// }; - - - -// IDictionary> positions = new Dictionary>(); - -// string partNumber = Regex.Replace(importData.PartNumber, "[^a-zA-Z0-9]", string.Empty); - -// string sql = $"select distinct BaseVehicleId, EngineConfigId, LineCode, PartNumber, Position from dbo.Fitment where LineCode in (select WhiCode from DcfMapping where LineCode='{importData.LineCode}') and PartNumber = '{partNumber}'"; - -// IList fitments = _partSourceContext.Fitments.FromSql(sql).ToList(); - - -// foreach (Fitment fitment in fitments) -// { -// fitment.Position = fitment.Position.Replace("\"", string.Empty); - -// if (string.IsNullOrEmpty(fitment.Position)) -// { -// continue; -// } - -// VehicleData vehicle = _partSourceContext.VehicleData.FirstOrDefault(v => v.BaseVehicleId == fitment.BaseVehicleId && v.EngineConfigId == fitment.EngineConfigId); - -// if (vehicle == null) -// { -// continue; -// } - -// if (positions.ContainsKey(fitment.Position)) -// { -// positions[fitment.Position].Add(vehicle.VehicleToEngineConfigId.ToString()); -// } - -// else -// { -// positions.Add(fitment.Position, new List -// { -// vehicle.VehicleToEngineConfigId.ToString() -// }); -// } -// } - -// foreach (KeyValuePair> position in positions) -// { -// Metafield metafield = new Metafield -// { -// OwnerId = product.Id, -// OwnerResource = "product", -// Namespace = "partsource", -// Key = position.Key, -// Value = string.Join(',', position.Value), -// ValueType = "string" -// }; - -// var x = shopifyClient.Metafields.Add(metafield).Result; - -// Console.WriteLine(product.Id); -// } - - - -// } - -// catch (Exception ex) -// { -// Console.WriteLine($"{ex.Message}"); -// } -// } - - -// i += _threadCount; -// products = _shopifyService.GetManyProducts(250, i).Result; - -// Console.WriteLine(i); -// } - -// catch (Exception ex) -// { -// Console.WriteLine($"{ex.Message}"); -// } -// } - -// } - -// private MenuNode[] GetMenuNodes(int menuId, int numberOfLevels, int? parentMenuNodeId = null) -// { -// MenuNodesLookup request = new MenuNodesLookup -// { -// MenuId = menuId, -// NumberOfLevels = numberOfLevels, -// ParentMenuNodeId = parentMenuNodeId -// }; - -// MenuNodesLookupResponse response = _nexpartService.SendRequest(request).Result; - -// return response.ResponseBody.MenuNode; -// } - -// //private bool IsFitmentLineCode(string lineCode) -// //{ -// // string sql = $"select WhiCode from DcfMapping where PartSourceCode='{importData.LineCode}'"; - -// // using (DataTable dataTable = new DataTable()) -// // { -// // using (SqlConnection connection = new SqlConnection(_connectionString)) -// // { -// // connection.Open(); - -// // using (SqlCommand command = new SqlCommand(sql, connection)) -// // { - -// // SqlDataAdapter dataAdapter = new SqlDataAdapter(command); -// // dataAdapter.Fill(dataTable); -// // } -// // } - -// // if (dataTable.Rows.Count == 0) -// // { -// // return false; -// // } - -// // lineCode = dataTable.Rows[0]["WhiCode"].ToString(); - - -// // } -// //} -// } -//} +using Microsoft.EntityFrameworkCore; +using Newtonsoft.Json; +using PartSource.Automation.Jobs.Interfaces; +using PartSource.Automation.Models; +using PartSource.Automation.Services; +using PartSource.Data; +using PartSource.Data.Models; +using PartSource.Data.Nexpart; +using PartSource.Services; +using PartSource.Services.Integrations; +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Data; +using System.Data.SqlClient; +using System.IO; +using System.Linq; +using System.Text; +using System.Text.RegularExpressions; +using System.Threading.Tasks; +using Ratermania.Shopify.Entities; + +namespace PartSource.Automation.Jobs +{ + public class UpdateFitment : IAutomationJob + { + private readonly IServiceProvider _serviceProvider; + private readonly ShopifyClient _shopifyClient; + private readonly PartSourceContext _partSourceContext; + private readonly NexpartService _nexpartService; + + private readonly VehicleService _vehicleService; + + public UpdateFitment(IServiceProvider serviceProvider, PartSourceContext partSourceContext, ShopifyClient shopifyClient, NexpartService nexpartService, VehicleService vehicleService) + { + _partSourceContext = partSourceContext; + _shopifyClient = shopifyClient; + _vehicleService = vehicleService; + } + + public async Task Run() + { + IList parts = _partSourceContext.ImportData.Where(i => new[] { "Raybestos Brakes", "MotoMaster", "Pro Series OE Plus Brake Pads" }.Contains(i.Vendor)).ToList(); + + foreach (ImportData importData in parts) + { + try + { + Product product = await _shopifyClient.Products.GetById((long)importData.ShopifyId); + if (product == null) + { + continue; + } + + + bool isFitment = false; + + IList vehicles = _vehicleService.GetVehiclesForPart(importData.PartNumber, importData.LineCode); + 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); + + List tags = new List + { + importData.LineCode, + importData.PartNumber + }; + + for (int i = 0; i < vehicleIdFitment.Count; i += 25) + { + tags.Add(string.Join('-', vehicleIdFitment.Skip(i).Take(25).Select(i => $"v{i}"))); + } + + tags.AddRange(ymmFitment); + + if (tags.Count > 250) + { + tags = tags.Take(250).ToList(); + } + + product.Tags = string.Join(',', tags); + + await _shopifyClient.Products.Update(product); + + } + + catch (Exception ex) + { + Console.WriteLine($"{importData.VariantSku}: {ex.Message}"); + } + } + + + return new AutomationJobResult + { + IsSuccess = true + }; + } + + private async Task DeleteFitmentMetafields(long shopifyId) + { + IDictionary parameters = new Dictionary + { + { "metafield[owner_id]", shopifyId}, + { "metafield[owner_resource]", "product" }, + { "namespace", "fitment" }, + }; + + IEnumerable metafields = await _shopifyClient.Metafields.Get(parameters); + + foreach (Metafield metafield in metafields) + { + await _shopifyClient.Metafields.Delete(metafield); + } + } + + public IList GetVehicles(string partNumber, string lineCode) + { + partNumber = Regex.Replace(partNumber, "[^a-zA-Z0-9]", string.Empty); + + //string sql = $"select distinct BaseVehicleId, EngineConfigId from dbo.Fitment where ManufacturerCode in (select WhiCode from DcfMapping where PartSourceCode='{lineCode}') and (partNumber = '{partNumber}' or partNumber = '{partNumber.Replace("-", string.Empty)}')"; + string sql = $"with FitmentIds (BaseVehicleId, EngineConfigId) as (select distinct BaseVehicleId, EngineConfigId from dbo.Fitment where LineCode in (select WhiCode from DcfMapping where LineCode='{lineCode}') and PartNumber = '{partNumber}') select v.* from VehicleData v join FitmentIds f on v.BaseVehicleId = f.BaseVehicleId and v.EngineConfigId = f.EngineConfigId;"; + +#pragma warning disable EF1000 // Possible SQL injection vulnerability. + IList vehicles = _partSourceContext.Vehicles.FromSql(sql).ToList(); +#pragma warning restore EF1000 // Possible SQL injection vulnerability. + + return vehicles; + } + private void Update() + { + + } + + } +} diff --git a/PartSource.Automation/Jobs/UpdateFitment.cs b/PartSource.Automation/Jobs/UpdateFitment.cs index 1c7c93a..0cc58aa 100644 --- a/PartSource.Automation/Jobs/UpdateFitment.cs +++ b/PartSource.Automation/Jobs/UpdateFitment.cs @@ -1,200 +1,200 @@ -using Microsoft.EntityFrameworkCore; -using Newtonsoft.Json; -using PartSource.Automation.Jobs.Interfaces; -using PartSource.Automation.Models; -using PartSource.Automation.Services; -using PartSource.Data; -using PartSource.Data.Models; -using PartSource.Data.Nexpart; -using PartSource.Services; -using PartSource.Services.Integrations; -using System; -using System.Collections.Concurrent; -using System.Collections.Generic; -using System.Data; -using System.Data.SqlClient; -using System.IO; -using System.Linq; -using System.Text; -using System.Text.RegularExpressions; -using System.Threading.Tasks; -using Ratermania.Shopify.Entities; +//using Microsoft.EntityFrameworkCore; +//using Newtonsoft.Json; +//using PartSource.Automation.Jobs.Interfaces; +//using PartSource.Automation.Models; +//using PartSource.Automation.Services; +//using PartSource.Data; +//using PartSource.Data.Models; +//using PartSource.Data.Nexpart; +//using PartSource.Services; +//using PartSource.Services.Integrations; +//using System; +//using System.Collections.Concurrent; +//using System.Collections.Generic; +//using System.Data; +//using System.Data.SqlClient; +//using System.IO; +//using System.Linq; +//using System.Text; +//using System.Text.RegularExpressions; +//using System.Threading.Tasks; +//using Ratermania.Shopify.Entities; -namespace PartSource.Automation.Jobs -{ - public class UpdateFitment : IAutomationJob - { - private readonly IServiceProvider _serviceProvider; - private readonly ShopifyClient _shopifyClient; - private readonly PartSourceContext _partSourceContext; - private readonly NexpartService _nexpartService; +//namespace PartSource.Automation.Jobs +//{ +// public class UpdateFitment : IAutomationJob +// { +// private readonly IServiceProvider _serviceProvider; +// private readonly ShopifyClient _shopifyClient; +// private readonly PartSourceContext _partSourceContext; +// private readonly NexpartService _nexpartService; - private readonly VehicleService _vehicleService; +// private readonly VehicleService _vehicleService; - public UpdateFitment(IServiceProvider serviceProvider, PartSourceContext partSourceContext, ShopifyClient shopifyClient, NexpartService nexpartService, VehicleService vehicleService) - { - _partSourceContext = partSourceContext; - _shopifyClient = shopifyClient; - _vehicleService = vehicleService; - } +// public UpdateFitment(IServiceProvider serviceProvider, PartSourceContext partSourceContext, ShopifyClient shopifyClient, NexpartService nexpartService, VehicleService vehicleService) +// { +// _partSourceContext = partSourceContext; +// _shopifyClient = shopifyClient; +// _vehicleService = vehicleService; +// } - public async Task Run() - { - IEnumerable products = await _shopifyClient.Products.Get(); +// public async Task Run() +// { +// IEnumerable products = await _shopifyClient.Products.Get(); - int i = 0; +// int i = 0; - while (products != null && products.Any()) - { - foreach (Product product in products) - { - try - { - ImportData importData = _partSourceContext.ImportData.FirstOrDefault(i => i.VariantSku == product.Variants[0].Sku && i.UpdatedAt == null); - IList vehicles = _vehicleService.GetVehiclesForPart(importData?.PartNumber, importData?.LineCode); +// while (products != null && products.Any()) +// { +// foreach (Product product in products) +// { +// try +// { +// ImportData importData = _partSourceContext.ImportData.FirstOrDefault(i => i.VariantSku == product.Variants[0].Sku && i.UpdatedAt == null); +// IList vehicles = _vehicleService.GetVehiclesForPart(importData?.PartNumber, importData?.LineCode); - if (vehicles == null || vehicles.Count == 0) - { - continue; - } +// if (vehicles == null || vehicles.Count == 0) +// { +// continue; +// } - await DeleteFitmentMetafields(product.Id); +// await DeleteFitmentMetafields(product.Id); - bool isFitment = false; +// bool isFitment = false; - IList vehicleIdFitment = _vehicleService.GetVehicleIdFitment(vehicles); - if (vehicleIdFitment.Count > 0) - { - isFitment = true; +// IList vehicleIdFitment = _vehicleService.GetVehicleIdFitment(vehicles); +// if (vehicleIdFitment.Count > 0) +// { +// isFitment = true; - string json = JsonConvert.SerializeObject(vehicleIdFitment); - if (json.Length >= 100000) - { - continue; - } +// 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 - }; +// Metafield vehicleMetafield = new Metafield +// { +// Namespace = "fitment", +// Key = "ids", +// Value = json, +// ValueType = "json_string", +// OwnerResource = "product", +// OwnerId = product.Id +// }; - await _shopifyClient.Metafields.Add(vehicleMetafield); - } +// await _shopifyClient.Metafields.Add(vehicleMetafield); +// } - IList ymmFitment = _vehicleService.GetYmmFitment(vehicles); - if (ymmFitment.Count > 0) - { - isFitment = true; +// IList ymmFitment = _vehicleService.GetYmmFitment(vehicles); +// if (ymmFitment.Count > 0) +// { +// isFitment = true; - string json = JsonConvert.SerializeObject(ymmFitment); - if (json.Length >= 100000) - { - continue; - } +// 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 - }; +// Metafield ymmMetafield = new Metafield +// { +// Namespace = "fitment", +// Key = "seo", +// Value = json, +// ValueType = "json_string", +// OwnerResource = "product", +// OwnerId = product.Id +// }; - await _shopifyClient.Metafields.Add(ymmMetafield); - } +// await _shopifyClient.Metafields.Add(ymmMetafield); +// } - Metafield isFitmentMetafield = new Metafield - { - Namespace = "Flags", - Key = "IsFitment", - Value = isFitment.ToString(), - ValueType = "string", - OwnerResource = "product", - OwnerId = product.Id - }; +// Metafield isFitmentMetafield = new Metafield +// { +// Namespace = "Flags", +// Key = "IsFitment", +// Value = isFitment.ToString(), +// ValueType = "string", +// OwnerResource = "product", +// OwnerId = product.Id +// }; - await _shopifyClient.Metafields.Add(isFitmentMetafield); +// await _shopifyClient.Metafields.Add(isFitmentMetafield); - importData.UpdatedAt = DateTime.Now; - importData.UpdateType = "Fitment"; - } +// importData.UpdatedAt = DateTime.Now; +// importData.UpdateType = "Fitment"; +// } - catch (Exception ex) - { - Console.WriteLine($"{product.Id}: {ex.Message}"); - } - } +// catch (Exception ex) +// { +// Console.WriteLine($"{product.Id}: {ex.Message}"); +// } +// } - try - { - i++; - Console.WriteLine(i); +// try +// { +// i++; +// Console.WriteLine(i); - await _partSourceContext.SaveChangesAsync(); +// await _partSourceContext.SaveChangesAsync(); - products = await _shopifyClient.Products.GetNext(); - } +// products = await _shopifyClient.Products.GetNext(); +// } - catch (Exception ex) - { - i++; - Console.WriteLine(i); +// catch (Exception ex) +// { +// i++; +// Console.WriteLine(i); - Console.WriteLine($"Retrying request: {ex.Message}"); +// Console.WriteLine($"Retrying request: {ex.Message}"); - await _partSourceContext.SaveChangesAsync(); +// await _partSourceContext.SaveChangesAsync(); - products = await _shopifyClient.Products.GetNext(); - } - } +// products = await _shopifyClient.Products.GetNext(); +// } +// } - return new AutomationJobResult - { - IsSuccess = true - }; - } +// return new AutomationJobResult +// { +// IsSuccess = true +// }; +// } - private async Task DeleteFitmentMetafields(long shopifyId) - { - IDictionary parameters = new Dictionary - { - { "metafield[owner_id]", shopifyId}, - { "metafield[owner_resource]", "product" }, - { "namespace", "fitment" }, - }; +// private async Task DeleteFitmentMetafields(long shopifyId) +// { +// IDictionary parameters = new Dictionary +// { +// { "metafield[owner_id]", shopifyId}, +// { "metafield[owner_resource]", "product" }, +// { "namespace", "fitment" }, +// }; - IEnumerable metafields = await _shopifyClient.Metafields.Get(parameters); +// IEnumerable metafields = await _shopifyClient.Metafields.Get(parameters); - foreach (Metafield metafield in metafields) - { - await _shopifyClient.Metafields.Delete(metafield); - } - } +// foreach (Metafield metafield in metafields) +// { +// await _shopifyClient.Metafields.Delete(metafield); +// } +// } - public IList GetVehicles(string partNumber, string lineCode) - { - partNumber = Regex.Replace(partNumber, "[^a-zA-Z0-9]", string.Empty); +// public IList GetVehicles(string partNumber, string lineCode) +// { +// partNumber = Regex.Replace(partNumber, "[^a-zA-Z0-9]", string.Empty); - //string sql = $"select distinct BaseVehicleId, EngineConfigId from dbo.Fitment where ManufacturerCode in (select WhiCode from DcfMapping where PartSourceCode='{lineCode}') and (partNumber = '{partNumber}' or partNumber = '{partNumber.Replace("-", string.Empty)}')"; - string sql = $"with FitmentIds (BaseVehicleId, EngineConfigId) as (select distinct BaseVehicleId, EngineConfigId from dbo.Fitment where LineCode in (select WhiCode from DcfMapping where LineCode='{lineCode}') and PartNumber = '{partNumber}') select v.* from VehicleData v join FitmentIds f on v.BaseVehicleId = f.BaseVehicleId and v.EngineConfigId = f.EngineConfigId;"; +// //string sql = $"select distinct BaseVehicleId, EngineConfigId from dbo.Fitment where ManufacturerCode in (select WhiCode from DcfMapping where PartSourceCode='{lineCode}') and (partNumber = '{partNumber}' or partNumber = '{partNumber.Replace("-", string.Empty)}')"; +// string sql = $"with FitmentIds (BaseVehicleId, EngineConfigId) as (select distinct BaseVehicleId, EngineConfigId from dbo.Fitment where LineCode in (select WhiCode from DcfMapping where LineCode='{lineCode}') and PartNumber = '{partNumber}') select v.* from VehicleData v join FitmentIds f on v.BaseVehicleId = f.BaseVehicleId and v.EngineConfigId = f.EngineConfigId;"; -#pragma warning disable EF1000 // Possible SQL injection vulnerability. - IList vehicles = _partSourceContext.VehicleData.FromSql(sql).ToList(); -#pragma warning restore EF1000 // Possible SQL injection vulnerability. +//#pragma warning disable EF1000 // Possible SQL injection vulnerability. +// IList vehicles = _partSourceContext.VehicleData.FromSql(sql).ToList(); +//#pragma warning restore EF1000 // Possible SQL injection vulnerability. - return vehicles; - } - private void Update() - { +// return vehicles; +// } +// private void Update() +// { - } +// } - } -} +// } +//} diff --git a/PartSource.Automation/Jobs/UpdatePositioning.cs b/PartSource.Automation/Jobs/UpdatePositioning.cs index fee4822..01e52e9 100644 --- a/PartSource.Automation/Jobs/UpdatePositioning.cs +++ b/PartSource.Automation/Jobs/UpdatePositioning.cs @@ -53,7 +53,7 @@ namespace PartSource.Automation.Jobs } IList fitments = GetPositionOrderedFitments(importData?.PartNumber, importData?.LineCode); - IList vehicles = _vehicleService.GetVehiclesForPart(importData?.PartNumber, importData?.LineCode); + IList vehicles = _vehicleService.GetVehiclesForPart(importData?.PartNumber, importData?.LineCode); if (fitments.Count == 0 || vehicles.Count == 0) { diff --git a/PartSource.Automation/Program.cs b/PartSource.Automation/Program.cs index ebd4549..869295e 100644 --- a/PartSource.Automation/Program.cs +++ b/PartSource.Automation/Program.cs @@ -102,7 +102,7 @@ namespace PartSource.Automation .AddSingleton() .AddSingleton() .AddSingleton() - .AddSingleton() + .AddSingleton() //.AddSingleton() //.AddSingleton() //.AddSingleton() 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.Automation/appsettings.json b/PartSource.Automation/appsettings.json index bc06491..88da9b3 100644 --- a/PartSource.Automation/appsettings.json +++ b/PartSource.Automation/appsettings.json @@ -1,7 +1,7 @@ { "ConnectionStrings": { - //"PartSourceDatabase": "Server=localhost;Database=ps-whi-stage;Integrated Security=True;" - "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=localhost;Database=ps-whi-stage;Integrated Security=True;" + //"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": { diff --git a/PartSource.Data/Dtos/EngineDto.cs b/PartSource.Data/Dtos/EngineDto.cs new file mode 100644 index 0000000..4731596 --- /dev/null +++ b/PartSource.Data/Dtos/EngineDto.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace PartSource.Data.Dtos +{ + public class EngineDto + { + public int EngineConfigId { get; set; } + + public string Description { get; set; } + + public string Make { get; set; } + + public int MakeId { get; set; } + } +} diff --git a/PartSource.Data/Dtos/SubmodelDto.cs b/PartSource.Data/Dtos/SubmodelDto.cs new file mode 100644 index 0000000..5d7498d --- /dev/null +++ b/PartSource.Data/Dtos/SubmodelDto.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace PartSource.Data.Dtos +{ + public class SubmodelDto + { + public int Id { get; set; } + + public string Name { get; set; } + + public string Make { get; set; } + + public int MakeId { get; set; } + } +} diff --git a/PartSource.Data/Models/BaseVehicle.cs b/PartSource.Data/Models/BaseVehicle.cs index ff954d4..dd64b74 100644 --- a/PartSource.Data/Models/BaseVehicle.cs +++ b/PartSource.Data/Models/BaseVehicle.cs @@ -5,14 +5,18 @@ using System.Text; namespace PartSource.Data.Models { - public class BaseVehicle - { - public int BaseVehicleId { get; set; } + public class BaseVehicle + { + public int BaseVehicleId { get; set; } - public int Year { get; set; } + public string Make { get; set; } - public int MakeId { get; set; } + public int MakeId { get; set; } - public int ModelId { get; set; } - } + public string Model { get; set; } + + public int ModelId { get; set; } + + public int Year { get; set; } + } } diff --git a/PartSource.Data/Models/Engine.cs b/PartSource.Data/Models/Engine.cs index 4330461..16fdb40 100644 --- a/PartSource.Data/Models/Engine.cs +++ b/PartSource.Data/Models/Engine.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations.Schema; +using System.Security.Cryptography; using System.Text; namespace PartSource.Data.Models @@ -14,5 +15,13 @@ namespace PartSource.Data.Models public int BaseVehicleId { get; set; } public int SubmodelId { get; set; } + + public string Make { get; set; } + + public int MakeId { get; set; } + + public string Model { get; set; } + + public int ModelId { get; set; } } } diff --git a/PartSource.Data/Models/Fitment.cs b/PartSource.Data/Models/Fitment.cs index 179d39b..b8e12ad 100644 --- a/PartSource.Data/Models/Fitment.cs +++ b/PartSource.Data/Models/Fitment.cs @@ -10,9 +10,9 @@ namespace PartSource.Data.Models public string LineCode { get; set; } - public int? BaseVehicleId { get; set; } + public int BaseVehicleId { get; set; } - public int? EngineConfigId { get; set; } + public int EngineConfigId { get; set; } public string Position { get; set; } } diff --git a/PartSource.Data/Models/Submodel.cs b/PartSource.Data/Models/Submodel.cs index f65b6ff..b606f77 100644 --- a/PartSource.Data/Models/Submodel.cs +++ b/PartSource.Data/Models/Submodel.cs @@ -7,20 +7,20 @@ using System.Text; namespace PartSource.Data.Models { - [Table("Submodel", Schema = "Vehicle")] public class Submodel { public int SubmodelId { get; set; } public string Name { get; set; } - [JsonIgnore] public int Year { get; set; } - [JsonIgnore] + public string Make { get; set; } + public int MakeId { get; set; } - [JsonIgnore] + public string Model { get; set; } + public int ModelId { get; set; } } } diff --git a/PartSource.Data/Models/VehicleData.cs b/PartSource.Data/Models/VehicleData.cs index 241e964..061b16e 100644 --- a/PartSource.Data/Models/VehicleData.cs +++ b/PartSource.Data/Models/VehicleData.cs @@ -6,32 +6,29 @@ using System.Text; namespace PartSource.Data.Models { - public class VehicleData + public class Vehicle { - public int? MakeId { get; set; } + public int MakeId { get; set; } public string MakeName { get; set; } - public int? ModelId { get; set; } + public int ModelId { get; set; } public string ModelName { get; set; } - public int? EngineConfigId { get; set; } + public int EngineConfigId { get; set; } public string EngineDescription { get; set; } - public int? BaseVehicleId { get; set; } + public int BaseVehicleId { get; set; } - public int? Year { get; set; } + public int Year { get; set; } - public int? SubmodelId { get; set; } + public int SubmodelId { get; set; } public string SubmodelName { get; set; } [Key] public int VehicleToEngineConfigId { get; set; } - - [NotMapped] - public string Position { get; set; } } } diff --git a/PartSource.Data/Models/VehicleMake.cs b/PartSource.Data/Models/VehicleMake.cs index 6b9a4ad..f03fac4 100644 --- a/PartSource.Data/Models/VehicleMake.cs +++ b/PartSource.Data/Models/VehicleMake.cs @@ -8,7 +8,7 @@ namespace PartSource.Data.Models public class VehicleMake { [DatabaseGenerated(DatabaseGeneratedOption.None)] - public int Id { get; set; } + public int MakeId { get; set; } public string Name { get; set; } } diff --git a/PartSource.Data/Models/VehicleModel.cs b/PartSource.Data/Models/VehicleModel.cs index 589cacb..d5f7120 100644 --- a/PartSource.Data/Models/VehicleModel.cs +++ b/PartSource.Data/Models/VehicleModel.cs @@ -9,11 +9,14 @@ namespace PartSource.Data.Models public class VehicleModel { [DatabaseGenerated(DatabaseGeneratedOption.None)] - public int Id { get; set; } + public int ModelId { get; set; } + + public int Year { get; set; } public string Name { get; set; } - public int VehicleMakeId { get; set; } + public string Make { get; set; } + public int MakeId { get; set; } } } diff --git a/PartSource.Data/PartSourceContext.cs b/PartSource.Data/PartSourceContext.cs index 3688585..1d52729 100644 --- a/PartSource.Data/PartSourceContext.cs +++ b/PartSource.Data/PartSourceContext.cs @@ -33,12 +33,7 @@ namespace PartSource.Data public DbSet Parts { get; set; } - public DbSet VehicleMakes { get; set; } - - public DbSet VehicleModels { get; set; } - - - public DbSet VehicleData { get; set; } + public DbSet Vehicles { get; set; } public DbSet PartAvailabilities { get; set; } @@ -48,6 +43,10 @@ namespace PartSource.Data public DbQuery Submodels { get; set; } + public DbQuery VehicleMakes { get; set; } + + public DbQuery VehicleModels { get; set; } + protected override void OnModelCreating(ModelBuilder modelBuilder) { base.OnModelCreating(modelBuilder); @@ -55,6 +54,8 @@ namespace PartSource.Data modelBuilder.Query().ToView(nameof(BaseVehicle)); modelBuilder.Query().ToView(nameof(Engine)); modelBuilder.Query().ToView(nameof(Submodel)); + modelBuilder.Query().ToView(nameof(VehicleMake)); + modelBuilder.Query().ToView(nameof(VehicleModel)); modelBuilder.Entity().HasKey(p => new { p.Store, p.SKU }); modelBuilder.Entity().HasKey(d => new { d.LineCode, d.WhiCode }); @@ -70,10 +71,9 @@ namespace PartSource.Data protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { - if (!optionsBuilder.IsConfigured) { - optionsBuilder.UseSqlServer("Server=(localdb)\\mssqllocaldb;Database=PartSource;Trusted_Connection=True;"); + optionsBuilder.UseSqlServer("Server=localhost;Database=ps-whi-stage;Trusted_Connection=True;"); } } } diff --git a/PartSource.Services/Extensions/IQueryableExtensions.cs b/PartSource.Services/Extensions/IQueryableExtensions.cs new file mode 100644 index 0000000..2fc6c28 --- /dev/null +++ b/PartSource.Services/Extensions/IQueryableExtensions.cs @@ -0,0 +1,83 @@ +using Microsoft.EntityFrameworkCore; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Linq.Expressions; +using System.Reflection; +using System.Text; + +using static System.Linq.Expressions.Expression; + + +namespace PartSource.Services.Extensions +{ + public static class IQueryableExtensions + { + public static IQueryable ApplyQueryDto(this IQueryable queryable, T dto) + { + foreach (PropertyInfo property in typeof(T).GetProperties()) + { + object value = property.GetValue(dto); + + if (IsFilterableValue(value)) + { + queryable = queryable.Where(property, value); + } + } + + return queryable; + } + + private static IQueryable Where(this IQueryable queryable, PropertyInfo property, object value) + { + if (property == null || value == null) + { + return queryable; + } + + MemberExpression functions = Property(null, typeof(EF).GetProperty(nameof(EF.Functions))); + MethodInfo likeMethodInfo = typeof(DbFunctionsExtensions).GetMethod(nameof(DbFunctionsExtensions.Like), new Type[] { functions.Type, typeof(string), typeof(string) }); + + ParameterExpression lambdaParameter = Parameter(typeof(T), "x"); + Expression expressionProperty = Property(lambdaParameter, property.Name); + + if (property.PropertyType != typeof(string)) + { + expressionProperty = Call(expressionProperty, typeof(object).GetMethod(nameof(object.ToString), new Type[0])); + } + + MethodCallExpression methodCall = Call( + null, + likeMethodInfo, + functions, + expressionProperty, + Constant(value.ToString())); + + return queryable.Where(Lambda>(methodCall, lambdaParameter)); + } + + private static bool IsFilterableValue(object value) + { + switch (value) + { + case int i: + if (i == default) return false; + break; + + case DateTime d: + if (d == default) return false; + break; + + case string s: + if (string.IsNullOrEmpty(s)) return false; + break; + + default: + if (value == null) return false; + break; + } + + return true; + } + } +} diff --git a/PartSource.Services/VehicleService.cs b/PartSource.Services/VehicleService.cs index 354edae..b74acb7 100644 --- a/PartSource.Services/VehicleService.cs +++ b/PartSource.Services/VehicleService.cs @@ -1,13 +1,15 @@ using Microsoft.EntityFrameworkCore; using PartSource.Data; +using PartSource.Data.Dtos; using PartSource.Data.Models; +using PartSource.Services.Extensions; using System; using System.Collections.Generic; using System.Linq; -using System.Text; using System.Text.RegularExpressions; using System.Threading.Tasks; + namespace PartSource.Services { public class VehicleService @@ -19,28 +21,102 @@ namespace PartSource.Services _partSourceContext = partSourceContext; } - public async Task> GetAllMakes() + public async Task> GetVehicles(Vehicle vehicleQuery) { - return await _partSourceContext.VehicleMakes.ToListAsync(); + return await _partSourceContext.Vehicles + .ApplyQueryDto(vehicleQuery) + .ToListAsync(); } - public async Task> GetModels(int makeId, int year) + public async Task GetVehicleById(int vehicleToEngineConfigId) { - return await _partSourceContext.VehicleData.Where(d => - d.MakeId == makeId - && d.Year == year - ) - .ToListAsync(); + return await _partSourceContext.Vehicles + .FirstOrDefaultAsync(v => v.VehicleToEngineConfigId == vehicleToEngineConfigId); } - public async Task> GetBaseVehicles(int makeId, int modelId, int year) + public async Task GetVehicle(int baseVehicleId, int engineConfigId, int submodelId) { - return await _partSourceContext.BaseVehicles.Where(d => + return await _partSourceContext.Vehicles.FirstOrDefaultAsync(d => + d.BaseVehicleId == baseVehicleId + && d.EngineConfigId == engineConfigId + && d.SubmodelId == submodelId + ); + } + + public async Task> GetMakes() + { + return await _partSourceContext.VehicleMakes + .OrderBy(m => m.Name) + .ToListAsync(); + } + + public async Task> GetMakes(VehicleMake criteria) + { + return await _partSourceContext.VehicleMakes + .ApplyQueryDto(criteria) + .OrderBy(m => m.Name) + .ToListAsync(); + } + + public async Task GetMakeById(int makeId) + { + return await _partSourceContext.VehicleMakes + .FirstOrDefaultAsync(m => m.MakeId == makeId); + } + + public async Task> GetModels(VehicleModel criteria) + { + return await _partSourceContext.VehicleModels + .ApplyQueryDto(criteria) + .OrderBy(m => m.Name) + .ToListAsync(); + } + + public async Task> GetModels(int makeId, int year) + { + return await _partSourceContext.VehicleModels + .Where(m => + m.MakeId == makeId + && m.Year == year + ) + .OrderBy(d => d.Name) + .ToListAsync(); + } + + public async Task GetModelById(int modelId) + { + return await _partSourceContext.VehicleModels + .FirstOrDefaultAsync(m => m.ModelId == modelId); + } + + + public async Task> GetBaseVehicles(BaseVehicle criteria) + { + return await _partSourceContext.BaseVehicles + .ApplyQueryDto(criteria) + .ToListAsync(); + } + + public async Task GetBaseVehicle(int makeId, int modelId, int year) + { + return await _partSourceContext.BaseVehicles.FirstOrDefaultAsync(d => d.MakeId == makeId && d.ModelId == modelId && d.Year == year - ) - .ToListAsync(); + ); + } + + public async Task GetBaseVehicleById(int baseVehicleId) + { + return await _partSourceContext.BaseVehicles + .FirstOrDefaultAsync(b => b.BaseVehicleId == baseVehicleId); + } + + public async Task> GetEngines(Engine criteria) + { + return await _partSourceContext.Engines + .ApplyQueryDto(criteria) + .ToListAsync(); } public async Task> GetEngines(int baseVehicleId) @@ -57,30 +133,57 @@ namespace PartSource.Services .ToListAsync(); } + public async Task GetEngineById(int engineConfigId) + { + return await _partSourceContext.Engines + .Where(e => e.EngineConfigId == engineConfigId) + .Select(e => new EngineDto + { + EngineConfigId = e.EngineConfigId, + Description = e.Description, + Make = e.Make, + MakeId = e.MakeId + }) + .FirstOrDefaultAsync(); + } + + public async Task> GetSubmodels(Submodel submodelQuery) + { + return await _partSourceContext.Submodels + .ApplyQueryDto(submodelQuery) + .ToListAsync(); + } + public async Task> GetSubmodels(int makeId, int modelId, int year) { return await _partSourceContext.Submodels.Where(s => s.MakeId == makeId && s.ModelId == modelId - && s.Year == modelId + && s.Year == year ) .ToListAsync(); } - public async Task GetVehicle(int baseVehicleId, int engineConfigId, int submodelId) + public async Task GetSubmodelById(int submodelId) { - return await _partSourceContext.VehicleData.FirstOrDefaultAsync(d => - d.BaseVehicleId == baseVehicleId - && d.EngineConfigId == engineConfigId - && d.SubmodelId == submodelId - ); + return await _partSourceContext.Submodels + .Where(s => s.SubmodelId == submodelId) + .Select(s => new SubmodelDto + { + Id = s.SubmodelId, + Name = s.Name, + Make = s.Make, + MakeId = s.MakeId + }) + .FirstOrDefaultAsync(); } - public IList GetYmmFitment(IList vehicles) + + public IList GetYmmFitment(IList vehicles) { if (vehicles.Count == 0) { - return null; + return new string[0]; } IList fitmentTags = new List(); @@ -95,7 +198,7 @@ namespace PartSource.Services List years = vehicles .Where(v => v.MakeName == make && v.ModelName == model) .OrderBy(v => v.Year) - .Select(v => v.Year.HasValue ? v.Year.Value.ToString().Trim() : string.Empty) + .Select(v => v.Year.ToString().Trim()) .Distinct() .ToList(); @@ -109,12 +212,12 @@ namespace PartSource.Services return fitmentTags; } - public IList GetVehicleIdFitment(IList vehicles) + public IList GetVehicleIdFitment(IList vehicles) { return vehicles.Select(v => v.VehicleToEngineConfigId).ToArray(); } - public IList GetVehiclesForPart(string partNumber, string lineCode) + public IList GetVehiclesForPart(string partNumber, string lineCode) { if (string.IsNullOrEmpty(partNumber) || string.IsNullOrEmpty(lineCode)) { @@ -127,13 +230,13 @@ namespace PartSource.Services .Where(d => d.LineCode == lineCode) .Select(d => d.WhiCode); - IQueryable vehicles = _partSourceContext.Fitments + IQueryable vehicles = _partSourceContext.Fitments .Where(f => f.PartNumber == partNumber && whiCodes.Contains(f.LineCode)) - .Join(_partSourceContext.VehicleData, + .Join(_partSourceContext.Vehicles, f => new { f.BaseVehicleId, f.EngineConfigId }, v => new { v.BaseVehicleId, v.EngineConfigId }, (f, v) => v); - + return vehicles.ToList(); } }