This commit is contained in:
@@ -352,7 +352,8 @@ namespace Sockeye.Biz
|
|||||||
#if (DEBUG)
|
#if (DEBUG)
|
||||||
//Test dev stuff
|
//Test dev stuff
|
||||||
#warning DEV TEST ORDER PROCESSING REMOVE THIS WHEN DONE
|
#warning DEV TEST ORDER PROCESSING REMOVE THIS WHEN DONE
|
||||||
await SockBotProcessVendorNotifications.ParseVendorNotificationData(vn, ct, log);
|
if (!string.IsNullOrWhiteSpace(vn.VendorData))
|
||||||
|
await SockBotProcessVendorNotifications.ParseVendorNotificationData(vn, ct, log);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
@@ -793,7 +794,7 @@ namespace Sockeye.Biz
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
}//eoc
|
}//eoc
|
||||||
|
|||||||
@@ -51,7 +51,6 @@ namespace Sockeye.Biz
|
|||||||
|
|
||||||
//get a list of all actionable vendor notifications
|
//get a list of all actionable vendor notifications
|
||||||
var vnList = await ct.VendorNotification
|
var vnList = await ct.VendorNotification
|
||||||
.AsNoTracking()
|
|
||||||
.Where(z => z.Processed == null)
|
.Where(z => z.Processed == null)
|
||||||
.OrderBy(z => z.Id)
|
.OrderBy(z => z.Id)
|
||||||
.ToListAsync();
|
.ToListAsync();
|
||||||
@@ -60,8 +59,7 @@ namespace Sockeye.Biz
|
|||||||
{
|
{
|
||||||
foreach (var vn in vnList)
|
foreach (var vn in vnList)
|
||||||
{
|
{
|
||||||
var biz = PurchaseBiz.GetBiz(ct);
|
|
||||||
var p = new Purchase();
|
|
||||||
|
|
||||||
log.LogDebug($"Processing vendor notification {vn.Id}-{vn.Created}");
|
log.LogDebug($"Processing vendor notification {vn.Id}-{vn.Created}");
|
||||||
|
|
||||||
@@ -73,15 +71,9 @@ namespace Sockeye.Biz
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//Parse json vendordata
|
//Parse json vendordata
|
||||||
await ParseVendorNotificationData(vn, ct, log);
|
await ParseVendorNotificationData(vn, ct, log);
|
||||||
|
|
||||||
//save changes
|
|
||||||
p.Processed = true;
|
|
||||||
await biz.PutAsync(p);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
@@ -97,14 +89,17 @@ namespace Sockeye.Biz
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
internal static async Task ParseVendorNotificationData(VendorNotification vn, AyContext ct, ILogger log)
|
internal static async Task<bool> ParseVendorNotificationData(VendorNotification vn, AyContext ct, ILogger log)
|
||||||
{
|
{
|
||||||
|
|
||||||
if (string.IsNullOrWhiteSpace(vn.VendorData)) return;
|
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var jData = JObject.Parse(vn.VendorData);
|
var jData = JObject.Parse(vn.VendorData);
|
||||||
|
//It's a test purchase, no need to process it any further...or is there??
|
||||||
|
if (jData["order_notification"]["purchase"]["is_test"].Value<bool>() == true)
|
||||||
|
{
|
||||||
|
vn.Processed = DateTime.UtcNow;
|
||||||
|
}
|
||||||
|
|
||||||
//fundamentally validate the object is a purchase notification
|
//fundamentally validate the object is a purchase notification
|
||||||
if (jData["order_notification"]["purchase"]["purchase_id"] == null)
|
if (jData["order_notification"]["purchase"]["purchase_id"] == null)
|
||||||
@@ -113,7 +108,11 @@ namespace Sockeye.Biz
|
|||||||
throw new System.FormatException($"Vendor data unexpected format:{vn.VendorData}");
|
throw new System.FormatException($"Vendor data unexpected format:{vn.VendorData}");
|
||||||
}
|
}
|
||||||
|
|
||||||
//CUSTOMER create or locate
|
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
#region CUSTOMER MAKE OR LOCATED
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
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 jCustomerAccountNumber = jData["order_notification"]["purchase"]["customer_data"]["shopper_id"].Value<string>();//appears to be mycommerce customer id number hopefully static between orders
|
||||||
@@ -122,17 +121,17 @@ namespace Sockeye.Biz
|
|||||||
|
|
||||||
//attempt to match to existing customer
|
//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
|
//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);
|
Customer customer = 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 (customer == null)
|
||||||
{
|
{
|
||||||
//New customer
|
//New customer
|
||||||
c = new Customer();
|
customer = new Customer();
|
||||||
c.Name = jCustomerName;
|
customer.Name = jCustomerName;
|
||||||
c.EmailAddress = jCustomerEmail;
|
customer.EmailAddress = jCustomerEmail;
|
||||||
c.AccountNumber = jCustomerAccountNumber;
|
customer.AccountNumber = jCustomerAccountNumber;
|
||||||
UpdateCustomerFromVendorData(jData, c);
|
UpdateCustomerFromVendorData(jData, customer);
|
||||||
c = await customerBiz.CreateAsync(c);
|
customer = await customerBiz.CreateAsync(customer);
|
||||||
if (c == null)
|
if (customer == 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
|
||||||
@@ -143,47 +142,90 @@ namespace Sockeye.Biz
|
|||||||
//email differs, this can happen and is ok
|
//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:
|
//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)
|
if (customer.EmailAddress != jCustomerEmail)
|
||||||
{
|
{
|
||||||
c.EmailAddress = jCustomerEmail;//assume it was empty or has been recently updated
|
customer.EmailAddress = jCustomerEmail;//assume it was empty or has been recently updated
|
||||||
}
|
}
|
||||||
|
|
||||||
if (c.AccountNumber != jCustomerAccountNumber)
|
if (customer.AccountNumber != jCustomerAccountNumber)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrWhiteSpace(c.AccountNumber))
|
if (string.IsNullOrWhiteSpace(customer.AccountNumber))
|
||||||
c.AccountNumber=jCustomerAccountNumber;//this is ok, there wasn't an account number before so we're just adding it
|
customer.AccountNumber = jCustomerAccountNumber;//this is ok, there wasn't an account number before so we're just adding it
|
||||||
else{
|
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
|
// 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}");
|
throw new System.ApplicationException($"Not processed due to error updating existing Customer: {customer.Name} Account numbers differ, expected: {customer.AccountNumber} vendor data:{vn.VendorData}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//refresh
|
//refresh
|
||||||
UpdateCustomerFromVendorData(jData, c);
|
UpdateCustomerFromVendorData(jData, customer);
|
||||||
c = await customerBiz.PutAsync(c);
|
customer = await customerBiz.PutAsync(customer);
|
||||||
if (c == null)
|
if (customer == 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}");
|
||||||
}
|
}
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
#endregion customer make or locate
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
#region MAKE PURCHASE RECORD
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
var salesOrderNumber = jData["order_notification"]["purchase"]["purchase_id"].Value<string>();
|
var salesOrderNumber = jData["order_notification"]["purchase"]["purchase_id"].Value<string>();
|
||||||
|
|
||||||
if (await ct.Purchase.AnyAsync(z => z.SalesOrderNumber == salesOrderNumber))
|
if (await ct.Purchase.AnyAsync(z => z.SalesOrderNumber == salesOrderNumber))
|
||||||
throw new System.ApplicationException($"Sales order already exists: {salesOrderNumber} will not be processed");
|
throw new System.ApplicationException($"Sales order already exists: {salesOrderNumber} will not be processed");
|
||||||
|
|
||||||
//ok, turn this into a fully realized Purchase record
|
//iterate purchase items array
|
||||||
|
var jaPurchaseList = (JArray)jData["order_notification"]["purchase"]["purchase_item"];
|
||||||
|
|
||||||
//Product group
|
foreach (JObject jPurchase in jaPurchaseList)
|
||||||
p.PGroup = ProductBiz.ProductGroupFromProductCode(p.OurCode);
|
{
|
||||||
|
Purchase p = new Purchase();
|
||||||
|
p.CustomerId = customer.Id;
|
||||||
|
p.VendorId = vn.VendorId;
|
||||||
|
p.Notes = vn.VendorData;//redundantly keep it
|
||||||
|
p.SalesOrderNumber = salesOrderNumber;
|
||||||
|
p.Currency = jPurchase["currency"].Value<string>();
|
||||||
|
var pId = jPurchase["product_id"].Value<string>();
|
||||||
|
var product = await ct.Product.AsNoTracking().FirstOrDefaultAsync(z => z.VendorCode == pId) ?? throw new System.ArgumentOutOfRangeException($"Vendor product code:{pId} was not found in Sockeye Products, record not processed");
|
||||||
|
p.ProductId = product.Id;
|
||||||
|
p.PGroup = product.PGroup;
|
||||||
|
p.
|
||||||
|
|
||||||
|
if (p.ProductId == 0)
|
||||||
|
|
||||||
|
switch (p.PGroup)
|
||||||
|
{
|
||||||
|
case ProductGroup.Misc:
|
||||||
|
//not a licensed product, probably misc custom or some fee or etc
|
||||||
|
p.Processed = true;//flag no further processing is required
|
||||||
|
break;
|
||||||
|
case ProductGroup.AyaNova7:
|
||||||
|
|
||||||
|
break;
|
||||||
|
case ProductGroup.RavenPerpetual:
|
||||||
|
|
||||||
|
break;
|
||||||
|
case ProductGroup.RavenSubscription:
|
||||||
|
|
||||||
|
break;
|
||||||
|
default://not set or unrecognized
|
||||||
|
throw new System.NotSupportedException($"Product group {p.PGroup} not recognized or supported for processing into purchase");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
#endregion make purchase record
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
var err = $"ParseVendorNotificationData: Purchase record {vn.Id}-{vn.Created} 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);
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user