diff --git a/PartSource.Automation/Jobs/AddProducts.cs b/PartSource.Automation/Jobs/AddProducts.cs index 97bf561..c5e5d32 100644 --- a/PartSource.Automation/Jobs/AddProducts.cs +++ b/PartSource.Automation/Jobs/AddProducts.cs @@ -1,13 +1,10 @@ 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 Ratermania.Shopify.Entities; using System; -using System.Collections.Concurrent; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; @@ -38,33 +35,30 @@ namespace PartSource.Automation.Jobs public async Task AddSkus() { - ImportData importData = _partSourceContext.ImportData.FirstOrDefault(p => !p.ShopifyId.HasValue); + IList items = _partSourceContext.ImportData + .Where(i => i.Title == _partSourceContext.ImportData.First().Title) + .ToList(); - while (importData != null) + while (items != null && items.Count > 0) { - if (importData == null) - { - continue; - } - // Images - List productImages = new List(); - string[] imageUrls = importData.ImageSrc?.Split(','); + IList productImages = items.SelectMany(v => { + IList images = new List(); - if (imageUrls?.Length > 0) - { - foreach (string url in imageUrls) + foreach (string src in v.ImageSrc?.Split(',')) { - productImages.Add(new ProductImage + images.Add(new ProductImage { - Src = url, - Alt = importData.ImageAltText + Src = src, + Alt = v.ImageAltText }); } - } - else - { + 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", @@ -75,27 +69,32 @@ namespace PartSource.Automation.Jobs // Product Tags List productTags = new List { - importData.LineCode, - importData.PartNumber, + items[0].LineCode, + items[0].PartNumber, }; List productVariants = new List(); - productVariants.Add(new ProductVariant + + foreach (ImportData itemVariant in items) { - InventoryPolicy = "Deny", - CompareAtPrice = importData.CompareAt, - Price = importData.Price, - Sku = importData.VariantSku, - Title = importData.VariantTitle, - Option1 = importData.IsVariant.ToString(), - RequiresShipping = false - }); + 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 = importData.BodyHtml, - Title = importData.Title, - Vendor = importData.Vendor, + BodyHtml = items[0].BodyHtml, + Title = items[0].Title, + Vendor = items[0].Vendor, Tags = string.Join(",", productTags), Published = true, //ProductType = importData.FINELINE_NM, @@ -109,19 +108,24 @@ namespace PartSource.Automation.Jobs if (requestData.Id > 0) { - importData.ShopifyId = requestData.Id; + foreach (ImportData variant in items) + { + variant.ShopifyId = requestData.Id; + } _partSourceContext.SaveChanges(); - Console.WriteLine($"{importData.VariantSku}"); + Console.WriteLine($"{items[0].VariantSku}"); } else { - Console.WriteLine($"SHOPIFY ID WAS 0 - {importData.VariantSku}"); + Console.WriteLine($"SHOPIFY ID WAS 0 - {items[0].VariantSku}"); } - importData = _partSourceContext.ImportData.FirstOrDefault(p => !p.ShopifyId.HasValue); + items = _partSourceContext.ImportData + .Where(i => i.Title == _partSourceContext.ImportData.First(d => d.ShopifyId == null).Title) + .ToList(); } } } diff --git a/PartSource.Automation/Jobs/DeleteProducts.cs b/PartSource.Automation/Jobs/DeleteProducts.cs index 2be7673..461ab10 100644 --- a/PartSource.Automation/Jobs/DeleteProducts.cs +++ b/PartSource.Automation/Jobs/DeleteProducts.cs @@ -1,27 +1,24 @@ -using PartSource.Data.Shopify; -using PartSource.Services; -using PartSource.Automation.Jobs.Interfaces; -using PartSource.Automation.Services; +using PartSource.Automation.Jobs.Interfaces; +using PartSource.Automation.Models; +using PartSource.Data; +using PartSource.Services.Integrations; +using Ratermania.Shopify.Entities; 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; + private readonly PartSourceContext _partSourceContext; - public DeleteProducts(ShopifyClient shopifyClient) + public DeleteProducts(ShopifyClient shopifyClient, PartSourceContext partSourceContext) { _shopifyClient = shopifyClient; + _partSourceContext = partSourceContext; } // If this job fails, oh well. Run it again and again until it works, or use the Shopify UI (LOL) @@ -38,20 +35,34 @@ namespace PartSource.Automation.Jobs }; } - IEnumerable products = await _shopifyClient.Products.Get(); + IList shopifyIds = _partSourceContext.ImportData + .Select(i => i.ShopifyId) + .Distinct() + .ToList(); - while (products != null) + foreach (long? id in shopifyIds) { - foreach (Product product in products) - { - bool result = await _shopifyClient.Products.Delete(product); - } + Product product = await _shopifyClient.Products.GetById((long)id); - products = await _shopifyClient.Products.GetNext(); + await _shopifyClient.Products.Delete(product); - Console.Write('.'); + Console.WriteLine(id); } + //IEnumerable 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", diff --git a/PartSource.Automation/Jobs/StatusCheck.cs b/PartSource.Automation/Jobs/StatusCheck.cs new file mode 100644 index 0000000..ccf0ba4 --- /dev/null +++ b/PartSource.Automation/Jobs/StatusCheck.cs @@ -0,0 +1,37 @@ +using PartSource.Automation.Jobs.Interfaces; +using PartSource.Automation.Models; +using PartSource.Automation.Services; +using System; +using System.Collections.Generic; +using System.Text; +using System.Threading.Tasks; + +namespace PartSource.Automation.Jobs +{ + public class StatusCheck : IAutomationJob + { + private readonly string[] phoneNumbers = { "8593609107", "5134008303" }; + private readonly EmailService _emailService; + + public StatusCheck(EmailService emailService) + { + _emailService = emailService; + } + + public async Task Run() + { + foreach (string phoneNumber in phoneNumbers) + { + // TODO: One day it won't just be AT&T numbers + string to = $"{phoneNumber}@txt.att.net"; + + _emailService.Send(to, string.Empty, "Partsource.Automation Running"); + } + + return new AutomationJobResult + { + IsSuccess = true + }; + } + } +} diff --git a/PartSource.Automation/Jobs/UpdateFitment.cs b/PartSource.Automation/Jobs/UpdateFitment.cs index 591e440..1c7c93a 100644 --- a/PartSource.Automation/Jobs/UpdateFitment.cs +++ b/PartSource.Automation/Jobs/UpdateFitment.cs @@ -6,7 +6,6 @@ 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; @@ -19,6 +18,7 @@ using System.Linq; using System.Text; using System.Text.RegularExpressions; using System.Threading.Tasks; +using Ratermania.Shopify.Entities; namespace PartSource.Automation.Jobs { @@ -42,22 +42,24 @@ namespace PartSource.Automation.Jobs { IEnumerable products = await _shopifyClient.Products.Get(); + int i = 0; + 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); + 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.Count == 0) + if (vehicles == null || vehicles.Count == 0) { continue; } + await DeleteFitmentMetafields(product.Id); + bool isFitment = false; IList vehicleIdFitment = _vehicleService.GetVehicleIdFitment(vehicles); @@ -119,23 +121,36 @@ namespace PartSource.Automation.Jobs }; await _shopifyClient.Metafields.Add(isFitmentMetafield); + + importData.UpdatedAt = DateTime.Now; + importData.UpdateType = "Fitment"; } - catch + catch (Exception ex) { - Console.WriteLine(product.Id); + Console.WriteLine($"{product.Id}: {ex.Message}"); } } try { - Console.Write('.'); + i++; + Console.WriteLine(i); + + await _partSourceContext.SaveChangesAsync(); products = await _shopifyClient.Products.GetNext(); } catch (Exception ex) { + i++; + Console.WriteLine(i); + + Console.WriteLine($"Retrying request: {ex.Message}"); + + await _partSourceContext.SaveChangesAsync(); + products = await _shopifyClient.Products.GetNext(); } } diff --git a/PartSource.Automation/Jobs/UpdatePositioning.cs b/PartSource.Automation/Jobs/UpdatePositioning.cs index b09f29a..fee4822 100644 --- a/PartSource.Automation/Jobs/UpdatePositioning.cs +++ b/PartSource.Automation/Jobs/UpdatePositioning.cs @@ -1,11 +1,12 @@ -using Newtonsoft.Json; +using Microsoft.EntityFrameworkCore; +using Newtonsoft.Json; using PartSource.Automation.Jobs.Interfaces; using PartSource.Automation.Models; using PartSource.Data; using PartSource.Data.Models; -using PartSource.Data.Shopify; using PartSource.Services; using PartSource.Services.Integrations; +using Ratermania.Shopify.Entities; using System; using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; @@ -31,7 +32,12 @@ namespace PartSource.Automation.Jobs public async Task Run() { - IEnumerable products = await _shopifyClient.Products.Get(); + IDictionary parameters = new Dictionary + { + { "limit", 250 } + }; + + IEnumerable products = await _shopifyClient.Products.Get(parameters); while (products != null && products.Any()) { @@ -79,30 +85,37 @@ namespace PartSource.Automation.Jobs } await SavePositionMetafield(product, vehicleIds, currentPosition); + + importData.UpdatedAt = DateTime.Now; + importData.UpdateType = "Positioning"; + + } - catch + catch (Exception ex) { - Console.WriteLine(product.Id); + Console.WriteLine($"{product.Id}: {ex.Message}"); } } try { Console.Write('.'); - + await _partSourceContext.SaveChangesAsync(); products = await _shopifyClient.Products.GetNext(); } catch (Exception ex) { - products = await _shopifyClient.Products.GetNext(); + Console.WriteLine($"Retrying: {ex.Message}"); + + products = await _shopifyClient.Products.GetPrevious(); } } return new AutomationJobResult { - Message = "Fitment updated successfully", + Message = "Positioning updated successfully", IsSuccess = true }; } @@ -119,6 +132,7 @@ namespace PartSource.Automation.Jobs .Where(f => f.PartNumber == partNumber && whiCodes.Contains(f.LineCode) && !string.IsNullOrEmpty(f.Position)) .OrderBy(f => f.Position) .ToList(); + } [SuppressMessage("Globalization", "CA1308:Normalize strings to uppercase", Justification = "It's a Shopify metafield key")] @@ -152,6 +166,8 @@ namespace PartSource.Automation.Jobs OwnerId = product.Id }; + System.Diagnostics.Debug.WriteLine(json); + await _shopifyClient.Metafields.Add(vehicleMetafield); } diff --git a/PartSource.Automation/Jobs/UpdatePricing.cs b/PartSource.Automation/Jobs/UpdatePricing.cs index 3cbb002..4d10f17 100644 --- a/PartSource.Automation/Jobs/UpdatePricing.cs +++ b/PartSource.Automation/Jobs/UpdatePricing.cs @@ -2,8 +2,8 @@ using PartSource.Automation.Models; using PartSource.Data; using PartSource.Data.Models; -using PartSource.Data.Shopify; using PartSource.Services.Integrations; +using Ratermania.Shopify.Entities; using System; using System.Collections.Generic; using System.Linq; @@ -53,31 +53,51 @@ namespace PartSource.Automation.Jobs ProductVariant variant = product.Variants[0]; PartPrice partPrice = _partSourceContext.PartPrices.Where(p => p.SKU == variant.Sku).FirstOrDefault(); - if (partPrice == null) + if (partPrice == null || !partPrice.Your_Price.HasValue || !partPrice.Compare_Price.HasValue) { continue; } - if (product.Variants[0].Price != partPrice.Your_Price.Value || product.Variants[0].CompareAtPrice != partPrice.Compare_Price.Value) + try { - product.Variants[0].Price = partPrice.Your_Price.Value; - product.Variants[0].CompareAtPrice = partPrice.Compare_Price.Value; - - try + if (product.Variants[0].Price != partPrice.Your_Price.Value || product.Variants[0].CompareAtPrice != partPrice.Compare_Price.Value) { - await _shopifyClient.Products.Update(product); + product.Variants[0].Price = partPrice.Your_Price.Value; + product.Variants[0].CompareAtPrice = partPrice.Compare_Price.Value; - updateCount++; - } + Metafield metafield = new Metafield + { + Namespace = "Pricing", + Key = "CorePrice", + Value = partPrice.Core_Price.HasValue ? partPrice.Core_Price.Value.ToString() : "0.00", + ValueType = "string", + OwnerResource = "product", + OwnerId = product.Id + }; - catch (Exception ex) - { - // TODO: Logged failed pricing update here + try + { + await _shopifyClient.Products.Update(product); + + updateCount++; + } + + catch (Exception ex) + { + + } } } + + catch (Exception ex) + { + ; + } } } + _partSourceContext.SaveChanges(); + try { products = await _shopifyClient.Products.GetNext(); @@ -85,13 +105,7 @@ namespace PartSource.Automation.Jobs catch (Exception ex) { - // TODO: Logging - - return new AutomationJobResult - { - Message = $"Failed to get the next set of products from Shopify.\n\n {ex}\n\n {updateCount} products were able to be updated.", - IsSuccess = false - }; + products = await _shopifyClient.Products.GetPrevious(); } } diff --git a/PartSource.Automation/PartSource.Automation.csproj b/PartSource.Automation/PartSource.Automation.csproj index feb7b50..523e8f3 100644 --- a/PartSource.Automation/PartSource.Automation.csproj +++ b/PartSource.Automation/PartSource.Automation.csproj @@ -15,10 +15,10 @@ - + diff --git a/PartSource.Automation/Program.cs b/PartSource.Automation/Program.cs index 4d607fb..456fbbf 100644 --- a/PartSource.Automation/Program.cs +++ b/PartSource.Automation/Program.cs @@ -1,5 +1,4 @@ -using PartSource.Data.Shopify; -using PartSource.Services; +using PartSource.Services; using PartSource.Automation.Factories; using PartSource.Automation.Jobs.Interfaces; using System; diff --git a/PartSource.Automation/Properties/launchSettings.json b/PartSource.Automation/Properties/launchSettings.json index 4e4d7f7..56ee9a2 100644 --- a/PartSource.Automation/Properties/launchSettings.json +++ b/PartSource.Automation/Properties/launchSettings.json @@ -2,7 +2,7 @@ "profiles": { "PartSource.Automation": { "commandName": "Project", - "commandLineArgs": "UpdatePositioning", + "commandLineArgs": "AddProducts", "environmentVariables": { "PS_AUTOMATION_ENVIRONMENT": "development" } diff --git a/PartSource.Automation/Services/EmailService.cs b/PartSource.Automation/Services/EmailService.cs index b051d91..00d94da 100644 --- a/PartSource.Automation/Services/EmailService.cs +++ b/PartSource.Automation/Services/EmailService.cs @@ -15,28 +15,53 @@ namespace PartSource.Automation.Services public EmailService(EmailConfiguration emailConfiguration) { - _emailConfiguration = emailConfiguration; + _emailConfiguration = emailConfiguration; } public void Send(string subject, string body) { - using (SmtpClient smtpClient = new SmtpClient { Host = _emailConfiguration.SmtpHost }) + using SmtpClient smtpClient = new SmtpClient { - MailMessage mailMessage = new MailMessage - { - From = new MailAddress(_emailConfiguration.From), - Subject = subject, - Body = body, - IsBodyHtml = true - }; + Host = _emailConfiguration.SmtpHost + }; - foreach (string address in _emailConfiguration.To.Split(',')) - { - mailMessage.To.Add(address); - } + using MailMessage mailMessage = new MailMessage + { + From = new MailAddress(_emailConfiguration.From), + Subject = subject, + Body = body, + IsBodyHtml = true + }; - smtpClient.Send(mailMessage); + foreach (string address in _emailConfiguration.To.Split(',')) + { + mailMessage.To.Add(address); } + + smtpClient.Send(mailMessage); + } + + public void Send(string to, string subject, string body) + { + using SmtpClient smtpClient = new SmtpClient + { + Host = _emailConfiguration.SmtpHost + }; + + using MailMessage mailMessage = new MailMessage + { + From = new MailAddress(_emailConfiguration.From), + Subject = subject, + Body = body, + IsBodyHtml = false + }; + + foreach (string address in _emailConfiguration.To.Split(',')) + { + mailMessage.To.Add(to); + } + + smtpClient.Send(mailMessage); } } } diff --git a/PartSource.Automation/appsettings.json b/PartSource.Automation/appsettings.json index 6568fcd..bc06491 100644 --- a/PartSource.Automation/appsettings.json +++ b/PartSource.Automation/appsettings.json @@ -1,6 +1,6 @@ { "ConnectionStrings": { - //"PartSourceDatabase": "Server=(localdb)\\mssqllocaldb;Database=PartSource;Trusted_Connection=True;" + //"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/Models/ImportData.cs b/PartSource.Data/Models/ImportData.cs index 3650076..acf892a 100644 --- a/PartSource.Data/Models/ImportData.cs +++ b/PartSource.Data/Models/ImportData.cs @@ -37,5 +37,9 @@ namespace PartSource.Data.Models public string LineCode { get; set; } public string PartNumber { get; set; } + + public DateTime? UpdatedAt { get; set; } + + public string UpdateType { get; set; } } } diff --git a/PartSource.Data/Models/PartPrice.cs b/PartSource.Data/Models/PartPrice.cs index b4b617c..2d3f0bd 100644 --- a/PartSource.Data/Models/PartPrice.cs +++ b/PartSource.Data/Models/PartPrice.cs @@ -10,6 +10,7 @@ namespace PartSource.Data.Models public string SKU { get; set; } public Nullable Compare_Price { get; set; } public Nullable Your_Price { get; set; } + public decimal? Core_Price { get; set; } public string Active { get; set; } // public virtual PartData PartData { get; set; } diff --git a/PartSource.Data/PartSource.Data.csproj b/PartSource.Data/PartSource.Data.csproj index bcb5132..9808e7d 100644 --- a/PartSource.Data/PartSource.Data.csproj +++ b/PartSource.Data/PartSource.Data.csproj @@ -5,11 +5,20 @@ Debug;Release;Also Debug + + + + + + - + + + + diff --git a/PartSource.Services/Integrations/ShopifyClient.cs b/PartSource.Services/Integrations/ShopifyClient.cs index 5667329..c05041d 100644 --- a/PartSource.Services/Integrations/ShopifyClient.cs +++ b/PartSource.Services/Integrations/ShopifyClient.cs @@ -1,5 +1,6 @@ -using PartSource.Data.Shopify; +//using PartSource.Data.Shopify; using Ratermania.Shopify; +using Ratermania.Shopify.Entities; using System; using System.Collections.Generic; using System.Text; diff --git a/PartSource.Services/MetafieldService.cs b/PartSource.Services/MetafieldService.cs new file mode 100644 index 0000000..a7b2eed --- /dev/null +++ b/PartSource.Services/MetafieldService.cs @@ -0,0 +1,73 @@ +//using Newtonsoft.Json; +//using PartSource.Data.Shopify; +//using PartSource.Services.Integrations; +//using Ratermania.Shopify; +//using System; +//using System.Collections.Generic; +//using System.Diagnostics.CodeAnalysis; +//using System.Text; +//using System.Threading.Tasks; + +//namespace PartSource.Services +//{ +// public class MetafieldService +// { +// private readonly ShopifyClient _shopifyClient; + +// public MetafieldService(ShopifyClient shopifyClient) +// { +// _shopifyClient = shopifyClient; +// } + +// [SuppressMessage("Globalization", "CA1308:Normalize strings to uppercase", Justification = "Lowercase is expected by Shopify")] +// public async Task SaveMetafield(T shopifyEntity, IList vehicleIds, string @namespace) where T : ShopifyEntity +// { +// if (vehicleIds.Count == 0) +// { +// return; +// } + +// string json = JsonConvert.SerializeObject(vehicleIds); +// if (json.Length >= 100000) +// { +// // TODO: Logging +// return; +// } + +// string key = @namespace.ToLowerInvariant().Replace(" ", "_"); +// if (key.Length > 20) +// { +// key = key.Substring(0, 20); +// } + +// Metafield metafield = new Metafield +// { +// Namespace = "position", +// Key = key, +// Value = json, +// ValueType = "json_string", +// OwnerResource = "product", +// OwnerId = shopifyEntity.Id +// }; + +// await _shopifyClient.Metafields.Add(metafield); +// } + +// public async Task DeleteMetafields(long shopifyId) where T : ShopifyEntity +// { +// IDictionary parameters = new Dictionary +// { +// { "metafield[owner_id]", shopifyId}, +// { "metafield[owner_resource]", "product" }, +// { "namespace", "position" }, +// }; + +// IEnumerable metafields = await _shopifyClient.Metafields.Get(parameters); + +// foreach (Metafield metafield in metafields) +// { +// await _shopifyClient.Metafields.Delete(metafield); +// } +// } +// } +//} diff --git a/PartSource.Services/PartSource.Services.csproj b/PartSource.Services/PartSource.Services.csproj index d0feba9..f6f7e4d 100644 --- a/PartSource.Services/PartSource.Services.csproj +++ b/PartSource.Services/PartSource.Services.csproj @@ -1,4 +1,4 @@ - + netcoreapp3.1 @@ -7,10 +7,10 @@ - + diff --git a/PartSource.Services/VehicleService.cs b/PartSource.Services/VehicleService.cs index 94bc5ac..354edae 100644 --- a/PartSource.Services/VehicleService.cs +++ b/PartSource.Services/VehicleService.cs @@ -101,7 +101,7 @@ namespace PartSource.Services string tag = $"{string.Join('-', years)} {make.Trim()} {model.Trim()}"; - Console.WriteLine(tag); + System.Diagnostics.Debug.WriteLine(tag); fitmentTags.Add(tag); } @@ -116,6 +116,11 @@ namespace PartSource.Services public IList GetVehiclesForPart(string partNumber, string lineCode) { + if (string.IsNullOrEmpty(partNumber) || string.IsNullOrEmpty(lineCode)) + { + return null; + } + partNumber = Regex.Replace(partNumber, "[^a-zA-Z0-9]", string.Empty); IQueryable whiCodes = _partSourceContext.DcfMappings diff --git a/PartSource.sln b/PartSource.sln index f8be63e..82b38d4 100644 --- a/PartSource.sln +++ b/PartSource.sln @@ -11,6 +11,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PartSource.Services", "Part EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PartSource.Automation", "PartSource.Automation\PartSource.Automation.csproj", "{C85D675B-A76C-4F9C-9C57-1E063211C946}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Shopify", "..\shopify\Shopify\Shopify.csproj", "{E3917C1F-2BBD-482F-90DE-DD693F28C105}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Also Debug|Any CPU = Also Debug|Any CPU @@ -42,6 +44,12 @@ Global {C85D675B-A76C-4F9C-9C57-1E063211C946}.Debug|Any CPU.Build.0 = Debug|Any CPU {C85D675B-A76C-4F9C-9C57-1E063211C946}.Release|Any CPU.ActiveCfg = Release|Any CPU {C85D675B-A76C-4F9C-9C57-1E063211C946}.Release|Any CPU.Build.0 = Release|Any CPU + {E3917C1F-2BBD-482F-90DE-DD693F28C105}.Also Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E3917C1F-2BBD-482F-90DE-DD693F28C105}.Also Debug|Any CPU.Build.0 = Debug|Any CPU + {E3917C1F-2BBD-482F-90DE-DD693F28C105}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E3917C1F-2BBD-482F-90DE-DD693F28C105}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E3917C1F-2BBD-482F-90DE-DD693F28C105}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E3917C1F-2BBD-482F-90DE-DD693F28C105}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE