1230 lines
44 KiB
C#
1230 lines
44 KiB
C#
using System;
|
|
using System.Linq;
|
|
using System.Net.Http;
|
|
using System.Threading.Tasks;
|
|
using Microsoft.EntityFrameworkCore;
|
|
using Microsoft.Extensions.Logging;
|
|
using Newtonsoft.Json.Linq;
|
|
using Sockeye.Models;
|
|
using Sockeye.Util;
|
|
|
|
namespace Sockeye.Biz
|
|
{
|
|
|
|
|
|
/// <summary>
|
|
/// Process vendor notifications
|
|
/// Turn vendordata into fully filled out purchase
|
|
/// attempt to match to existing customer or create one if necessary
|
|
///
|
|
/// A Separate job will make licenses from the new purchases where feasible
|
|
///
|
|
/// </summary>
|
|
internal static class SockBotProcessVendorNotifications
|
|
{
|
|
private static ILogger log = Sockeye.Util.ApplicationLogging.CreateLogger("SockBotProcessVendorNotifications");
|
|
private static DateTime lastSweep = DateTime.MinValue;
|
|
#if (DEBUG)
|
|
private static TimeSpan PROCESS_EVERY_INTERVAL = new TimeSpan(0, 0, 30);//every 30 seconds during development
|
|
#else
|
|
private static TimeSpan PROCESS_EVERY_INTERVAL = new TimeSpan(0, 5, 10);//every 5 minutes
|
|
#endif
|
|
////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// DoSweep
|
|
//
|
|
public static async Task DoWorkAsync()
|
|
{
|
|
//This will get triggered roughly every minute, but we don't want to check that frequently
|
|
if (DateTime.UtcNow - lastSweep < PROCESS_EVERY_INTERVAL)
|
|
return;
|
|
|
|
if (ServerBootConfig.MIGRATING) return;//don't do this during migration (migration is one time only so can remove after up and running)
|
|
|
|
log.LogDebug("Process vendor notifications starting");
|
|
await ProcessVendorNotificationDataIntoPurchases();
|
|
|
|
lastSweep = DateTime.UtcNow;
|
|
}
|
|
|
|
private static async Task ProcessVendorNotificationDataIntoPurchases()
|
|
{
|
|
using (AyContext ct = Sockeye.Util.ServiceProviderProvider.DBContext)
|
|
{
|
|
|
|
//get a list of all actionable vendor notifications
|
|
var vnList = await ct.VendorNotification
|
|
.Where(z => z.Processed == null)
|
|
.OrderBy(z => z.Id)
|
|
.ToListAsync();
|
|
|
|
try
|
|
{
|
|
foreach (var vn in vnList)
|
|
{
|
|
log.LogDebug($"Processing vendor notification {vn.Id}-{vn.Created}");
|
|
if (string.IsNullOrWhiteSpace(vn.VendorData))
|
|
{
|
|
var err = $"VendorNotification record {vn.Id}-{vn.Created} has no vendor data";
|
|
await NotifyEventHelper.AddOpsProblemEvent("SockBotProcessVendorNotifications: " + err);
|
|
log.LogError(err);
|
|
continue;
|
|
}
|
|
//Parse json vendordata
|
|
if (await ParseVendorNotificationData(vn, ct, log))
|
|
{
|
|
//success, save vendornotification as processed
|
|
vn.Processed = DateTime.UtcNow;
|
|
await ct.SaveChangesAsync();
|
|
}
|
|
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
var err = "SockBotProcessVendorNotifications error running job";
|
|
//serious issue requires immediate notification
|
|
await NotifyEventHelper.AddOpsProblemEvent(err, ex);
|
|
log.LogError(ex, err);
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
|
|
internal static async Task<bool> ParseVendorNotificationData(VendorNotification vn, AyContext ct, ILogger log)
|
|
{
|
|
|
|
try
|
|
{
|
|
var jData = JObject.Parse(vn.VendorData);
|
|
|
|
//It's a test purchase, no need to process it any further...or is there??
|
|
bool IsTestOrder = false;
|
|
if (jData["order_notification"]["purchase"]["is_test"] != null && jData["order_notification"]["purchase"]["is_test"].Value<bool>() == true)
|
|
IsTestOrder = true;
|
|
|
|
//fundamentally validate the object is a purchase notification
|
|
if (jData["order_notification"]["purchase"]["purchase_id"] == null)
|
|
{
|
|
//this is not the expected format data, stop processing and alert:
|
|
throw new System.FormatException($"Vendor data unexpected format:{vn.VendorData}");
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////
|
|
#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}");
|
|
if (jData["order_notification"]["purchase"]["customer_data"]["delivery_contact"]["email"] == null)//we can't process orders with no email at all hard no
|
|
throw new System.FormatException($"Vendor data empty email:{vn.VendorData}");
|
|
var jCustomerEmail = jData["order_notification"]["purchase"]["customer_data"]["delivery_contact"]["email"].Value<string>();
|
|
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);
|
|
|
|
//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 customer = await ct.Customer.AsNoTracking().FirstOrDefaultAsync(z => z.AccountNumber == jCustomerAccountNumber)
|
|
?? await ct.Customer.AsNoTracking().FirstOrDefaultAsync(z => z.Name.StartsWith(jCustomerName))
|
|
?? await ct.Customer.AsNoTracking().FirstOrDefaultAsync(z => z.EmailAddress == jCustomerEmail);
|
|
if (customer == null)
|
|
{
|
|
//New customer
|
|
customer = new Customer();
|
|
customer.Name = jCustomerName;
|
|
customer.EmailAddress = jCustomerEmail;
|
|
customer.AccountNumber = jCustomerAccountNumber;
|
|
UpdateCustomerFromVendorData(jData, customer);
|
|
customer = await customerBiz.CreateAsync(customer);
|
|
if (customer == null)
|
|
throw new System.ApplicationException($"Error creating new Customer: {customerBiz.GetErrorsAsString()} vendor data :{vn.VendorData}");
|
|
}
|
|
else
|
|
{
|
|
//existing customer
|
|
//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 unfortunately normal as users may re-buy again with new account or buy an addon with a new account
|
|
//so the vendor account nubmer should just be the most recent for finding them purposes I guess
|
|
//
|
|
if (customer.EmailAddress != jCustomerEmail)
|
|
customer.EmailAddress = jCustomerEmail;//assume it was empty or has been recently updated
|
|
|
|
if (customer.AccountNumber != jCustomerAccountNumber)
|
|
customer.AccountNumber = jCustomerAccountNumber;//see above
|
|
|
|
|
|
//refresh
|
|
UpdateCustomerFromVendorData(jData, customer);
|
|
customer = await customerBiz.PutAsync(customer);
|
|
if (customer == null)
|
|
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>();
|
|
if (IsTestOrder)
|
|
salesOrderNumber = "test-order-" + salesOrderNumber;
|
|
#if (DEBUG)
|
|
salesOrderNumber += "-debug-test";
|
|
#endif
|
|
|
|
//https://www.newtonsoft.com/json/help/html/DatesInJSON.htm
|
|
var purchaseDate = jData["order_notification"]["purchase"]["purchase_date"].Value<DateTime>();
|
|
|
|
if (await ct.Purchase.AnyAsync(z => z.SalesOrderNumber == salesOrderNumber))
|
|
throw new System.ApplicationException($"Sales order already exists: {salesOrderNumber} will not be processed");
|
|
|
|
//iterate purchase items array
|
|
var jaPurchaseList = (JArray)jData["order_notification"]["purchase"]["purchase_item"];
|
|
|
|
foreach (JObject jPurchase in jaPurchaseList)
|
|
{
|
|
Purchase p = new Purchase();
|
|
p.PurchaseDate = purchaseDate;
|
|
p.CustomerId = customer.Id;
|
|
p.VendorId = vn.VendorId;
|
|
p.SalesOrderNumber = salesOrderNumber;
|
|
var SalesItemProductVendorCode = jPurchase["product_id"].Value<string>();
|
|
var product = await ct.Product.AsNoTracking().FirstOrDefaultAsync(z => z.VendorCode == SalesItemProductVendorCode) ?? throw new System.ArgumentOutOfRangeException($"Vendor product code:{SalesItemProductVendorCode} was not found in Sockeye Products, record not processed");
|
|
p.ProductId = product.Id;
|
|
p.PGroup = product.PGroup;
|
|
if (jPurchase["accounting"] != null)
|
|
{
|
|
p.Currency = jPurchase["accounting"]["currency"].Value<string>();
|
|
p.ProductNet = jPurchase["accounting"]["product_net"].Value<decimal>();
|
|
p.Discount = jPurchase["accounting"]["discount"].Value<decimal>();
|
|
p.VendorFee = jPurchase["accounting"]["margin_net"].Value<decimal>();
|
|
p.Revenue = jPurchase["accounting"]["your_revenue"].Value<decimal>();
|
|
}
|
|
|
|
//Capture raven database id if present
|
|
if (jPurchase["additional_information"] != null)
|
|
{
|
|
var jaAdditionalItems = (JArray)jPurchase["additional_information"];
|
|
foreach (JObject jAdditionalItem in jaAdditionalItems)
|
|
{
|
|
if (jAdditionalItem["additional_id"] != null && jAdditionalItem["additional_id"].Value<string>() == "DATABASEID")
|
|
{
|
|
p.DbId = jAdditionalItem["additional_value"].Value<string>();
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (jPurchase["promotion_coupon"] != null)
|
|
p.CouponCode = jPurchase["promotion_coupon"].Value<string>();
|
|
|
|
if (jPurchase["promotion"] != null)
|
|
p.CouponCode += $" {jPurchase["promotion"].Value<string>()}";
|
|
|
|
p.Quantity = jPurchase["quantity"].Value<int>();
|
|
p.VendorNotificationId = vn.Id;
|
|
|
|
//it's a subscription?
|
|
if (jPurchase["subscription"] != null && jPurchase["subscription"]["expiration_date"] != null)
|
|
{
|
|
p.ExpireDate = jPurchase["subscription"]["expiration_date"].Value<DateTime>();
|
|
}
|
|
|
|
PurchaseBiz pbiz = PurchaseBiz.GetBiz(ct);
|
|
p = await pbiz.CreateAsync(p);
|
|
if (p == null)
|
|
{
|
|
//did not save, throw an error
|
|
throw new System.ApplicationException($"Error creating purchase: {pbiz.GetErrorsAsString()} for product item: {SalesItemProductVendorCode} vendor data :{vn.VendorData}");
|
|
}
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////
|
|
#endregion make purchase record
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
var err = $"ParseVendorNotificationData: VendorNotification record {vn.Id}-{vn.Created} triggered exception, see log";
|
|
await NotifyEventHelper.AddOpsProblemEvent(err);//notify, this is serious
|
|
log.LogError(ex, err);
|
|
return false;
|
|
}
|
|
return true; //successfully processed so vendor notification should be set to processed by caller
|
|
}
|
|
|
|
private static void UpdateCustomerFromVendorData(JObject jData, Customer c)
|
|
{
|
|
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.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>();
|
|
|
|
//State doesn't always exist in mycommerce notifications
|
|
if (jData["order_notification"]["purchase"]["customer_data"]["delivery_contact"]["address"]["state"] != null)
|
|
c.Region = c.PostRegion = jData["order_notification"]["purchase"]["customer_data"]["delivery_contact"]["address"]["state"].Value<string>();
|
|
c.Country = c.PostCountry = jData["order_notification"]["purchase"]["customer_data"]["delivery_contact"]["address"]["country"].Value<string>();
|
|
c.PostCode = c.AddressPostal = jData["order_notification"]["purchase"]["customer_data"]["delivery_contact"]["address"]["postal_code"].Value<string>();
|
|
var firstName = jData["order_notification"]["purchase"]["customer_data"]["delivery_contact"]["first_name"].Value<string>() ?? "FirstNameEmpty";
|
|
var lastName = jData["order_notification"]["purchase"]["customer_data"]["delivery_contact"]["last_name"].Value<string>() ?? "LastNameEmpty";
|
|
var language = jData["order_notification"]["purchase"]["customer_data"]["language"].Value<string>() ?? "LanguageEmpty";
|
|
if (string.IsNullOrWhiteSpace(c.Notes))
|
|
c.Notes = string.Empty;
|
|
if (!c.Notes.Contains(lastName))
|
|
{
|
|
if (c.Notes.Length > 0 && !c.Notes.EndsWith('\n'))
|
|
c.Notes += "\n";
|
|
c.Notes += $"Purchase contact:{firstName} {lastName}, language: {language}\n";
|
|
}
|
|
|
|
}
|
|
|
|
|
|
#region SAMPLE VENDOR PURCHASE NOTIFICATIONS
|
|
/*
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
////////////////////// V7 MULTIPLE PRODUCTS IN ONE ORDER/////////////////////////////
|
|
|
|
{
|
|
"creation_date": "2023-01-22T23:21:49Z",
|
|
"id": 357678128,
|
|
"order_notification": {
|
|
"purchase": {
|
|
"customer_data": {
|
|
"billing_contact": {
|
|
"address": {
|
|
"city": "Courtenay",
|
|
"country": "Canada",
|
|
"country_id": "CA",
|
|
"postal_code": "V9J9T6",
|
|
"state": "British Columbia",
|
|
"state_id": "BC",
|
|
"street1": "05-3610 Christie Parkway"
|
|
},
|
|
"company": "GZTestCo",
|
|
"email": "gzmailadmin@gmail.com",
|
|
"first_name": "Test",
|
|
"last_name": "Testerson"
|
|
},
|
|
"customer_payment_data": {
|
|
"currency": "USD",
|
|
"payment_method": "Other"
|
|
},
|
|
"delivery_contact": {
|
|
"address": {
|
|
"city": "Courtenay",
|
|
"country": "Canada",
|
|
"country_id": "CA",
|
|
"postal_code": "V9J9T6",
|
|
"state": "British Columbia",
|
|
"state_id": "BC",
|
|
"street1": "05-3610 Christie Parkway"
|
|
},
|
|
"company": "GZTestCo",
|
|
"email": "gzmailadmin@gmail.com",
|
|
"first_name": "Test",
|
|
"last_name": "Testerson"
|
|
},
|
|
"language": "English",
|
|
"language_iso": "en",
|
|
"reg_name": "GZTestCo",
|
|
"shopper_id": "65860321",
|
|
"subscribe_newsletter": false,
|
|
"user_id": "gzmailadmin@gmail.com-38"
|
|
},
|
|
"is_test": true,
|
|
"payment_complete_date": "2023-01-22T23:21:48Z",
|
|
"payment_status": "testpaymentarrived",
|
|
"payment_status_id": "TCA",
|
|
"purchase_date": "2023-01-22T23:21:47Z",
|
|
"purchase_id": 843671213,
|
|
"purchase_item": [
|
|
{
|
|
"additional_information": [
|
|
{
|
|
"additional_id": "ADDITIONAL1",
|
|
"additional_value": "YES"
|
|
},
|
|
{
|
|
"additional_id": "ADDITIONAL2",
|
|
"additional_value": "YES"
|
|
},
|
|
{
|
|
"additional_id": "ADDITIONAL3",
|
|
"additional_value": "YES"
|
|
}
|
|
],
|
|
"currency": "USD",
|
|
"delivery_type": "Electronically",
|
|
"discount": 0.0,
|
|
"extended_download_price": 0.0,
|
|
"manual_order_price": 0.0,
|
|
"notification_no": 0,
|
|
"product_id": 300740317,
|
|
"product_name": "Up to 5 AyaNova schedulable resource 1 year subscription license",
|
|
"product_single_price": 695.0,
|
|
"purchase_item_key": [],
|
|
"quantity": 1,
|
|
"running_no": 1,
|
|
"shipping_price": 0.0,
|
|
"shipping_vat_pct": 0.0,
|
|
"subscription": {
|
|
"expiration_date": "2024-01-22T23:21:48Z",
|
|
"id": "843671213-1",
|
|
"interval": "Yearly without end",
|
|
"renewal_discount_count": "",
|
|
"renewal_discount_start": "",
|
|
"renewal_type": "auto",
|
|
"retention_discount_count": "",
|
|
"retention_discount_percent": "",
|
|
"start_date": "2023-01-23T00:00:00",
|
|
"status": "ToProcess",
|
|
"status_id": "TOP"
|
|
},
|
|
"vat_pct": 12.0
|
|
},
|
|
{
|
|
"additional_information": [
|
|
{
|
|
"additional_id": "ADDITIONAL1",
|
|
"additional_value": "YES"
|
|
},
|
|
{
|
|
"additional_id": "ADDITIONAL2",
|
|
"additional_value": "YES"
|
|
},
|
|
{
|
|
"additional_id": "ADDITIONAL3",
|
|
"additional_value": "YES"
|
|
}
|
|
],
|
|
"currency": "USD",
|
|
"delivery_type": "Electronically",
|
|
"discount": 0.0,
|
|
"extended_download_price": 0.0,
|
|
"manual_order_price": 0.0,
|
|
"notification_no": 0,
|
|
"product_id": 300740314,
|
|
"product_name": "optional add-on AyaNova RI (responsive interface) 1 year subscription license",
|
|
"product_single_price": 199.0,
|
|
"purchase_item_key": [],
|
|
"quantity": 1,
|
|
"running_no": 2,
|
|
"shipping_price": 0.0,
|
|
"shipping_vat_pct": 0.0,
|
|
"subscription": {
|
|
"expiration_date": "2024-01-22T23:21:48Z",
|
|
"id": "843671213-2",
|
|
"interval": "Yearly without end",
|
|
"renewal_discount_count": "",
|
|
"renewal_discount_start": "",
|
|
"renewal_type": "auto",
|
|
"retention_discount_count": "",
|
|
"retention_discount_percent": "",
|
|
"start_date": "2023-01-23T00:00:00",
|
|
"status": "ToProcess",
|
|
"status_id": "TOP"
|
|
},
|
|
"vat_pct": 12.0
|
|
},
|
|
{
|
|
"additional_information": [
|
|
{
|
|
"additional_id": "ADDITIONAL1",
|
|
"additional_value": "YES"
|
|
}
|
|
],
|
|
"currency": "USD",
|
|
"delivery_type": "Electronically",
|
|
"discount": 0.0,
|
|
"extended_download_price": 0.0,
|
|
"manual_order_price": 0.0,
|
|
"notification_no": 0,
|
|
"product_id": 300740321,
|
|
"product_name": "optional add-on AyaNova WBI (web browser interface) 1 year subscription license",
|
|
"product_single_price": 99.0,
|
|
"purchase_item_key": [],
|
|
"quantity": 1,
|
|
"running_no": 3,
|
|
"shipping_price": 0.0,
|
|
"shipping_vat_pct": 0.0,
|
|
"subscription": {
|
|
"expiration_date": "2024-01-22T23:21:48Z",
|
|
"id": "843671213-3",
|
|
"interval": "Yearly without end",
|
|
"renewal_discount_count": "",
|
|
"renewal_discount_start": "",
|
|
"renewal_type": "auto",
|
|
"retention_discount_count": "",
|
|
"retention_discount_percent": "",
|
|
"start_date": "2023-01-23T00:00:00",
|
|
"status": "ToProcess",
|
|
"status_id": "TOP"
|
|
},
|
|
"vat_pct": 12.0
|
|
},
|
|
{
|
|
"additional_information": [
|
|
{
|
|
"additional_id": "ADDITIONAL1",
|
|
"additional_value": "YES"
|
|
}
|
|
],
|
|
"currency": "USD",
|
|
"delivery_type": "Electronically",
|
|
"discount": 0.0,
|
|
"extended_download_price": 0.0,
|
|
"manual_order_price": 0.0,
|
|
"notification_no": 0,
|
|
"product_id": 300740322,
|
|
"product_name": "optional add-on AyaNova MBI (minimal browser interface) 1 year subscription license",
|
|
"product_single_price": 99.0,
|
|
"purchase_item_key": [],
|
|
"quantity": 1,
|
|
"running_no": 4,
|
|
"shipping_price": 0.0,
|
|
"shipping_vat_pct": 0.0,
|
|
"subscription": {
|
|
"expiration_date": "2024-01-22T23:21:48Z",
|
|
"id": "843671213-4",
|
|
"interval": "Yearly without end",
|
|
"renewal_discount_count": "",
|
|
"renewal_discount_start": "",
|
|
"renewal_type": "auto",
|
|
"retention_discount_count": "",
|
|
"retention_discount_percent": "",
|
|
"start_date": "2023-01-23T00:00:00",
|
|
"status": "ToProcess",
|
|
"status_id": "TOP"
|
|
},
|
|
"vat_pct": 12.0
|
|
},
|
|
{
|
|
"additional_information": [
|
|
{
|
|
"additional_id": "ADDITIONAL1",
|
|
"additional_value": "YES"
|
|
}
|
|
],
|
|
"currency": "USD",
|
|
"delivery_type": "Electronically",
|
|
"discount": 0.0,
|
|
"extended_download_price": 0.0,
|
|
"manual_order_price": 0.0,
|
|
"notification_no": 0,
|
|
"product_id": 300740323,
|
|
"product_name": "optional add-on AyaNova QBI(QuickBooks interface) 1 year subscription license",
|
|
"product_single_price": 99.0,
|
|
"purchase_item_key": [],
|
|
"quantity": 1,
|
|
"running_no": 5,
|
|
"shipping_price": 0.0,
|
|
"shipping_vat_pct": 0.0,
|
|
"subscription": {
|
|
"expiration_date": "2024-01-22T23:21:48Z",
|
|
"id": "843671213-5",
|
|
"interval": "Yearly without end",
|
|
"renewal_discount_count": "",
|
|
"renewal_discount_start": "",
|
|
"renewal_type": "auto",
|
|
"retention_discount_count": "",
|
|
"retention_discount_percent": "",
|
|
"start_date": "2023-01-23T00:00:00",
|
|
"status": "ToProcess",
|
|
"status_id": "TOP"
|
|
},
|
|
"vat_pct": 12.0
|
|
}
|
|
],
|
|
"purchase_origin": "online"
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
//////////////////////v7 export to xls add on/////////////////////////////
|
|
{
|
|
"creation_date": "2023-01-20T00:18:33Z",
|
|
"id": 357520816,
|
|
"order_notification": {
|
|
"purchase": {
|
|
"customer_data": {
|
|
"billing_contact": {
|
|
"address": {
|
|
"city": "Cambridge",
|
|
"country": "Canada",
|
|
"country_id": "CA",
|
|
"postal_code": "N1T 1J3",
|
|
"state": "Ontario",
|
|
"state_id": "ON",
|
|
"street1": "181 Shearson Crescent"
|
|
},
|
|
"company": "Cambridge Elevating Inc",
|
|
"email": "richard.wright@cambridgeelevating.com",
|
|
"first_name": "Richard",
|
|
"last_name": "Wright"
|
|
},
|
|
"customer_payment_data": {
|
|
"currency": "USD",
|
|
"payment_method": "MasterCard"
|
|
},
|
|
"delivery_contact": {
|
|
"address": {
|
|
"city": "Cambridge",
|
|
"country": "Canada",
|
|
"country_id": "CA",
|
|
"postal_code": "N1T 1J3",
|
|
"state": "Ontario",
|
|
"state_id": "ON",
|
|
"street1": "181 Shearson Crescent"
|
|
},
|
|
"company": "Cambridge Elevating Inc",
|
|
"email": "richard.wright@cambridgeelevating.com",
|
|
"first_name": "Richard",
|
|
"last_name": "Wright"
|
|
},
|
|
"language": "English",
|
|
"language_iso": "en",
|
|
"reg_name": "Cambridge Elevating Inc",
|
|
"shopper_id": "62545677",
|
|
"subscribe_newsletter": false,
|
|
"user_id": "richard.wright@cambridgeelevating.com-5"
|
|
},
|
|
"is_test": false,
|
|
"payment_complete_date": "2023-01-20T00:18:33Z",
|
|
"payment_status": "complete",
|
|
"payment_status_id": "PCA",
|
|
"purchase_date": "2023-01-20T00:18:31Z",
|
|
"purchase_id": 843101393,
|
|
"purchase_item": [
|
|
{
|
|
"accounting": {
|
|
"currency": "USD",
|
|
"product_net": 6.65,
|
|
"discount": 0.0,
|
|
"product_vat": 0.86,
|
|
"shipping": 0.0,
|
|
"shipping_vat": 0.0,
|
|
"eu_vat": -0.86,
|
|
"margin_net": -2.5,
|
|
"your_revenue": 4.15
|
|
},
|
|
"additional_information": [
|
|
{
|
|
"additional_id": "ADDITIONAL1",
|
|
"additional_value": "YES"
|
|
}
|
|
],
|
|
"currency": "USD",
|
|
"delivery_type": "Electronically",
|
|
"discount": 0.0,
|
|
"extended_download_price": 0.0,
|
|
"manual_order_price": 0.0,
|
|
"notification_no": 7953,
|
|
"product_id": 300740327,
|
|
"product_name": "optional add-on plug-in Export to XLS 1 year subscription license",
|
|
"product_single_price": 6.65,
|
|
"purchase_item_key": [],
|
|
"quantity": 1,
|
|
"running_no": 1,
|
|
"shipping_price": 0.0,
|
|
"shipping_vat_pct": 0.0,
|
|
"subscription": {
|
|
"expiration_date": "2024-01-20T18:36:22Z",
|
|
"id": "771160083-3",
|
|
"interval": "Yearly without end",
|
|
"original_notification_no": "7779",
|
|
"original_purchase_id": "771160083",
|
|
"original_running_no": "3",
|
|
"renewal_discount_count": "",
|
|
"renewal_discount_start": "",
|
|
"renewal_type": "auto",
|
|
"retention_discount_count": "",
|
|
"retention_discount_percent": "",
|
|
"start_date": "2022-01-20T00:00:00",
|
|
"status": "ToProcess",
|
|
"status_id": "TOP"
|
|
},
|
|
"vat_pct": 13.0
|
|
}
|
|
],
|
|
"purchase_origin": "Subscription",
|
|
"sequential_invoice_no": "e5-DE-2023-00000163106"
|
|
}
|
|
}
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
///////////////////////////////////// V7 Scheduleable user //////////////////////
|
|
|
|
{
|
|
"creation_date": "2023-01-20T00:18:32Z",
|
|
"id": 357520809,
|
|
"order_notification": {
|
|
"purchase": {
|
|
"customer_data": {
|
|
"billing_contact": {
|
|
"address": {
|
|
"city": "Cambridge",
|
|
"country": "Canada",
|
|
"country_id": "CA",
|
|
"postal_code": "N1T 1J3",
|
|
"state": "Ontario",
|
|
"state_id": "ON",
|
|
"street1": "181 Shearson Crescent"
|
|
},
|
|
"company": "Cambridge Elevating Inc",
|
|
"email": "richard.wright@cambridgeelevating.com",
|
|
"first_name": "Richard",
|
|
"last_name": "Wright"
|
|
},
|
|
"customer_payment_data": {
|
|
"currency": "USD",
|
|
"payment_method": "MasterCard"
|
|
},
|
|
"delivery_contact": {
|
|
"address": {
|
|
"city": "Cambridge",
|
|
"country": "Canada",
|
|
"country_id": "CA",
|
|
"postal_code": "N1T 1J3",
|
|
"state": "Ontario",
|
|
"state_id": "ON",
|
|
"street1": "181 Shearson Crescent"
|
|
},
|
|
"company": "Cambridge Elevating Inc",
|
|
"email": "richard.wright@cambridgeelevating.com",
|
|
"first_name": "Richard",
|
|
"last_name": "Wright"
|
|
},
|
|
"language": "English",
|
|
"language_iso": "en",
|
|
"reg_name": "Cambridge Elevating Inc",
|
|
"shopper_id": "62545677",
|
|
"subscribe_newsletter": false,
|
|
"user_id": "richard.wright@cambridgeelevating.com-5"
|
|
},
|
|
"is_test": false,
|
|
"payment_complete_date": "2023-01-20T00:18:32Z",
|
|
"payment_status": "complete",
|
|
"payment_status_id": "PCA",
|
|
"purchase_date": "2023-01-20T00:18:31Z",
|
|
"purchase_id": 843101383,
|
|
"purchase_item": [
|
|
{
|
|
"accounting": {
|
|
"currency": "USD",
|
|
"product_net": 577.5,
|
|
"discount": 0.0,
|
|
"product_vat": 75.08,
|
|
"shipping": 0.0,
|
|
"shipping_vat": 0.0,
|
|
"eu_vat": -75.08,
|
|
"margin_net": -29.05,
|
|
"your_revenue": 548.45
|
|
},
|
|
"additional_information": [
|
|
{
|
|
"additional_id": "ADDITIONAL1",
|
|
"additional_value": "YES"
|
|
},
|
|
{
|
|
"additional_id": "ADDITIONAL2",
|
|
"additional_value": "YES"
|
|
},
|
|
{
|
|
"additional_id": "ADDITIONAL3",
|
|
"additional_value": "YES"
|
|
}
|
|
],
|
|
"currency": "USD",
|
|
"delivery_type": "Electronically",
|
|
"discount": 0.0,
|
|
"extended_download_price": 0.0,
|
|
"manual_order_price": 0.0,
|
|
"notification_no": 7952,
|
|
"product_id": 300807973,
|
|
"product_name": "Up to 15 AyaNova schedulable resource 1 year subscription license",
|
|
"product_single_price": 577.5,
|
|
"purchase_item_key": [],
|
|
"quantity": 1,
|
|
"running_no": 1,
|
|
"shipping_price": 0.0,
|
|
"shipping_vat_pct": 0.0,
|
|
"subscription": {
|
|
"expiration_date": "2024-01-20T18:36:22Z",
|
|
"id": "771160083-1",
|
|
"interval": "Yearly without end",
|
|
"original_notification_no": "7777",
|
|
"original_purchase_id": "771160083",
|
|
"original_running_no": "1",
|
|
"renewal_discount_count": "",
|
|
"renewal_discount_start": "",
|
|
"renewal_type": "auto",
|
|
"retention_discount_count": "",
|
|
"retention_discount_percent": "",
|
|
"start_date": "2022-01-20T00:00:00",
|
|
"status": "ToProcess",
|
|
"status_id": "TOP"
|
|
},
|
|
"vat_pct": 13.0
|
|
}
|
|
],
|
|
"purchase_origin": "Subscription",
|
|
"sequential_invoice_no": "e5-DE-2023-00000163105"
|
|
}
|
|
}
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
//////////////////// NOT A LICENSE PRODUCT - CUSTOMIZATION SERVICES FOR REPORT TEMPLATE
|
|
|
|
{
|
|
"creation_date": "2023-01-18T15:45:50Z",
|
|
"id": 357446088,
|
|
"order_notification": {
|
|
"purchase": {
|
|
"customer_data": {
|
|
"billing_contact": {
|
|
"address": {
|
|
"city": "Brunswick",
|
|
"country": "USA",
|
|
"country_id": "US",
|
|
"postal_code": "38014",
|
|
"state": "Tennessee",
|
|
"state_id": "TN",
|
|
"street1": "PO Box 374"
|
|
},
|
|
"company": "Tri-Star Medical Technologies LLC",
|
|
"email": "stan@tri-starmedical.com",
|
|
"first_name": "Stan",
|
|
"last_name": "Hilton"
|
|
},
|
|
"customer_payment_data": {
|
|
"currency": "USD",
|
|
"payment_method": "Visa"
|
|
},
|
|
"delivery_contact": {
|
|
"address": {
|
|
"city": "Brunswick",
|
|
"country": "USA",
|
|
"country_id": "US",
|
|
"postal_code": "38014",
|
|
"state": "Tennessee",
|
|
"state_id": "TN",
|
|
"street1": "PO Box 374"
|
|
},
|
|
"company": "Tri-Star Medical Technologies LLC",
|
|
"email": "stan@tri-starmedical.com",
|
|
"first_name": "Stan",
|
|
"last_name": "Hilton"
|
|
},
|
|
"language": "English",
|
|
"language_iso": "en",
|
|
"reg_name": "Tri-Star Medical Technologies LLC",
|
|
"shopper_id": "65821033",
|
|
"subscribe_newsletter": false,
|
|
"user_id": "stan@tri-starmedical.com-1"
|
|
},
|
|
"is_test": false,
|
|
"payment_complete_date": "2023-01-18T15:45:49Z",
|
|
"payment_status": "complete",
|
|
"payment_status_id": "PCA",
|
|
"purchase_date": "2023-01-18T15:45:48Z",
|
|
"purchase_id": 842819563,
|
|
"purchase_item": [
|
|
{
|
|
"accounting": {
|
|
"currency": "USD",
|
|
"product_net": 50.0,
|
|
"discount": 0.0,
|
|
"product_vat": 4.63,
|
|
"shipping": 0.0,
|
|
"shipping_vat": 0.0,
|
|
"eu_vat": -4.63,
|
|
"margin_net": -5.14,
|
|
"your_revenue": 44.86
|
|
},
|
|
"additional_information": [],
|
|
"currency": "USD",
|
|
"delivery_type": "Electronically",
|
|
"discount": 0.0,
|
|
"extended_download_price": 0.0,
|
|
"manual_order_price": 0.0,
|
|
"notification_no": 7945,
|
|
"product_id": 300525428,
|
|
"product_name": "AyaNova customization services",
|
|
"product_single_price": 50.0,
|
|
"purchase_item_key": [],
|
|
"quantity": 1,
|
|
"running_no": 1,
|
|
"shipping_price": 0.0,
|
|
"shipping_vat_pct": 0.0,
|
|
"vat_pct": 9.25
|
|
}
|
|
],
|
|
"purchase_origin": "online",
|
|
"sequential_invoice_no": "e5-US-2023-00000083100"
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
////////////////////////////// TEST PURCHASE USING SPECIAL TEST CREDIT CARD NUMBER PROVIDED BY MYCOMMERCE
|
|
{
|
|
"creation_date": "2023-01-18T04:24:28Z",
|
|
"id": 357424814,
|
|
"order_notification": {
|
|
"purchase": {
|
|
"customer_data": {
|
|
"billing_contact": {
|
|
"address": {
|
|
"city": "Courtenay",
|
|
"country": "Canada",
|
|
"country_id": "CA",
|
|
"postal_code": "V9J9T6",
|
|
"state": "British Columbia",
|
|
"state_id": "BC",
|
|
"street1": "05-3610 Christie Parkway"
|
|
},
|
|
"company": "GZTestCo",
|
|
"email": "gzmailadmin@gmail.com",
|
|
"first_name": "Test",
|
|
"last_name": "Testerson"
|
|
},
|
|
"customer_payment_data": {
|
|
"currency": "USD",
|
|
"payment_method": "Other"
|
|
},
|
|
"delivery_contact": {
|
|
"address": {
|
|
"city": "Courtenay",
|
|
"country": "Canada",
|
|
"country_id": "CA",
|
|
"postal_code": "V9J9T6",
|
|
"state": "British Columbia",
|
|
"state_id": "BC",
|
|
"street1": "05-3610 Christie Parkway"
|
|
},
|
|
"company": "GZTestCo",
|
|
"email": "gzmailadmin@gmail.com",
|
|
"first_name": "Test",
|
|
"last_name": "Testerson"
|
|
},
|
|
"language": "English",
|
|
"language_iso": "en",
|
|
"reg_name": "GZTestCo",
|
|
"shopper_id": "65817245",
|
|
"subscribe_newsletter": false,
|
|
"user_id": "gzmailadmin@gmail.com-36"
|
|
},
|
|
"is_test": true,
|
|
"payment_complete_date": "2023-01-18T04:24:28Z",
|
|
"payment_status": "testpaymentarrived",
|
|
"payment_status_id": "TCA",
|
|
"purchase_date": "2023-01-18T04:24:28Z",
|
|
"purchase_id": 842769483,
|
|
"purchase_item": [
|
|
{
|
|
"additional_information": [],
|
|
"currency": "USD",
|
|
"delivery_type": "Electronically",
|
|
"discount": 0.0,
|
|
"extended_download_price": 0.0,
|
|
"manual_order_price": 0.0,
|
|
"notification_no": 0,
|
|
"product_id": 300525428,
|
|
"product_name": "AyaNova customization services",
|
|
"product_single_price": 50.0,
|
|
"purchase_item_key": [],
|
|
"quantity": 1,
|
|
"running_no": 1,
|
|
"shipping_price": 0.0,
|
|
"shipping_vat_pct": 0.0,
|
|
"vat_pct": 12.0
|
|
}
|
|
],
|
|
"purchase_origin": "online"
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
//////////////////////////////// RAVEN PERPETUAL
|
|
|
|
{
|
|
"creation_date": "2023-01-14T06:17:59Z",
|
|
"id": 357214426,
|
|
"order_notification": {
|
|
"purchase": {
|
|
"customer_data": {
|
|
"billing_contact": {
|
|
"address": {
|
|
"city": "Frankfort",
|
|
"country": "USA",
|
|
"country_id": "US",
|
|
"postal_code": "46041",
|
|
"state": "Indiana",
|
|
"state_id": "IN",
|
|
"street1": "47 N Jackson St."
|
|
},
|
|
"company": "ACCS",
|
|
"email": "internet@accs.net",
|
|
"first_name": "Marcus",
|
|
"last_name": "Hodges"
|
|
},
|
|
"customer_payment_data": {
|
|
"currency": "USD",
|
|
"payment_method": "Visa"
|
|
},
|
|
"delivery_contact": {
|
|
"address": {
|
|
"city": "Frankfort",
|
|
"country": "USA",
|
|
"country_id": "US",
|
|
"postal_code": "46041",
|
|
"state": "Indiana",
|
|
"state_id": "IN",
|
|
"street1": "47 N Jackson St."
|
|
},
|
|
"company": "ACCS",
|
|
"email": "internet@accs.net",
|
|
"first_name": "Marcus",
|
|
"last_name": "Hodges"
|
|
},
|
|
"language": "English",
|
|
"language_iso": "en",
|
|
"reg_name": "ACCS",
|
|
"shopper_id": "65783365",
|
|
"subscribe_newsletter": false,
|
|
"user_id": "internet@accs.net"
|
|
},
|
|
"is_test": false,
|
|
"payment_complete_date": "2023-01-14T06:17:59Z",
|
|
"payment_status": "complete",
|
|
"payment_status_id": "PCA",
|
|
"purchase_date": "2023-01-14T06:17:58Z",
|
|
"purchase_id": 841935113,
|
|
"purchase_item": [
|
|
{
|
|
"accounting": {
|
|
"currency": "USD",
|
|
"product_net": 72.0,
|
|
"discount": 0.0,
|
|
"product_vat": 5.04,
|
|
"shipping": 0.0,
|
|
"shipping_vat": 0.0,
|
|
"eu_vat": -5.04,
|
|
"margin_net": -6.03,
|
|
"your_revenue": 65.97
|
|
},
|
|
"additional_information": [
|
|
{
|
|
"additional_id": "AGREENOREFUNDS",
|
|
"additional_value": "YES"
|
|
},
|
|
{
|
|
"additional_id": "AGREEPAYMETHODVALIDCANCEL",
|
|
"additional_value": "YES"
|
|
},
|
|
{
|
|
"additional_id": "AGREEEXPIRESIFNOTPAID",
|
|
"additional_value": "YES"
|
|
},
|
|
{
|
|
"additional_id": "DATABASEID",
|
|
"additional_value": "7ktPA+Eaq+LM4vNMkQdbwBkUMDzzFYXmH+m21n3w5Rk="
|
|
}
|
|
],
|
|
"currency": "USD",
|
|
"delivery_type": "Electronically",
|
|
"discount": 0.0,
|
|
"extended_download_price": 0.0,
|
|
"manual_order_price": 0.0,
|
|
"notification_no": 7944,
|
|
"product_id": 301028317,
|
|
"product_name": "AyaNova perpetual single user license includes one year maintenance plan ",
|
|
"product_single_price": 24.0,
|
|
"purchase_item_key": [],
|
|
"quantity": 3,
|
|
"running_no": 1,
|
|
"shipping_price": 0.0,
|
|
"shipping_vat_pct": 0.0,
|
|
"subscription": {
|
|
"expiration_date": "2024-01-14T06:17:59Z",
|
|
"id": "841935113-1",
|
|
"interval": "Yearly without end",
|
|
"renewal_discount_count": "",
|
|
"renewal_discount_start": "",
|
|
"renewal_type": "auto",
|
|
"retention_discount_count": "",
|
|
"retention_discount_percent": "",
|
|
"start_date": "2023-01-14T00:00:00",
|
|
"status": "ToProcess",
|
|
"status_id": "TOP"
|
|
},
|
|
"vat_pct": 7.0,
|
|
"your_product_id": "perpetual"
|
|
}
|
|
],
|
|
"purchase_origin": "online",
|
|
"sequential_invoice_no": "e5-US-2023-00000064245"
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
///////////////////////////////// RAVEN MONTHLY SUBSCRIPTION
|
|
{
|
|
"creation_date": "2023-01-07T01:54:11Z",
|
|
"id": 356798113,
|
|
"order_notification": {
|
|
"purchase": {
|
|
"customer_data": {
|
|
"billing_contact": {
|
|
"address": {
|
|
"city": "UNIONVILLE",
|
|
"country": "Canada",
|
|
"country_id": "CA",
|
|
"postal_code": "L3R 9W6",
|
|
"state": "Ontario",
|
|
"state_id": "ON",
|
|
"street1": "4261 HWY 7 E, Unit A14 #399"
|
|
},
|
|
"company": "sportseffect",
|
|
"email": "service@sportseffect.com",
|
|
"first_name": "Mark",
|
|
"last_name": "Hopkins"
|
|
},
|
|
"customer_payment_data": {
|
|
"currency": "CAD",
|
|
"payment_method": "Visa"
|
|
},
|
|
"delivery_contact": {
|
|
"address": {
|
|
"city": "UNIONVILLE",
|
|
"country": "Canada",
|
|
"country_id": "CA",
|
|
"postal_code": "L3R 9W6",
|
|
"state": "Ontario",
|
|
"state_id": "ON",
|
|
"street1": "4261 HWY 7 E, Unit A14 #399"
|
|
},
|
|
"company": "sportseffect",
|
|
"email": "service@sportseffect.com",
|
|
"first_name": "Mark",
|
|
"last_name": "Hopkins"
|
|
},
|
|
"language": "English",
|
|
"language_iso": "en",
|
|
"reg_name": "sportseffect",
|
|
"shopper_id": "65387076",
|
|
"subscribe_newsletter": false,
|
|
"user_id": "service@sportseffect.com"
|
|
},
|
|
"is_test": false,
|
|
"payment_complete_date": "2023-01-07T01:54:11Z",
|
|
"payment_status": "complete",
|
|
"payment_status_id": "PCA",
|
|
"purchase_date": "2023-01-07T01:54:09Z",
|
|
"purchase_id": 840549123,
|
|
"purchase_item": [
|
|
{
|
|
"accounting": {
|
|
"currency": "USD",
|
|
"product_net": 23.8,
|
|
"discount": 0.0,
|
|
"product_vat": 3.09,
|
|
"shipping": 0.0,
|
|
"shipping_vat": 0.0,
|
|
"eu_vat": -3.09,
|
|
"margin_net": -4.03,
|
|
"your_revenue": 19.77
|
|
},
|
|
"additional_information": [
|
|
{
|
|
"additional_id": "AGREENOREFUNDS",
|
|
"additional_value": "YES"
|
|
},
|
|
{
|
|
"additional_id": "AGREEPAYMETHODVALIDCANCEL",
|
|
"additional_value": "YES"
|
|
},
|
|
{
|
|
"additional_id": "AGREEEXPIRESIFNOTPAID",
|
|
"additional_value": "YES"
|
|
},
|
|
{
|
|
"additional_id": "DATABASEID",
|
|
"additional_value": "New subscription"
|
|
}
|
|
],
|
|
"currency": "USD",
|
|
"delivery_type": "Electronically",
|
|
"discount": 0.0,
|
|
"extended_download_price": 0.0,
|
|
"manual_order_price": 0.0,
|
|
"notification_no": 7937,
|
|
"product_id": 301028467,
|
|
"product_name": "AyaNova subscription one user monthly",
|
|
"product_single_price": 11.9,
|
|
"purchase_item_key": [],
|
|
"quantity": 2,
|
|
"running_no": 1,
|
|
"shipping_price": 0.0,
|
|
"shipping_vat_pct": 0.0,
|
|
"subscription": {
|
|
"expiration_date": "2023-02-07T00:15:13Z",
|
|
"id": "833674953-1",
|
|
"interval": "Monthly without end",
|
|
"original_notification_no": "7925",
|
|
"original_purchase_id": "833674953",
|
|
"original_running_no": "1",
|
|
"renewal_discount_count": "",
|
|
"renewal_discount_start": "",
|
|
"renewal_type": "auto",
|
|
"retention_discount_count": "",
|
|
"retention_discount_percent": "",
|
|
"start_date": "2022-12-07T00:00:00",
|
|
"status": "ToProcess",
|
|
"status_id": "TOP"
|
|
},
|
|
"vat_pct": 13.0,
|
|
"your_product_id": "subscriptionmonthly"
|
|
}
|
|
],
|
|
"purchase_origin": "Subscription",
|
|
"sequential_invoice_no": "e5-DE-2023-00000055949"
|
|
}
|
|
}
|
|
}
|
|
|
|
*/
|
|
|
|
#endregion sample vendor notifications
|
|
//order notification json schema on this page down
|
|
//actual schema: https://api.shareit.com/xml/2.4/ordernotification.xsd
|
|
//https://account.mycommerce.com/home/wiki/7479997 //json format
|
|
//https://account.mycommerce.com/home/wiki/7479805 //overall info
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////
|
|
|
|
}//eoc
|
|
|
|
|
|
}//eons
|
|
|