This commit is contained in:
@@ -195,7 +195,10 @@ namespace Sockeye.Biz
|
|||||||
{
|
{
|
||||||
var CustomerName = jCustomer["name"].Value<string>();
|
var CustomerName = jCustomer["name"].Value<string>();
|
||||||
if (multiSite)
|
if (multiSite)
|
||||||
|
{
|
||||||
CustomerName += " - " + jSite["name"].Value<string>();
|
CustomerName += " - " + jSite["name"].Value<string>();
|
||||||
|
log.LogInformation($"RFImport MULTISITE CUSTOMER: {CustomerName}");
|
||||||
|
}
|
||||||
long CurrentCustomerId = 0;
|
long CurrentCustomerId = 0;
|
||||||
|
|
||||||
//Create customer if we don't have one already
|
//Create customer if we don't have one already
|
||||||
@@ -222,9 +225,12 @@ namespace Sockeye.Biz
|
|||||||
if (jSite["hosted"].Value<bool>() == true)
|
if (jSite["hosted"].Value<bool>() == true)
|
||||||
c.Tags.Add("hosted");
|
c.Tags.Add("hosted");
|
||||||
|
|
||||||
var adminEmail = jCustomer["adminEmail"].Value<string>();
|
//In rockfish there were support emails that were people allowed to be contacting us on behalf of the customer
|
||||||
if (!string.IsNullOrWhiteSpace(adminEmail))
|
var supportEmail = jCustomer["supportEmail"].Value<string>();
|
||||||
c.Notes += "\nAdmin Email: " + adminEmail;
|
if (!string.IsNullOrWhiteSpace(supportEmail))
|
||||||
|
c.Notes += "\nSupport Emails: " + supportEmail;
|
||||||
|
//in Rockfish the admin email is the main license related contact and technically the only person responsible to contact us
|
||||||
|
//usually the same as the purchase email
|
||||||
c.EmailAddress = jCustomer["adminEmail"].Value<string>();
|
c.EmailAddress = jCustomer["adminEmail"].Value<string>();
|
||||||
CustomerBiz biz = CustomerBiz.GetBiz(ct);
|
CustomerBiz biz = CustomerBiz.GetBiz(ct);
|
||||||
var NewObject = await biz.CreateAsync(c);
|
var NewObject = await biz.CreateAsync(c);
|
||||||
|
|||||||
@@ -13,11 +13,11 @@ namespace Sockeye.Biz
|
|||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Process purchases that are from vendor notification
|
/// Process vendor notifications
|
||||||
/// Turn vendordata into fully filled out purchase
|
/// Turn vendordata into fully filled out purchase
|
||||||
/// attempt to match to existing customer or create one if necessary
|
/// attempt to match to existing customer or create one if necessary
|
||||||
///
|
///
|
||||||
/// A Separate job will make licenses
|
/// A Separate job will make licenses from the new purchases where feasible
|
||||||
///
|
///
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal static class SockBotProcessVendorNotifications
|
internal static class SockBotProcessVendorNotifications
|
||||||
@@ -39,9 +39,6 @@ namespace Sockeye.Biz
|
|||||||
log.LogDebug("Process vendor notifications starting");
|
log.LogDebug("Process vendor notifications starting");
|
||||||
await ProcessVendorNotificationDataIntoPurchases();
|
await ProcessVendorNotificationDataIntoPurchases();
|
||||||
|
|
||||||
// log.LogDebug("Process licenses from purchases starting");
|
|
||||||
// await ProcessPurchasesIntoLicenses();
|
|
||||||
|
|
||||||
lastSweep = DateTime.UtcNow;
|
lastSweep = DateTime.UtcNow;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -53,58 +50,43 @@ namespace Sockeye.Biz
|
|||||||
{
|
{
|
||||||
|
|
||||||
//get a list of all actionable vendor notifications
|
//get a list of all actionable vendor notifications
|
||||||
var ProcessablePurchaseIdList = await ct.Purchase
|
var vnList = await ct.VendorNotification
|
||||||
.AsNoTracking()
|
.AsNoTracking()
|
||||||
.Where(z => z.Processed == false
|
.Where(z => z.Processed == null)
|
||||||
&& z.ProductId == null)
|
|
||||||
.OrderBy(z => z.Id)
|
.OrderBy(z => z.Id)
|
||||||
.Select(z => z.Id)
|
|
||||||
.ToListAsync();
|
.ToListAsync();
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
foreach (long purchaseId in ProcessablePurchaseIdList)
|
foreach (var vn in vnList)
|
||||||
{
|
{
|
||||||
var biz = PurchaseBiz.GetBiz(ct);
|
var biz = PurchaseBiz.GetBiz(ct);
|
||||||
var p = await biz.GetAsync(purchaseId, false);
|
var p = new Purchase();
|
||||||
if (p == null)
|
|
||||||
|
log.LogDebug($"Processing vendor notification {vn.Id}-{vn.Created}");
|
||||||
|
|
||||||
|
if (string.IsNullOrWhiteSpace(vn.VendorData))
|
||||||
{
|
{
|
||||||
//this is a serious issue log and server ops it
|
var err = $"VendorNotification record {vn.Id}-{vn.Created} has no vendor data";
|
||||||
var err = $"SockBotProcessPurchases error running job, purchase record id {purchaseId} could not be fetched {biz.GetErrorsAsString}";
|
await NotifyEventHelper.AddOpsProblemEvent("SockBotProcessVendorNotifications: " + err);
|
||||||
await NotifyEventHelper.AddOpsProblemEvent(err);
|
|
||||||
log.LogError(err);
|
log.LogError(err);
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
log.LogDebug($"Processing purchase {p.Id}-{p.PurchaseDate}");
|
|
||||||
|
|
||||||
if (string.IsNullOrWhiteSpace(p.VendorData))
|
|
||||||
{
|
|
||||||
var err = $"Purchase record with ID {purchaseId} has no vendor data for sales order {p.SalesOrderNumber}";
|
|
||||||
await NotifyEventHelper.AddOpsProblemEvent("SockBotProcessPurchases: " + err);
|
|
||||||
log.LogError(err);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//Parse json vendordata
|
|
||||||
|
|
||||||
//Existing customer or create new one?
|
//Parse json vendordata
|
||||||
//here maybe need to match by vendor provided customer ID??
|
await ParseVendorNotificationData(vn, ct, log);
|
||||||
//sometimes a user will make a new account for a new purchase but intend it as an addon to v7
|
|
||||||
//for v8 it should be straightforward, however if pricing chagnes and new product needs to be purchased they may create a new record
|
|
||||||
//same dbid for v8 should do the trick
|
|
||||||
|
|
||||||
|
//save changes
|
||||||
|
p.Processed = true;
|
||||||
|
await biz.PutAsync(p);
|
||||||
|
|
||||||
//save changes
|
|
||||||
p.Processed = true;
|
|
||||||
await biz.PutAsync(p);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
var err = "SockBotProcessPurchases error running job";
|
var err = "SockBotProcessVendorNotifications error running job";
|
||||||
//serious issue requires immediate notification
|
//serious issue requires immediate notification
|
||||||
await NotifyEventHelper.AddOpsProblemEvent(err, ex);
|
await NotifyEventHelper.AddOpsProblemEvent(err, ex);
|
||||||
log.LogError(ex, err);
|
log.LogError(ex, err);
|
||||||
@@ -134,26 +116,50 @@ namespace Sockeye.Biz
|
|||||||
//CUSTOMER create or locate
|
//CUSTOMER create or locate
|
||||||
var jCustomerName = jData["order_notification"]["purchase"]["customer_data"]["reg_name"].Value<string>() ?? throw new System.FormatException($"Vendor data empty reg_name:{vn.VendorData}");
|
var jCustomerName = jData["order_notification"]["purchase"]["customer_data"]["reg_name"].Value<string>() ?? throw new System.FormatException($"Vendor data empty reg_name:{vn.VendorData}");
|
||||||
var jCustomerEmail = jData["order_notification"]["purchase"]["customer_data"]["delivery_contact"]["email"].Value<string>() ?? throw new System.FormatException($"Vendor data empty email:{vn.VendorData}");
|
var jCustomerEmail = jData["order_notification"]["purchase"]["customer_data"]["delivery_contact"]["email"].Value<string>() ?? throw new System.FormatException($"Vendor data empty email:{vn.VendorData}");
|
||||||
|
var jCustomerAccountNumber = jData["order_notification"]["purchase"]["customer_data"]["shopper_id"].Value<string>();//appears to be mycommerce customer id number hopefully static between orders
|
||||||
|
|
||||||
var customerBiz = CustomerBiz.GetBiz(ct);
|
var customerBiz = CustomerBiz.GetBiz(ct);
|
||||||
|
|
||||||
Customer c = await ct.Customer.FirstOrDefaultAsync(z => z.Name == jCustomerName) ?? await ct.Customer.FirstOrDefaultAsync(z => z.EmailAddress == jCustomerEmail);
|
//attempt to match to existing customer
|
||||||
|
//account number is most ideal match, name second but could be multiple in sockeye from rockfish sites so name will start the same, finally email if nothing else
|
||||||
|
Customer c = await ct.Customer.FirstOrDefaultAsync(z => z.AccountNumber == jCustomerAccountNumber) ?? await ct.Customer.FirstOrDefaultAsync(z => z.Name.StartsWith(jCustomerName)) ?? await ct.Customer.FirstOrDefaultAsync(z => z.EmailAddress == jCustomerEmail);
|
||||||
if (c == null)
|
if (c == null)
|
||||||
{
|
{
|
||||||
//New customer
|
//New customer
|
||||||
c = new Customer();
|
c = new Customer();
|
||||||
|
|
||||||
c.Name = jCustomerName;
|
c.Name = jCustomerName;
|
||||||
UpdateCustomerFromVendorData(jData, jCustomerEmail, c);
|
c.EmailAddress = jCustomerEmail;
|
||||||
|
c.AccountNumber = jCustomerAccountNumber;
|
||||||
|
UpdateCustomerFromVendorData(jData, c);
|
||||||
c = await customerBiz.CreateAsync(c);
|
c = await customerBiz.CreateAsync(c);
|
||||||
if (c == null)
|
if (c == null)
|
||||||
throw new System.ApplicationException($"Error creating new Customer: {customerBiz.GetErrorsAsString()} vendor data :{vn.VendorData}");
|
throw new System.ApplicationException($"Error creating new Customer: {customerBiz.GetErrorsAsString()} vendor data :{vn.VendorData}");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
//existing customer, refresh it
|
//existing customer
|
||||||
UpdateCustomerFromVendorData(jData, jCustomerEmail, c);
|
//here there could be several potential issues:
|
||||||
|
//name differs because it was a separate site in rockfish, it's not cool to change the name
|
||||||
|
//email differs, this can happen and is ok
|
||||||
|
//account number differs if was empty then it's ok. If it wasn't empty and it differs this is a potential problem:
|
||||||
|
//
|
||||||
|
if (c.EmailAddress != jCustomerEmail)
|
||||||
|
{
|
||||||
|
c.EmailAddress = jCustomerEmail;//assume it was empty or has been recently updated
|
||||||
|
}
|
||||||
|
|
||||||
|
if (c.AccountNumber != jCustomerAccountNumber)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(c.AccountNumber))
|
||||||
|
c.AccountNumber=jCustomerAccountNumber;//this is ok, there wasn't an account number before so we're just adding it
|
||||||
|
else{
|
||||||
|
// this is problematic, it matched but for some reason the account numbers differ, there's no safe way to process this so alert and bail
|
||||||
|
throw new System.ApplicationException($"Not processed due to error updating existing Customer: {c.Name} Account numbers differ, expected: {c.AccountNumber} vendor data:{vn.VendorData}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//refresh
|
||||||
|
UpdateCustomerFromVendorData(jData, c);
|
||||||
c = await customerBiz.PutAsync(c);
|
c = await customerBiz.PutAsync(c);
|
||||||
if (c == null)
|
if (c == null)
|
||||||
throw new System.ApplicationException($"Error updating existing Customer: {customerBiz.GetErrorsAsString()} vendor data :{vn.VendorData}");
|
throw new System.ApplicationException($"Error updating existing Customer: {customerBiz.GetErrorsAsString()} vendor data :{vn.VendorData}");
|
||||||
@@ -167,24 +173,23 @@ namespace Sockeye.Biz
|
|||||||
//ok, turn this into a fully realized Purchase record
|
//ok, turn this into a fully realized Purchase record
|
||||||
|
|
||||||
//Product group
|
//Product group
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
var err = $"ParseVendorNotificationData: Purchase record {vn.Id}-{vn.PurchaseDate} triggered exception, see log";
|
var err = $"ParseVendorNotificationData: Purchase record {vn.Id}-{vn.Created} triggered exception, see log";
|
||||||
await NotifyEventHelper.AddOpsProblemEvent(err);//notify, this is serious
|
await NotifyEventHelper.AddOpsProblemEvent(err);//notify, this is serious
|
||||||
log.LogError(ex, err);
|
log.LogError(ex, err);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void UpdateCustomerFromVendorData(JObject jData, string jCustomerEmail, Customer c)
|
private static void UpdateCustomerFromVendorData(JObject jData, Customer c)
|
||||||
{
|
{
|
||||||
c.EmailAddress = jCustomerEmail;
|
|
||||||
c.Active = true;//if they just made a purchase they are active even if they weren't before
|
c.Active = true;//if they just made a purchase they are active even if they weren't before
|
||||||
c.DoNotContact = false;//if they just made a purchase they are contactable even if they weren't before
|
c.DoNotContact = false;//if they just made a purchase they are contactable even if they weren't before
|
||||||
c.AccountNumber = jData["order_notification"]["purchase"]["customer_data"]["shopper_id"].Value<string>();//appears to be mycommerce customer id number hopefully static between orders
|
|
||||||
c.Address = c.PostAddress = jData["order_notification"]["purchase"]["customer_data"]["delivery_contact"]["address"]["street1"].Value<string>();
|
c.Address = c.PostAddress = jData["order_notification"]["purchase"]["customer_data"]["delivery_contact"]["address"]["street1"].Value<string>();
|
||||||
c.City = c.PostCity = jData["order_notification"]["purchase"]["customer_data"]["delivery_contact"]["address"]["city"].Value<string>();
|
c.City = c.PostCity = jData["order_notification"]["purchase"]["customer_data"]["delivery_contact"]["address"]["city"].Value<string>();
|
||||||
c.Region = c.PostRegion = jData["order_notification"]["purchase"]["customer_data"]["delivery_contact"]["address"]["state"].Value<string>();
|
c.Region = c.PostRegion = jData["order_notification"]["purchase"]["customer_data"]["delivery_contact"]["address"]["state"].Value<string>();
|
||||||
@@ -201,6 +206,7 @@ namespace Sockeye.Biz
|
|||||||
c.Notes += "\n";
|
c.Notes += "\n";
|
||||||
c.Notes += $"Purchase contact:{firstName} {lastName}, language: {language}\n";
|
c.Notes += $"Purchase contact:{firstName} {lastName}, language: {language}\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user