Added core pricing metafield and status check job
This commit is contained in:
@@ -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<ImportData> 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<ProductImage> productImages = new List<ProductImage>();
|
||||
string[] imageUrls = importData.ImageSrc?.Split(',');
|
||||
IList<ProductImage> productImages = items.SelectMany(v => {
|
||||
IList<ProductImage> images = new List<ProductImage>();
|
||||
|
||||
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<string> productTags = new List<string>
|
||||
{
|
||||
importData.LineCode,
|
||||
importData.PartNumber,
|
||||
items[0].LineCode,
|
||||
items[0].PartNumber,
|
||||
};
|
||||
|
||||
List<ProductVariant> productVariants = new List<ProductVariant>();
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<Product> products = await _shopifyClient.Products.Get();
|
||||
IList<long?> 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<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",
|
||||
|
||||
37
PartSource.Automation/Jobs/StatusCheck.cs
Normal file
37
PartSource.Automation/Jobs/StatusCheck.cs
Normal file
@@ -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<AutomationJobResult> 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
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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<Product> 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<VehicleData> 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<int> 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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<AutomationJobResult> Run()
|
||||
{
|
||||
IEnumerable<Product> products = await _shopifyClient.Products.Get();
|
||||
IDictionary<string, object> parameters = new Dictionary<string, object>
|
||||
{
|
||||
{ "limit", 250 }
|
||||
};
|
||||
|
||||
IEnumerable<Product> 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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -15,10 +15,10 @@
|
||||
<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" />
|
||||
<PackageReference Include="Ratermania.Shopify" Version="1.0.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\shopify\Shopify\Shopify.csproj" />
|
||||
<ProjectReference Include="..\PartSource.Data\PartSource.Data.csproj" />
|
||||
<ProjectReference Include="..\PartSource.Services\PartSource.Services.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
"profiles": {
|
||||
"PartSource.Automation": {
|
||||
"commandName": "Project",
|
||||
"commandLineArgs": "UpdatePositioning",
|
||||
"commandLineArgs": "AddProducts",
|
||||
"environmentVariables": {
|
||||
"PS_AUTOMATION_ENVIRONMENT": "development"
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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": {
|
||||
|
||||
Reference in New Issue
Block a user