Processor Classes
For each pair of entities that you want to synchronize between an e-commerce system and MYOB Acumatica, you need to create a processor class.
A processor classes perform the following functions:
- Retrieval of the MYOB Acumatica records and external records
- Providing of the default mapping logic
- Providing of the export and import logic
Base Classes and Interface
A processor class implements the PX.Commerce.Core.IProcessor
interface and derives from one of the following base abstract classes:
- PX.Commerce.Core.BCProcessorSingleBase<TGraph, TEntityBucket, TPrimaryMapped>, which is a standard base class for processors that synchronizes records one by one.
- PX.Commerce.Core.BCProcessorBulkBase<TGraph, TEntityBucket, TPrimaryMapped>, which can mass-process records for the entities that require higher performance during synchronization. For example, this base class is used for the processor classes for the availability and price list entities in the BigCommerce connector.
Attributes of the Processor Class
You assign the following attributes to the processor class:
- BCProcessor, which specifies the basic functions of the processor, such as which directions of synchronization are supported by the processor
- Optional: BCProcessorRealtime, which specifies whether the processor works with push notifications and webhooks
Methods of the Processor Class
In the processor class, you implement the methods that perform the following functions:-
The fetching of the records that have been changed in MYOB Acumatica or the external system
-
The checking and merging of duplicated records
-
The handling of real-time processing
-
Other supplementary functions
Example
The following code shows an example of the processor implementation.
Tip: You can see this code on GitHub.
using PX.Commerce.Core;
using PX.Commerce.Core.API;
using PX.Commerce.Objects;
using PX.Data;
using PX.Objects.AR;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
namespace WooCommerceTest
{
[BCProcessor(typeof(WooCommerceConnector), BCEntitiesAttribute.Customer, 20,
BCCaptions.Customer,
IsInternal = false,
Direction = SyncDirection.Import,
PrimaryDirection = SyncDirection.Import,
PrimarySystem = PrimarySystem.Extern,
PrimaryGraph = typeof(PX.Objects.AR.CustomerMaint),
ExternTypes = new Type[] { typeof(CustomerData) },
LocalTypes = new Type[] { typeof(PX.Commerce.Core.API.Customer) },
AcumaticaPrimaryType = typeof(PX.Objects.AR.Customer),
AcumaticaPrimarySelect = typeof(PX.Objects.AR.Customer.acctCD),
URL = "user-edit.php?user_id={0}"
)]
[BCProcessorRealtime(PushSupported = false, HookSupported = false)]
public class WooCustomerProcessor : BCProcessorSingleBase<WooCustomerProcessor,
WooCustomerEntityBucket, MappedCustomer>, IProcessor
{
public WooRestClient client;
protected CustomerDataProvider customerDataProvider;
//protected List<Country> countries;
public CommerceHelper helper = PXGraph.CreateInstance<CommerceHelper>();
#region Constructor
public override void Initialise(IConnector iconnector,
ConnectorOperation operation)
{
base.Initialise(iconnector, operation);
client = WooCommerceConnector.GetRestClient(
GetBindingExt<BCBindingWooCommerce>());
customerDataProvider = new CustomerDataProvider(client);
}
#endregion
#region Import
public override async Task MapBucketImport(WooCustomerEntityBucket bucket,
IMappedEntity existing, CancellationToken cancellationToken = default)
{
MappedCustomer customerObj = bucket.Customer;
PX.Commerce.Core.API.Customer customerImpl = customerObj.Local =
new PX.Commerce.Core.API.Customer();
customerImpl.Custom = GetCustomFieldsForImport();
customerImpl.CustomerName = GetBillingCustomerName(customerObj.Extern).
ValueField();
customerImpl.AccountRef = APIHelper.ReferenceMake(customerObj.Extern.Id,
GetBinding().BindingName).ValueField();
customerImpl.CustomerClass = customerObj.LocalID == null ||
existing?.Local == null ?
GetBindingExt<BCBindingExt>().CustomerClassID?.ValueField() : null;
//Primary Contact
customerImpl.PrimaryContact = GetPrimaryContact(customerObj.Extern);
customerImpl.MainContact = SetBillingContact(customerObj.Extern);
customerImpl.ShippingAddressOverride = true.ValueField();
customerImpl.ShippingContactOverride = true.ValueField();
customerImpl.ShippingContact = SetShippingContact(customerObj.Extern);
BCBindingExt bindingExt = GetBindingExt<BCBindingExt>();
if (bindingExt.CustomerClassID != null)
{
CustomerClass customerClass = PXSelect<CustomerClass,
Where<CustomerClass.customerClassID,
Equal<Required<CustomerClass.customerClassID>>>>.
Select(this, bindingExt.CustomerClassID);
if (customerClass != null)
{
customerClass.ShipVia.ValueField();
}
}
}
public virtual Contact GetPrimaryContact(CustomerData customer)
{
var contact = new Contact();
contact.FirstName = !string.IsNullOrWhiteSpace(customer.FirstName) &&
string.IsNullOrWhiteSpace(customer.LastName) ?
string.Empty.ValueField() : customer.FirstName.ValueField();
contact.LastName = !string.IsNullOrWhiteSpace(customer.LastName) ?
customer.LastName.ValueField() :
!string.IsNullOrWhiteSpace(customer.FirstName) &&
string.IsNullOrWhiteSpace(customer.LastName) ?
customer.FirstName.ValueField() : customer.Username.ValueField();
contact.Email = customer.Email.ValueField();
return contact;
}
public virtual Contact SetBillingContact(CustomerData customerObj)
{
Contact contactImpl = new Contact();
contactImpl.DisplayName = GetBillingCustomerName(customerObj).
ValueField();
contactImpl.Attention = $"{customerObj.Billing?.FirstName} {
customerObj.Billing?.LastName}".ValueField(); ;
contactImpl.FullName = GetBillingCustomerName(customerObj).ValueField();
contactImpl.FirstName = customerObj.Billing?.FirstName.ValueField();
contactImpl.LastName = customerObj.Billing.LastName.ValueField();
contactImpl.Email = customerObj.Billing.Email.ValueField();
contactImpl.Address = MapAddress(customerObj.Billing);
contactImpl.Active = true.ValueField();
contactImpl.Phone1 = customerObj.Billing?.Phone.ValueField();
contactImpl.Phone1Type = PhoneTypes.Business1.ValueField();
return contactImpl;
}
public virtual Contact SetShippingContact(CustomerData customerObj)
{
Contact contactImpl = new Contact();
contactImpl.DisplayName = GetShippingCustomerName(customerObj).
ValueField();
contactImpl.Attention = $"{customerObj.Shipping?.FirstName} {
customerObj.Shipping?.LastName}".ValueField();
contactImpl.FullName = GetShippingCustomerName(customerObj).ValueField();
contactImpl.FirstName = customerObj.Shipping?.FirstName.ValueField();
contactImpl.LastName = customerObj.Shipping.LastName.ValueField();
contactImpl.Address = MapAddress(customerObj.Shipping);
contactImpl.Active = true.ValueField();
return contactImpl;
}
public virtual string GetBillingCustomerName(CustomerData data)
{
return !string.IsNullOrWhiteSpace(data.Billing.Company)
? data.Billing.Company
: string.IsNullOrWhiteSpace($"{data.Billing?.FirstName} {
data.Billing?.LastName}") ? data.Username : $"{
data.Billing?.FirstName} {data.Billing?.LastName}";
}
public virtual string GetShippingCustomerName(CustomerData data)
{
return !string.IsNullOrWhiteSpace(data.Shipping?.Company)
? data.Shipping.Company
: $"{data.Shipping?.FirstName} {data.Shipping?.LastName}";
}
public virtual Address MapAddress(CustomerAddressData addressObj)
{
var address = new Address();
address.AddressLine1 = addressObj.Address1.ValueField();
address.AddressLine2 = addressObj.Address2.ValueField();
address.City = addressObj.City.ValueField();
address.PostalCode = addressObj.PostalCode.ValueField();
if (!string.IsNullOrWhiteSpace(addressObj.Country))
{
var selectedCountry = addressObj.Country;
if (selectedCountry != null)
{
address.Country = addressObj.Country.ValueField();
if (!string.IsNullOrWhiteSpace(addressObj.State))
{
address.State = addressObj.State.ValueField();
}
}
}
return address;
}
public override async Task<PullSimilarResult<MappedCustomer>> PullSimilar(
IExternEntity entity, CancellationToken cancellationToken = default)
{
var uniqueField = string.IsNullOrWhiteSpace(
((CustomerData)entity)?.Billing.Email) ?
((CustomerData)entity)?.Email :
((CustomerData)entity)?.Billing.Email;
if (uniqueField == null) return null;
List<MappedCustomer> result = new List<MappedCustomer>();
foreach (PX.Objects.AR.Customer item in helper.CustomerByEmail.Select(
uniqueField))
{
PX.Commerce.Core.API.Customer data = new PX.Commerce.Core.API.Customer() {
SyncID = item.NoteID, SyncTime = item.LastModifiedDateTime };
result.Add(new MappedCustomer(data, data.SyncID, data.SyncTime));
}
if (result == null || result?.Count == 0) return null;
return new PullSimilarResult<MappedCustomer>() {
UniqueField = uniqueField, Entities = result };
}
public override async Task<PullSimilarResult<MappedCustomer>> PullSimilar(
ILocalEntity entity, CancellationToken cancellationToken = default)
{
var uniqueField = ((PX.Commerce.Core.API.Customer)entity)?.
MainContact?.Email?.Value;
if (uniqueField == null) return null;
IEnumerable<CustomerData> datas = customerDataProvider.GetAll(null);
if (datas == null) return null;
return new PullSimilarResult<MappedCustomer>() {
UniqueField = uniqueField, Entities = datas.Select(
data => new MappedCustomer(data, data.Id.ToString(),
data.DateModified.ToDate())) };
}
public override async Task SaveBucketImport(WooCustomerEntityBucket bucket,
IMappedEntity existing, string operation,
CancellationToken cancellationToken = default)
{
MappedCustomer obj = bucket.Customer;
PX.Commerce.Core.API.Customer impl = cbapi.Put(obj.Local, obj.LocalID);
obj.AddLocal(impl, impl.SyncID, impl.SyncTime);
UpdateStatus(obj, operation);
}
#endregion
#region Export
public override async Task MapBucketExport(WooCustomerEntityBucket bucket,
IMappedEntity existing, CancellationToken cancellationToken = default)
{
}
public override async Task SaveBucketExport(WooCustomerEntityBucket bucket,
IMappedEntity existing, string operation,
CancellationToken cancellationToken = default)
{
}
#endregion
#region Pull
public override async Task<MappedCustomer> PullEntity(Guid? localID,
Dictionary<string, object> externalInfo,
CancellationToken cancellationToken = default)
{
throw new NotImplementedException();
}
public override async Task<MappedCustomer> PullEntity(string externID,
string externalInfo, CancellationToken cancellationToken = default)
{
throw new NotImplementedException();
}
public override async Task FetchBucketsForImport(DateTime? minDateTime,
DateTime? maxDateTime, PXFilterRow[] filters,
CancellationToken cancellationToken = default)
{
IEnumerable<CustomerData> customers = customerDataProvider.GetAll(null);
foreach (CustomerData data in customers)
{
WooCustomerEntityBucket bucket = CreateBucket();
MappedCustomer mapped = bucket.Customer = bucket.Customer.Set(
data, data.Id.ToString(), data.LastName, data.DateModified.ToDate());
EnsureStatus(mapped, SyncDirection.Import);
}
}
public override async Task FetchBucketsForExport(DateTime? minDateTime,
DateTime? maxDateTime, PXFilterRow[] filters,
CancellationToken cancellationToken = default)
{
throw new NotImplementedException();
}
public override async Task<EntityStatus> GetBucketForImport(
WooCustomerEntityBucket bucket, BCSyncStatus syncstatus,
CancellationToken cancellationToken = default)
{
CustomerData data = client.Get<CustomerData>(
string.Format("/customers/{0}", syncstatus.ExternID));
MappedCustomer obj = bucket.Customer = bucket.Customer.Set(data,
data.Id.ToString(), data.LastName, data.DateModified.ToDate());
EntityStatus status = EnsureStatus(obj, SyncDirection.Import);
return status;
}
public override async Task<EntityStatus> GetBucketForExport(
WooCustomerEntityBucket bucket, BCSyncStatus bcstatus,
CancellationToken cancellationToken = default)
{
PX.Commerce.Core.API.Customer impl =
cbapi.GetByID<PX.Commerce.Core.API.Customer>(bcstatus.LocalID,
GetCustomFieldsForExport());
if (impl == null) return EntityStatus.None;
bucket.Customer = bucket.Customer.Set(impl, impl.SyncID, impl.SyncTime);
EntityStatus status = EnsureStatus(bucket.Customer, SyncDirection.Export);
return status;
}
#endregion
}
public static class PhoneTypes
{
public static string Business1 = "B1";
}
}