Initial commit

This commit is contained in:
2020-04-12 20:52:03 -04:00
parent e750d2848a
commit 01e7627293
249 changed files with 9733 additions and 0 deletions

View File

@@ -0,0 +1,13 @@
[*.cs]
# CA1307: Specify StringComparison
dotnet_diagnostic.CA1307.severity = suggestion
# CA1031: Do not catch general exception types
dotnet_diagnostic.CA1031.severity = none
# CA2007: Consider calling ConfigureAwait on the awaited task
dotnet_diagnostic.CA2007.severity = silent
# CA1303: Do not pass literals as localized parameters
dotnet_diagnostic.CA1303.severity = silent

View File

@@ -0,0 +1,49 @@
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using PartSource.Automation.Jobs;
using PartSource.Automation.Jobs.Interfaces;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace PartSource.Automation.Factories
{
public class JobFactory
{
public IServiceProvider _serviceProvider;
public JobFactory(IServiceProvider serviceProvider)
{
_serviceProvider = serviceProvider;
}
public IAutomationJob Build(string jobName)
{
switch (jobName)
{
case nameof(AddProducts):
return _serviceProvider.GetService<AddProducts>();
case nameof(DeleteProducts):
return _serviceProvider.GetService<DeleteProducts>();
case nameof(TestJob):
return new TestJob();
case nameof(UpdateFitment):
return _serviceProvider.GetService<UpdateFitment>();
case nameof(UpdatePricing):
return _serviceProvider.GetService<UpdatePricing>();
case nameof(ExecuteSsisPackages):
return _serviceProvider.GetService<ExecuteSsisPackages>();
default:
throw new Exception($"The job {jobName} could not be found.");
}
}
}
}

View File

@@ -0,0 +1,145 @@
using PartSource.Automation.Jobs.Interfaces;
using PartSource.Automation.Models;
using PartSource.Automation.Services;
using PartSource.Data;
using PartSource.Data.Models;
using PartSource.Data.Shopify;
using PartSource.Services;
using PartSource.Services.Integrations;
using System;
using System.Collections.Concurrent;
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<AutomationJobResult> Run()
{
await AddSkus();
return new AutomationJobResult
{
IsSuccess = true
};
}
public async Task AddSkus()
{
ImportData importData = _partSourceContext.ImportData.FirstOrDefault(p => !p.ShopifyId.HasValue);
while (importData != null)
{
if (importData == null)
{
continue;
}
// Images
List<ProductImage> productImages = new List<ProductImage>();
string[] imageUrls = importData.ImageSrc?.Split(',');
if (imageUrls?.Length > 0)
{
foreach (string url in imageUrls)
{
productImages.Add(new ProductImage
{
Src = url,
Alt = importData.ImageAltText
});
}
}
else
{
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<string> productTags = new List<string>
{
importData.LineCode,
importData.PartNumber,
};
List<ProductVariant> productVariants = new List<ProductVariant>();
productVariants.Add(new ProductVariant
{
InventoryPolicy = "Deny",
CompareAtPrice = importData.CompareAt,
Price = importData.Price,
Sku = importData.VariantSku,
Title = importData.VariantTitle,
Option1 = importData.IsVariant.ToString(),
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)
{
importData.ShopifyId = requestData.Id;
_partSourceContext.SaveChanges();
Console.WriteLine($"{importData.VariantSku}");
}
else
{
Console.WriteLine($"SHOPIFY ID WAS 0 - {importData.VariantSku}");
}
importData = _partSourceContext.ImportData.FirstOrDefault(p => !p.ShopifyId.HasValue);
}
}
}
//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);
// }
//}
}

View File

@@ -0,0 +1,320 @@
//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.Services;
//using System;
//using System.Collections.Generic;
//using System.Linq;
//using System.Text;
//using BaseVehicle = PartSource.Data.Models.BaseVehicle;
//namespace PartSource.Automation.Jobs
//{
// public class BuildVehicleCache : IAutomationJob
// {
// private readonly NexpartService _nexpartService;
// private readonly PartSourceContext _partSourceContext;
// private readonly IServiceProvider _serviceProvider;
// public BuildVehicleCache(IServiceProvider serviceProvider, PartSourceContext partSourceContext, NexpartService nexpartService)
// {
// _nexpartService = nexpartService;
// _partSourceContext = partSourceContext;
// _serviceProvider = serviceProvider;
// }
// public void Run()
// {
// try
// {
// //AddMakes();
// //AddModels();
// // AddEngines();
// //AddYearMakeModels();
// AddSubmodels();
// }
// catch (Exception ex)
// {
// ;
// }
// }
// private void AddEngines()
// {
// IList<BaseVehicle> baseVehicles = _partSourceContext.BaseVehicles.ToList();
// foreach (BaseVehicle baseVehicle in baseVehicles)
// {
// try
// {
// WHIEngineSearch whiEngineSearch = new WHIEngineSearch
// {
// VehicleIdentifier = new VehicleIdentifier
// {
// BaseVehicleId = baseVehicle.Id
// }
// };
// WHIEngineSearchResponse response = _nexpartService.SendRequest<WHIEngineSearch, WHIEngineSearchResponse>(whiEngineSearch).Result;
// foreach (WHIEngine engine in response.ResponseBody.WHIEngine)
// {
// try
// {
// if (!_partSourceContext.Engines.Any(e => e.Id == engine.Id))
// {
// _partSourceContext.Engines.Add(new Data.Models.Engine
// {
// Id = engine.Id,
// Description = engine.Description
// });
// }
// _partSourceContext.SaveChanges();
// }
// catch (Exception ex)
// {
// Console.WriteLine($"Failed to add engine { engine.Id } - { ex.Message }");
// }
// }
// }
// catch (Exception ex)
// {
// Console.WriteLine($"Failed to add engines for base vehicle { baseVehicle.Id } - { ex.Message }");
// }
// }
// }
// private void AddSubmodels()
// {
// int maxBaseVehicleId = _partSourceContext.Submodels.Any()
// ? _partSourceContext.Submodels.Max(s => s.BaseVehicleId)
// : 0;
// IList<BaseVehicle> baseVehicles = _partSourceContext.BaseVehicles.AsNoTracking().Where(b => b.Id > maxBaseVehicleId).ToList();
// foreach (BaseVehicle baseVehicle in baseVehicles)
// {
// try
// {
// SubModelSearch smSearch = new SubModelSearch()
// {
// MakeId = baseVehicle.VehicleMakeId,
// ModelId = baseVehicle.VehicleModelId,
// Year = baseVehicle.Year,
// RegionId = 2
// };
// SubModelSearchResponse smResponse = _nexpartService.SendRequest<SubModelSearch, SubModelSearchResponse>(smSearch).Result;
// SubModel[] subModels = smResponse.ResponseBody?.SubModel;
// if (subModels == null)
// {
// continue;
// }
// foreach (SubModel submodel in subModels)
// {
// EngineSearch requestContent = new EngineSearch()
// {
// VehicleIdentifier = new VehicleIdentifier()
// {
// BaseVehicleId = baseVehicle.Id
// },
// SubModelId = int.Parse(submodel.Id)
// };
// EngineSearchResponse response = _nexpartService.SendRequest<EngineSearch, EngineSearchResponse>(requestContent).Result;
// if (response.ResponseBody == null)
// {
// continue;
// }
// foreach (Data.Nexpart.Engine engine in response.ResponseBody.Engine)
// {
// VehicleIdSearch vidSearch = new VehicleIdSearch
// {
// VehicleIdentifier = new VehicleIdentifier()
// {
// BaseVehicleId = baseVehicle.Id,
// EngineConfigId = engine.Id
// },
// Criterion = new Criterion[]
// {
// new Criterion
// {
// Attribute = "SUB_MODEL",
// Id = int.Parse(submodel.Id)
// }
// },
// RegionId = new RegionId
// {
// Value = 2
// },
// ResultOption = new ResultOption[]
// {
// new ResultOption
// {
// Value = "WHI_ENGINE"
// }
// }
// };
// VehicleIdSearchResponse vidResponse = _nexpartService.SendRequest<VehicleIdSearch, VehicleIdSearchResponse>(vidSearch).Result;
// if (vidResponse != null && vidResponse.ResponseBody.VehicleToEngineConfigId > 0)
// {
// _partSourceContext.Submodels.Add(new Submodel
// {
// VehicleToEngineConfigId = vidResponse.ResponseBody.VehicleToEngineConfigId,
// SubmodelId = int.Parse(submodel.Id),
// BaseVehicleId = baseVehicle.Id,
// EngineId = vidResponse.ResponseBody.WHIEngineId
// });
// }
// }
// }
// _partSourceContext.SaveChanges();
// }
// catch (Exception ex)
// {
// Console.WriteLine($"Failed to add BaseVehicleId {baseVehicle.Id}: {ex.Message}");
// }
// }
// }
// private void AddYearMakeModels()
// {
// BaseVehicleSearch request = new BaseVehicleSearch
// {
// Years = new Years
// {
// From = 1950,
// To = 2020
// },
// Region = new[]
// {
// new Region
// {
// Id = 2
// }
// },
// VehicleType = new[]
// {
// new VehicleType
// {
// Id = 5
// },
// new VehicleType
// {
// Id = 6
// },
// new VehicleType
// {
// Id = 7
// }
// }
// };
// BaseVehicleSearchResponse response = _nexpartService.SendRequest<BaseVehicleSearch, BaseVehicleSearchResponse>(request).Result;
// foreach (Data.Nexpart.BaseVehicle vehicle in response.ResponseBody.BaseVehicle)
// {
// _partSourceContext.BaseVehicles.Add(new Data.Models.BaseVehicle
// {
// Id = (int)vehicle.BaseVehicleId,
// VehicleMakeId = (int)vehicle.MakeId,
// VehicleModelId = (int)vehicle.ModelId,
// Year = (int)vehicle.Year
// });
// }
// _partSourceContext.SaveChanges();
// }
// private void AddMakes()
// {
// MakeSearch requestContent = new MakeSearch()
// {
// VehicleTypeId = new int[] { 5, 6, 7 },
// RegionId = new int[] { 2 }
// };
// MakeSearchResponse response = _nexpartService.SendRequest<MakeSearch, MakeSearchResponse>(requestContent).Result;
// foreach (Make make in response.ResponseBody.Make)
// {
// _partSourceContext.VehicleMakes.Add(new VehicleMake
// {
// Id = make.Id,
// Name = make.Value
// });
// }
// _partSourceContext.SaveChanges();
// }
// private void AddModels()
// {
// IList<VehicleMake> vehicleMakes = _partSourceContext.VehicleMakes.ToList();
// IDictionary<int, VehicleModel> vehicleModels = new Dictionary<int, VehicleModel>();
// foreach (VehicleMake vehicleMake in vehicleMakes)
// {
// for (int year = 1950; year <= 2020; year++)
// {
// ModelSearch requestContent = new ModelSearch()
// {
// MakeId = vehicleMake.Id,
// Year = year,
// VehicleTypeId = new int[] { 5, 6, 7 },
// RegionId = new int[] { 2 }
// };
// ModelSearchResponse response = _nexpartService.SendRequest<ModelSearch, ModelSearchResponse>(requestContent).Result;
// if (response.ResponseBody == null || response.ResponseBody.Length == 0)
// {
// continue;
// }
// foreach (Model model in response.ResponseBody[0].Model)
// {
// bool result = vehicleModels.TryGetValue(model.Id, out VehicleModel throwaway);
// if (!result)
// {
// VehicleModel vehicleModel = new VehicleModel
// {
// Id = model.Id,
// Name = model.Value,
// VehicleMakeId = vehicleMake.Id
// };
// vehicleModels.Add(model.Id, vehicleModel);
// }
// }
// }
// }
// _partSourceContext.VehicleModels.AddRange(vehicleModels.Values);
// _partSourceContext.SaveChanges();
// }
// }
//}

View File

@@ -0,0 +1,62 @@
using PartSource.Data.Shopify;
using PartSource.Services;
using PartSource.Automation.Jobs.Interfaces;
using PartSource.Automation.Services;
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Linq;
using PartSource.Data;
using PartSource.Data.Models;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
using PartSource.Services.Integrations;
using PartSource.Automation.Models;
namespace PartSource.Automation.Jobs
{
public class DeleteProducts : IAutomationJob
{
private readonly ShopifyClient _shopifyClient;
public DeleteProducts(ShopifyClient shopifyClient)
{
_shopifyClient = shopifyClient;
}
// If this job fails, oh well. Run it again and again until it works, or use the Shopify UI (LOL)
public async Task<AutomationJobResult> Run()
{
Console.WriteLine("This job will delete ALL PRODUCTS from Shopify. If you really want to delete EVERY SINGLE PRODUCT, type 'mechanical keyboard' below.");
string input = Console.ReadLine();
if (input != "mechanical keyboard")
{
return new AutomationJobResult
{
IsSuccess = true
};
}
IEnumerable<Product> products = await _shopifyClient.Products.Get();
while (products != null)
{
foreach (Product product in products)
{
bool result = await _shopifyClient.Products.Delete(product);
}
products = await _shopifyClient.Products.GetNext();
Console.Write('.');
}
return new AutomationJobResult
{
Message = "All products deleted. Don't forget to truncate the ImportData table",
IsSuccess = true
};
}
}
}

View File

@@ -0,0 +1,53 @@
using PartSource.Automation.Jobs.Interfaces;
using PartSource.Automation.Models;
using PartSource.Automation.Services;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
namespace PartSource.Automation.Jobs
{
public class ExecuteSsisPackages : IAutomationJob
{
private readonly FtpService _ftpService;
private readonly SsisService _ssisService;
// TODO: set from config
private readonly string[] _ssisPackages = { "Parts Availability", "Parts Price" };
public ExecuteSsisPackages(FtpService ftpService, SsisService ssisService)
{
_ftpService = ftpService;
_ssisService = ssisService;
}
public async Task<AutomationJobResult> Run()
{
IList<string> updatedPackages = new List<string>();
IList<string> failedPackages = new List<string>();
foreach (string package in _ssisPackages)
{
try
{
_ftpService.Download($"{package}.txt");
_ssisService.Execute($"{package}.dtsx");
updatedPackages.Add(package);
}
catch (Exception ex)
{
failedPackages.Add(package);
// TODO: Log
}
}
return new AutomationJobResult
{
Message = $"Updated Packages: {string.Join(',', updatedPackages)} \n Failed Packages: {string.Join(',', failedPackages)}",
IsSuccess = failedPackages.Count == 0
};
}
}
}

View File

@@ -0,0 +1,14 @@
using PartSource.Automation.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace PartSource.Automation.Jobs.Interfaces
{
public interface IAutomationJob
{
Task<AutomationJobResult> Run();
}
}

View File

@@ -0,0 +1,21 @@
using PartSource.Automation.Jobs.Interfaces;
using PartSource.Automation.Models;
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;
namespace PartSource.Automation.Jobs
{
public class TestJob : IAutomationJob
{
public async Task<AutomationJobResult> Run()
{
return new AutomationJobResult
{
Message = "Test job ran successfully",
IsSuccess = true
};
}
}
}

View File

@@ -0,0 +1,535 @@
//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<long> _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<long> shopifyIds = _partSourceContext.ImportData.Where(s => s.IsFitment.Value && s.ShopifyId != null).Select(s => (long)s.ShopifyId).ToList();
// //List<long> shopifyIds = _partSourceContext.ImportData.Where(s => s.ShopifyId != null).Select(s => (long)s.ShopifyId).ToList();
// //_shopifyIdQueue = new ConcurrentQueue<long>(shopifyIds);
// //Parallel.For(0, _threadCount, i =>
// // {
// // //Categorize();
// // });
// // });
// }
// private IList<string> GetYmmFitmentTags(BuyersGuideSearchResponse response)
// {
// BuyersGuideMake[] makes = response?.ResponseBody?.Apps?.Make;
// if (makes == null)
// {
// return new List<string>();
// }
// IList<string> fitmentTags = new List<string>();
// foreach (BuyersGuideMake make in makes)
// {
// foreach (BuyersGuideModel model in make.Model)
// {
// IList<int> years = new List<int>();
// 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<string> GetVehicleIdFitmentTags(BuyersGuideSearchResponse response)
// //{
// // BuyersGuideMake[] makes = response?.ResponseBody?.Apps?.Make;
// // if (makes == null)
// // {
// // return new List<string>();
// // }
// // IList<string> fitmentTags = new List<string>();
// // foreach (BuyersGuideMake make in makes)
// // {
// // foreach (BuyersGuideModel model in make.Model)
// // {
// // foreach (BuyersGuideEngine engine in model.Engine)
// // {
// // IList<int> 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<Product> 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<string> ymmFitmentTags = new List<string>();
// List<string> vehicleIdFitmentTags = new List<string>();
// foreach (DcfMapping mapping in importData.DcfMappings)
// {
// buyersGuideSearch = new BuyersGuideSearch
// {
// Part = new BuyersGuidePart
// {
// PartNumber = importData.PartNumber,
// MfrCode = mapping.WhiCode
// }
// };
// BuyersGuideSearchResponse response = _nexpartService.SendRequest<BuyersGuideSearch, BuyersGuideSearchResponse>(buyersGuideSearch).Result;
// if (response.ResponseBody != null)
// {
// ymmFitmentTags.AddRange(GetYmmFitmentTags(response));
// //vehicleIdFitmentTags.AddRange(GetVehicleIdFitmentTags(response));
// }
// }
// bool published = true;
// List<string> productTags = new List<string>
// {
// 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<PartSourceContext> optionsBuilder = new DbContextOptionsBuilder<PartSourceContext>();
// optionsBuilder.UseSqlServer(_connectionString);
// PartSourceContext threadDbContext = new PartSourceContext(optionsBuilder.Options);
// int i = 0;
// int updated = 0;
// IList<Product> 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<string> 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<ImportData> importCache = _partSourceContext.ImportData.Where(s => s.IsFitment.Value && s.ShopifyId != null).ToList();
// IList<DcfMapping> 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<Product> 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<string> 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<PartSourceContext> optionsBuilder = new DbContextOptionsBuilder<PartSourceContext>();
// 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<Product> 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<string> productTags = new List<string>
// {
// importData.LineCode,
// importData.PartNumber
// };
// IDictionary<string, IList<string>> positions = new Dictionary<string, IList<string>>();
// 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<Fitment> 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<string>
// {
// vehicle.VehicleToEngineConfigId.ToString()
// });
// }
// }
// foreach (KeyValuePair<string, IList<string>> 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<MenuNodesLookup, MenuNodesLookupResponse>(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();
// // }
// //}
// }
//}

View File

@@ -0,0 +1,184 @@
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.Data.Shopify;
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;
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<AutomationJobResult> Run()
{
IEnumerable<Product> products = await _shopifyClient.Products.Get();
while (products != null && products.Any())
{
foreach (Product product in products)
{
try
{
await DeleteFitmentMetafields(product.Id);
ImportData importData = _partSourceContext.ImportData.FirstOrDefault(i => i.VariantSku == product.Variants[0].Sku);
IList<VehicleData> vehicles = _vehicleService.GetVehiclesForPart(importData?.PartNumber, importData?.LineCode);
if (vehicles.Count > 0)
{
bool isFitment = false;
IList<int> 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<string> 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
{
Console.WriteLine(product.Id);
}
}
try
{
Console.Write('.');
products = await _shopifyClient.Products.GetNext();
}
catch (Exception ex)
{
products = await _shopifyClient.Products.GetNext();
}
}
return new AutomationJobResult
{
IsSuccess = true
};
}
private async Task DeleteFitmentMetafields(long shopifyId)
{
IDictionary<string, object> parameters = new Dictionary<string, object>
{
{ "metafield[owner_id]", shopifyId},
{ "metafield[owner_resource]", "product" },
{ "namespace", "fitment" },
};
IEnumerable<Metafield> metafields = await _shopifyClient.Metafields.Get(parameters);
foreach (Metafield metafield in metafields)
{
await _shopifyClient.Metafields.Delete(metafield);
}
}
public IList<VehicleData> 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<VehicleData> vehicles = _partSourceContext.VehicleData.FromSql(sql).ToList();
#pragma warning restore EF1000 // Possible SQL injection vulnerability.
return vehicles;
}
private void Update()
{
}
}
}

View File

@@ -0,0 +1,105 @@
using PartSource.Automation.Jobs.Interfaces;
using PartSource.Automation.Models;
using PartSource.Data;
using PartSource.Data.Models;
using PartSource.Data.Shopify;
using PartSource.Services.Integrations;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace PartSource.Automation.Jobs
{
public class UpdatePricing : IAutomationJob
{
private readonly PartSourceContext _partSourceContext;
private readonly ShopifyClient _shopifyClient;
public UpdatePricing(PartSourceContext partSourceContext, ShopifyClient shopifyClient)
{
_partSourceContext = partSourceContext;
_shopifyClient = shopifyClient;
}
public async Task<AutomationJobResult> Run()
{
IEnumerable<Product> products = null;
int updateCount = 0;
try
{
products = await _shopifyClient.Products.Get();
}
catch (Exception ex)
{
// TODO: Logging
return new AutomationJobResult
{
Message = "Failed to get products from Shopify",
IsSuccess = false
};
}
while (products != null && products.Any())
{
foreach (Product product in products)
{
if (product.Variants.Length > 0)
{
ProductVariant variant = product.Variants[0];
PartPrice partPrice = _partSourceContext.PartPrices.Where(p => p.SKU == variant.Sku).FirstOrDefault();
if (partPrice == null)
{
continue;
}
if (product.Variants[0].Price != partPrice.Your_Price.Value || product.Variants[0].CompareAtPrice != partPrice.Compare_Price.Value)
{
product.Variants[0].Price = partPrice.Your_Price.Value;
product.Variants[0].CompareAtPrice = partPrice.Compare_Price.Value;
try
{
await _shopifyClient.Products.Update(product);
updateCount++;
}
catch (Exception ex)
{
// TODO: Logged failed pricing update here
}
}
}
}
try
{
products = await _shopifyClient.Products.GetNext();
}
catch (Exception ex)
{
// TODO: Logging
return new AutomationJobResult
{
Message = $"Failed to get the next set of products from Shopify. {updateCount} products were able to be updated.",
IsSuccess = false
};
}
}
return new AutomationJobResult
{
Message = $"The nightly pricing update has completed. {updateCount} products were updated.",
IsSuccess = true
};
}
}
}

View File

@@ -0,0 +1,9 @@
namespace PartSource.Automation.Models
{
public class AutomationJobResult
{
public string Message { get; set; }
public bool IsSuccess { get; set; }
}
}

View File

@@ -0,0 +1,19 @@
using PartSource.Data.Nexpart;
using System;
using System.Collections.Generic;
using System.Text;
namespace PartSource.Automation.Models.Cache
{
public class VehicleCacheItem
{
public BaseVehicle BaseVehicle { get; set; }
public IList<int> VehicleIds { get; set; }
public VehicleCacheItem()
{
VehicleIds = new List<int>();
}
}
}

View File

@@ -0,0 +1,18 @@
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace PartSource.Automation.Models.Configuration
{
public class EmailConfiguration
{
public string From { get; set; }
public string To { get; set; }
public string SmtpHost { get; set; }
}
}

View File

@@ -0,0 +1,20 @@
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace PartSource.Automation.Models.Configuration
{
public class FtpConfiguration
{
public string Url { get; set; }
public string Destination { get; set; }
public string Username { get; set; }
public string Password { get; set; }
}
}

View File

@@ -0,0 +1,14 @@
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace PartSource.Automation.Models.Configuration
{
public class SsisConfiguration
{
public string Directory { get; set; }
}
}

View File

@@ -0,0 +1,32 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp3.1</TargetFramework>
<Platforms>AnyCPU;x86;x64</Platforms>
<Configurations>Debug;Release;Also Debug</Configurations>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.CodeAnalysis.FxCopAnalyzers" Version="2.9.6">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.Extensions.Configuration.FileExtensions" Version="2.2.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="2.2.0" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="2.2.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\ratermania\shopify\Shopify\Shopify.csproj" />
<ProjectReference Include="..\PartSource.Data\PartSource.Data.csproj" />
<ProjectReference Include="..\PartSource.Services\PartSource.Services.csproj" />
</ItemGroup>
<ItemGroup>
<None Update="appsettings.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>
</Project>

View File

@@ -0,0 +1,120 @@
using PartSource.Data.Shopify;
using PartSource.Services;
using PartSource.Automation.Factories;
using PartSource.Automation.Jobs.Interfaces;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Configuration.FileExtensions;
using Microsoft.Extensions.Configuration.Json;
using PartSource.Data;
using System.IO;
using Microsoft.EntityFrameworkCore;
using PartSource.Automation.Models.Configuration;
using PartSource.Automation.Jobs;
using PartSource.Automation.Services;
using PartSource.Services.Integrations;
using Ratermania.Shopify.DependencyInjection;
using PartSource.Automation.Models;
namespace PartSource.Automation
{
internal class Program
{
private static void Main(string[] args)
{
IServiceProvider serviceProvider = ConfigureServices();
JobFactory jobFactory = serviceProvider.GetService<JobFactory>();
EmailService emailService = serviceProvider.GetService<EmailService>();
foreach (string arg in args)
{
Console.Write($"Running job {arg}... ");
try
{
IAutomationJob job = jobFactory.Build(arg);
AutomationJobResult result = job.Run().Result;
if (result.IsSuccess)
{
emailService.Send($"{arg} Completed Successfully", result.Message);
}
else
{
emailService.Send($"{arg} Failed", result.Message);
}
Console.WriteLine("Done");
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
}
private static IServiceProvider ConfigureServices()
{
string environment = Environment.GetEnvironmentVariable("PS_AUTOMATION_ENVIRONMENT");
IConfigurationBuilder builder = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
.AddJsonFile($"appsettings.{environment}.json", optional: true, reloadOnChange: true);
IConfigurationRoot configuration = builder.Build();
EmailConfiguration emailConfiguration = new EmailConfiguration();
FtpConfiguration ftpConfiguration = new FtpConfiguration();
SsisConfiguration ssisConfiguration = new SsisConfiguration();
configuration.Bind("emailConfiguration", emailConfiguration);
configuration.Bind("ftpConfiguration", ftpConfiguration);
configuration.Bind("ssisConfiguration", ssisConfiguration);
ServiceProvider serviceProvider = new ServiceCollection()
.AddDbContext<PartSourceContext>(options =>
options.UseSqlServer(configuration.GetConnectionString("PartSourceDatabase"), opts => opts.EnableRetryOnFailure())
)
.AddShopify<ShopifyClient>(options => {
options.ApiKey = configuration["Shopify:ApiKey"];
options.ApiSecret = configuration["Shopify:ApiSecret"];
options.ApiVersion = "2020-01";
options.ShopDomain = configuration["Shopify:ShopDomain"];
})
.AddSingleton(emailConfiguration)
.AddSingleton(ftpConfiguration)
.AddSingleton(ssisConfiguration)
.AddSingleton<NexpartService>()
.AddSingleton<VehicleService>()
.AddSingleton<SsisService>()
.AddSingleton<FtpService>()
.AddSingleton<EmailService>()
.AddSingleton<AddProducts>()
//.AddSingleton<BuildCategories>()
//.AddSingleton<BackupProducts>()
//.AddSingleton<BuildVehicleCache>()
.AddSingleton<DeleteProducts>()
.AddSingleton<UpdateFitment>()
.AddSingleton<UpdatePricing>()
.AddSingleton<ExecuteSsisPackages>()
.AddSingleton<JobFactory>()
.BuildServiceProvider();
return serviceProvider;
}
}
}

View File

@@ -0,0 +1,11 @@
{
"profiles": {
"PartSource.Automation": {
"commandName": "Project",
"commandLineArgs": "UpdatePricing",
"environmentVariables": {
"PS_AUTOMATION_ENVIRONMENT": "development"
}
}
}
}

View File

@@ -0,0 +1,42 @@
using PartSource.Automation.Models.Configuration;
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Linq;
using System.Net.Mail;
using System.Text;
using System.Threading.Tasks;
namespace PartSource.Automation.Services
{
public class EmailService
{
private readonly EmailConfiguration _emailConfiguration;
public EmailService(EmailConfiguration emailConfiguration)
{
_emailConfiguration = emailConfiguration;
}
public void Send(string subject, string body)
{
using (SmtpClient smtpClient = new SmtpClient { Host = _emailConfiguration.SmtpHost })
{
MailMessage mailMessage = new MailMessage
{
From = new MailAddress(_emailConfiguration.From),
Subject = subject,
Body = body,
IsBodyHtml = true
};
foreach (string address in _emailConfiguration.To.Split(','))
{
mailMessage.To.Add(address);
}
smtpClient.Send(mailMessage);
}
}
}
}

View File

@@ -0,0 +1,35 @@
using PartSource.Automation.Models.Configuration;
using System;
using System.Configuration;
using System.IO;
using System.Net;
using System.Threading.Tasks;
namespace PartSource.Automation.Services
{
public class FtpService
{
private readonly FtpConfiguration _ftpConfiguration;
public FtpService(FtpConfiguration ftpConfiguration)
{
_ftpConfiguration = ftpConfiguration;
}
public void Download(string filename)
{
FtpWebRequest request = (FtpWebRequest)WebRequest.Create($"{_ftpConfiguration.Url}/{filename}");
request.Credentials = new NetworkCredential(_ftpConfiguration.Username, _ftpConfiguration.Password);
request.Method = WebRequestMethods.Ftp.DownloadFile;
using (FtpWebResponse response = (FtpWebResponse)request.GetResponse())
{
using (Stream responseStream = response.GetResponseStream())
using (FileStream fileStream = new FileStream($"{_ftpConfiguration.Destination}\\{filename}", FileMode.Create))
{
responseStream.CopyTo(fileStream);
}
}
}
}
}

View File

@@ -0,0 +1,66 @@
using System;
using System.Collections.Generic;
using System.Data.SqlClient;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using PartSource.Automation.Models.Configuration;
using System.Configuration;
using System.Diagnostics;
namespace PartSource.Automation.Services
{
public class SsisService
{
private readonly SsisConfiguration _ssisConfiguration;
public SsisService(SsisConfiguration ssisConfiguration)
{
_ssisConfiguration = ssisConfiguration;
}
public bool Execute(string packageName)
{
try
{
using Process process = new Process
{
StartInfo = new ProcessStartInfo
{
FileName = "dtexec",
Arguments = $"/file \"{_ssisConfiguration.Directory}\\{packageName}\"",
UseShellExecute = false,
CreateNoWindow = false,
RedirectStandardOutput = true,
RedirectStandardError = true
}
};
process.Start();
//process.WaitForExit();
string stdout = process.StandardOutput.ReadToEnd();
string stderr = process.StandardError.ReadToEnd();
Console.WriteLine(stdout);
Console.WriteLine(stderr);
// Application application = new Application();
//Package package = application.LoadPackage($"{_ssisConfiguration.Directory}\\{packageName}", null);
//DTSExecResult result = package.Execute();
return true; //result == DTSExecResult.Success;
}
catch (Exception ex)
{
;
return false;
}
}
}
}

View File

@@ -0,0 +1,141 @@
using PartSource.Automation.Models.Cache;
using PartSource.Data.Nexpart;
using PartSource.Services;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace PartSource.Automation.Services
{
public class VehicleCacheService
{
private readonly ConcurrentBag<VehicleCacheItem> _vehicleCache;
private readonly ConcurrentBag<BaseVehicle> _sorryNotCanadianCache;
private readonly NexpartService _nexpartService;
public VehicleCacheService(NexpartService nexpartService)
{
_vehicleCache = new ConcurrentBag<VehicleCacheItem>();
_sorryNotCanadianCache = new ConcurrentBag<BaseVehicle>();
_nexpartService = nexpartService;
}
public VehicleCacheItem Get(int baseVehicleId, int engineConfigId)
{
return _vehicleCache.FirstOrDefault(v => v.BaseVehicle.BaseVehicleId == baseVehicleId && v.BaseVehicle.EngineConfigId == engineConfigId);
}
public void Add(VehicleCacheItem vehicle)
{
_vehicleCache.Add(vehicle);
}
public bool TryAdd(int baseVehicleId, int engineConfigId)
{
BaseVehicle sorryNotCanadian = _sorryNotCanadianCache.FirstOrDefault(b => b.BaseVehicleId == baseVehicleId && b.EngineConfigId == engineConfigId);
if (sorryNotCanadian != null)
{
return false;
}
VehicleIdSearch vehicleIdSearch = new VehicleIdSearch
{
VehicleIdentifier = new VehicleIdentifier
{
BaseVehicleId = baseVehicleId,
EngineConfigId = engineConfigId
},
ResultOption = new ResultOption[2]
{
new ResultOption { Value = "BASE_VEHICLE" },
new ResultOption { Value = "BASE_VEHICLE_DESC" }
},
RegionId = new RegionId
{
Value = 2
}
};
VehicleIdSearchResponse response = _nexpartService.SendRequest<VehicleIdSearch, VehicleIdSearchResponse>(vehicleIdSearch).Result;
if (response.ResponseBody?.BaseVehicle == null)
{
BaseVehicle vehicle = new BaseVehicle
{
BaseVehicleId = baseVehicleId,
EngineConfigId = engineConfigId
};
_sorryNotCanadianCache.Add(vehicle);
return false;
}
BaseVehicle baseVehicle = response.ResponseBody.BaseVehicle;
baseVehicle.EngineConfigId = engineConfigId;
SubModelSearch smSearch = new SubModelSearch()
{
MakeId = baseVehicle.MakeId,
ModelId = baseVehicle.ModelId,
Year = baseVehicle.Year,
RegionId = 2
};
SubModelSearchResponse smResponse = _nexpartService.SendRequest<SubModelSearch, SubModelSearchResponse>(smSearch).Result;
SubModel[] subModels = smResponse.ResponseBody?.SubModel;
if (subModels == null)
{
_sorryNotCanadianCache.Add(baseVehicle);
return false;
}
IList<int> vehicleIds = new List<int>();
foreach (SubModel submodel in subModels)
{
VehicleIdSearch vidSearch = new VehicleIdSearch
{
VehicleIdentifier = new VehicleIdentifier()
{
BaseVehicleId = baseVehicle.BaseVehicleId,
EngineConfigId = baseVehicle.EngineConfigId
},
Criterion = new Criterion[1]
{
new Criterion
{
Attribute = "SUB_MODEL",
Id = int.Parse(submodel.Id)
}
},
RegionId = new RegionId
{
Value = 2
},
};
VehicleIdSearchResponse vidResponse = _nexpartService.SendRequest<VehicleIdSearch, VehicleIdSearchResponse>(vidSearch).Result;
int? vehicleId = vidResponse.ResponseBody?.VehicleToEngineConfigId;
if (vehicleId != null && vehicleId > 0)
{
vehicleIds.Add((int)vehicleId);
}
}
VehicleCacheItem cacheItem = new VehicleCacheItem
{
BaseVehicle = baseVehicle,
VehicleIds = vehicleIds
};
_vehicleCache.Add(cacheItem);
return true;
}
}
}

View File

@@ -0,0 +1,32 @@
{
"ConnectionStrings": {
//"PartSourceDatabase": "Server=(localdb)\\mssqllocaldb;Database=PartSource;Trusted_Connection=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": {
"From": "alerts@ps-shopify.canadaeast.cloudapp.azure.com",
// "To": "tom@soundpress.com,Anas.Bajwa@Partsource.ca",
"To": "tommy@localhost",
"SmtpHost": "localhost"
},
"ftpConfiguration": {
"Username": "ps-ftp\\$ps-ftp",
"Password": "ycvXptffBxqkBXW4vuRYqn4Zi1soCvnvMMolTe5HNSeAlcl3bAyJYtNhG579",
"Url": "ftp://waws-prod-yq1-007.ftp.azurewebsites.windows.net/site/wwwroot",
"Destination": "C:\\Users\\soundpress\\Desktop"
},
"ssisConfiguration": {
"Directory": "c:\\users\\soundpress\\desktop"
},
//"Shopify": {
// "ApiKey": "9a533dad460321c6ce8f30bf5b8691ed",
// "ApiSecret": "dc9e28365d9858e544d57ac7af43fee7",
// "ShopDomain": "dev-partsource.myshopify.com"
//}
"Shopify": {
"ApiKey": "88f931933b566ade1fc92c6a39f04b34",
"ApiSecret": "527a3b4213c2c7ecb214728a899052df",
"ShopDomain": "partsource.myshopify.com"
}
}