???Connection pools are the interface to X3 for SOAP calls. Learn how to configure a pool.
Because X3 does not allow basic authentication, it is necessary to use OAuth2 authentication for SOAP web services. These sections cover the things you need to set it up. We provide step-by-step instructions, from creating a provider to authenticating, using Google as an example.
This is the place to start. Here’s how you can set up your own OAuth2 client.
All the pieces you need inside X3 to work with OAuth2.
Once you have OAuth2 authentication configured, you’ll want to add it to your web service calls.
Open Classic SOAP Web Services in the Administration tab and select Web Services (Client might need to create one) From here you can pen Run, Read, and Query
Query is great for seeing a full table, but what if you wanted to narrow down your search. One common job will be only grabbing new entries or searching by a certain date, which is not possible with Query
Requires: Database credentials from the client
var allAccounts = OracleDB.Bpcustomers.Where(x => x.Upddat0 >= compareDate || x.Credat0 >=
compareDate).ToList();
var contacts = OracleDB.Contacts.Where(x => x.Bpanum0 == account.Bpcnum0 && x.Cntfnc0 == 2).ToArray();
contactName = OracleDB.Contactcrms.FirstOrDefault(x => x.Cntnum0 == contact.Ccncrm0);
var address = OracleDB.Bpaddresses.Where(x => x.Bpanum0 == account.Bpcnum0 && x.Bpaadd0 != "000").ToList();
var newProducts = OracleDB.Itmmasters.Where(x => x.Upddat0 >= compareDate || x.Credat0 >= compareDate).ToList();
var specs = OracleDB.Ypartsetspecs.Where(x => x.Ypartset0 == product.Ypartset0).ToArray();
var newInventory = OracleDB.Itmmvts.Where(x => x.Upddat0 >= compareDate || x.Credat0 >= compareDate).ToList();
var priceList = OracleDB.Spricfiches.Where(x => x.Pli0.Contains("{priceList}"));
foreach (var record in priceList)
{
var pliRecord = OracleDB.Spriclists.Where(x => x.Plicrd0 == record.Plicrd0).GroupBy(x => x.Plicri20);
foreach (var priceRule in pliRecord)
{
}
}
var x3SalesOrders = OracleDB.Sorders.Where(x => x.Upddat0 >= compareDate || x.Credat0 >= compareDate).ToList();
var lineItemQuantities = OracleDB.Sorderqs.Where(x => x.Sohnum0 == order.Sohnum0).ToArray();
Create a new job called CustomersSageX3ToCef
Add this method and set a breakpoint at the if Statement
[SkipWhenPreviousJobIsRunning]
[DisableConcurrentExecution(5), AutomaticRetry(Attempts = 0, OnAttemptsExceeded = AttemptsExceededAction.Fail)]
public async Task ProcessAccountsFromSageX3ToCEF(PerformContext context, CancellationToken token)
{
var compareDate = GetCompareDate(context, nameof(ProcessAccountsFromSageX3ToCEF)) ?? DateTime.Now.AddDays(-10);
compareDate = new DateTime(2015, 01, 01);
var x3AccountIDs = await _x3Service.ListX3ProductIds(compareDate, token).ConfigureAwait(false);
if (x3AccountIDs?.Any() != true) { return; }
//foreach (var sku in x3AccountIDs)
//{
// var product = await _x3Service.ReadX3Product(_x3Options.ProductObjectPublicName, nameof(X3Field.ITMREF), sku.RETVAL, token);
//}
}
Back in your JobService.SageX3ToCEF set the job we just created.
{
RecurringJobManager.AddOrUpdate(
recurringJobId: "ProcessAccountsFromSageX3ToCEF",
job: Job.FromExpression(() => ProcessAccountsFromSageX3ToCEF(null, CancellationToken.None)),
cronExpression: _cron.wooX3Cron.SageToWooProducts,
options: _recurringJobOptions); ;
}
We’re ready to run the job now. Run the programKnown Customizations
Now uncomment out the foreach loop. Make sure you’re using the AccountObjectPublicName and BPCNUM as the X3Field
foreach (var sku in x3AccountIDs)
{
var account = await _x3Service.ReadX3Product(_x3Options.AccountObjectPublicName, nameof(X3Field.BPCNUM sku.RETVAL, token);
}
Now put a breakpoint on the account and step through it. You should pull an XML document that will contain all of the information about that customer.
Get XML Schema from Sage X3. Start with opening your Classic Soap Web service

Select the, Get Description, Web Service

Enter which web service you are wanting to upload to. In this case lets upload a new customer

A full XML template for that object should be generated. Copy all of that XML

Create a new folder in your Clarity Connect project called, ObjectSchema. Create a new XML file called X3Customer.xml. Paste in the full XML schema from Sage X3 Description Web Service

Open your SageX3Options and add a line for X3CustomerFileName

Now go to AppSettings and add the option there as well using your X3Customer.xml

public void SetSageX3CEFJobs()
{
RecurringJobManager.AddOrUpdate(
recurringJobId: "ProcessAccountsFromSageX3ToCEF",
job: Job.FromExpression(() => ProcessAccountsFromSageX3ToCEF(null, CancellationToken.None)),
cronExpression: _cron.wooX3Cron.SageToWooProducts,
options: _recurringJobOptions); ;
In your AccountsSageX3ToCEF class create a new method called BuildXmlMessage. This is how we will implement the X3CustomerFileName Schema we just created. You may need to add a few new properties to your X3Account class.
private string BuildXmlMessage(X3Account account)
{
var x3SchemaReader = new X3SchemaReader(_x3Options.X3CustomerFileName);
x3SchemaReader.AddXmlSoapData("BPCNUM", account.BPCNUM);
x3SchemaReader.AddXmlSoapData("BPRNAM", account.BPRNAM);
x3SchemaReader.AddXmlSoapData("BCGCOD", account.BCGCOD);
//x3SchemaReader.AddXmlSoapData("ZBPCNUM", account.ZBPCNUM);
x3SchemaReader.AddXmlSoapData("PTE", account.PTE);
var count = 1;
var addressList = new List<NameValuePair>
{
new NameValuePair("BPAADDFLG", "1"),
new NameValuePair("CODADR", account.CODADR),
new NameValuePair("CRY", account.CRY),
new NameValuePair("ADDLIG1", account.XADDLIG1),
new NameValuePair("ADDLIG2", account.XADDLIG2),
new NameValuePair("CTY", account.XCTY),
new NameValuePair("SAT", account.XSAT),
new NameValuePair("POSCOD", account.XPOSCOD),
new NameValuePair("FCYWEB", account.XFCYWEB),
new NameValuePair("TEL1", account.XTEL1),
new NameValuePair("WEB1", account.XWEB1),
};
x3SchemaReader.AddXmlSoapListData(addressList, count++);
return x3SchemaReader.XmlRequestMessage;
}
Open both your x3Service and iX3Services and create a new method called UpdateX3CustomerAsync.
Task UpdateX3CustomerAsync(string bpcNum, string customer, CancellationToken token);
public async Task UpdateX3CustomerAsync(string bpcNum, string customer, CancellationToken token)
{
var x3UpdateRequest = new SageX3AccountUpdateRequest("ECMBPC", nameof(X3Field.BPCNUM), bpcNum, customer);
var x3CustomerResult = await Mediator.Send(x3UpdateRequest, token).ConfigureAwait(false);
}
Create a new ICefService.Customer and CefService.Customer and add the interface to your ICefService class. In your ICefService.Customer, create a new method called ListCustomersByCompareDate. Your full method in your CefService.Customer should look something like this.
public async Task<List<AccountModel>> ListCustomersByCompareDate(DateTime? compareDate, CancellationToken token)
{
var searchModel = new SearchModel();
searchModel.ModifiedSince = compareDate;
var request = new CefAccountListRequest(searchModel);
var orders = await Mediator.Send(request, token).ConfigureAwait(false);
return orders.ToList();
}
Back in your AccountsSageX3ToCEF class, create a new method called ProccessCustomersFromWooCommerceToSageX3
[SkipWhenPreviousJobIsRunning]
[DisableConcurrentExecution(5), AutomaticRetry(Attempts = 0, OnAttemptsExceeded = AttemptsExceededAction.Fail)]
public async Task ProcessCustomersFromCEFToSagex3(PerformContext context, CancellationToken token)
{
//var compareDate = GetCompareDate(context, nameof(ProcessCustomersFromSageX3ToWooCommerce)) ?? DateTime.Now.AddDays(-10);
// How far back to check for updated customers
var compareDate = DateTime.Now.AddDays(-1);
//Get All CEF Customers
var cefCustomers = await _cefService.ListCustomersByCompareDate(compareDate, token).ConfigureAwait(false);
if (cefCustomers?.Any() != true) { return; }
foreach (var cefCustomer in cefCustomers)
{
// Check if customer has been updated
var cefToX3Customer= Mapper.Map<X3Account>(cefCustomer);
var x3CustomerUpdate = BuildXmlMessage(cefToX3Customer);
await _x3Service.UpdateX3CustomerAsync(cefToX3Customer.BPCNUM, x3CustomerUpdate, token).ConfigureAwait(false);
}
}
In your AccountProfile Mappings add a new mapping for AccountModel to X3Account
CreateMap<AccountModel, X3Account>()
//.ForMember(dest => dest.BPC, opt => opt.MapFrom(src => src.BPCNUM + " - " + src.BPRNAM))
//.ForMember(dest => dest.BCGCOD, opt => opt.MapFrom(src => src.C)) // Customer Category
.ForMember(dest => dest.BPCNUM, opt => opt.MapFrom(src => src.CustomKey)) // WooID
.ForMember(dest => dest.BPRNAM, opt => opt.MapFrom(src => src.Name)) // Customer Nam
.ForMember(dest => dest.XTEL1, opt => opt.MapFrom(src => src.Phone)) // Phone Number
.ForMember(dest => dest.XWEB1, opt => opt.MapFrom(src => src.Email)) // Email
.AfterMap((src, dest) => dest.BCGCOD = "CC2")
.AfterMap((src, dest) => dest.CRY = "US")
.AfterMap((src, dest) => dest.CUR = "USD")
.AfterMap((src, dest) => dest.LAN = "ENG")
.AfterMap((src, dest) => dest.CODADR = "A1")
.AfterMap((src, dest) => dest.PTE = "DCC")
.ForAllOtherMembers(opt => opt.Ignore());
}
Set a new job in your JobService class
RecurringJobManager.AddOrUpdate(
recurringJobId: nameof(ProcessCustomersFromCEFToSagex3),
job: Job.FromExpression(() => ProcessCustomersFromCEFToSagex3(null, CancellationToken.None)),
cronExpression: _cron.x3CefCron.X3ToCefAccounts,
options: _recurringJobOptions);
Run your new job!
If you are running integrations with Sage X3 using REST or SOAP web services, you may come across issues when the web pool is in a stopped state, or is no longer responding due to errors on prior web service calls. There are several ways to check the state of a web service pool and to restart the web service pool using Syracuse REST utilities.
When consuming web services with Sage X3, you're used to referring to the pool using the SOAP classic pool alias, which can be seen under Administration > Administration > Web Services > Classic SOAP Pools configuration. For any activities related to the pools as described below, you will need to use the pool UUID (universally unique identifier).
A list of web pools can be retrieved by running a REST query request, as shown below, substituting your Sage X3 URL for "x3instance".
http://x3instance:8124/sdata/syracuse/collaboration/syracuse/soapClassicPools?representation=soapClassicPool.$query
Using "Basic Auth" for the Authorization type, the same way you use X3 web service SOAP, will result in some paging information, along with a list of resources, which are the SOAP pool details. Below is a sample of the resource details.
The piece of information you will need for specific activities on the web pool is the UUID for the web pool.
Another item that is useful in the "autoStartDisabled" value. If this has a value of "true", the web service is not currently running.
If the pool UUID is already know, the pool details can be obtained by running a REST details request, as shown below, substituting your Sage X3 URL for "x3instance". Also make sure you substitute you UUID in the single quotes.
http://x3instance:8124/sdata/syracuse/collaboration/syracuse/soapClassicPools('7f487d15-fd90-44a4-941a-a0d75175bf9e')?representation=soapClassicPool.details
The results will contain the same information as the query results, for a single pool only.
By using the above request and results, you can determine the state of your web pool using REST commands. This information could be used to stop and start the pool.
**NOTE—if you run reoccurring tasks for integrations, be aware that stopping and starting the pool will interrupt any transactions in process. This should only be done after hours, if it is determined that the pool is not responding.
One way to use these commands would be to do a daily or weekly stop and start of the web pool. This can be done by embedding the REST commands for stop and start in a .net, curl, or other application to issue the commands.
Using the UUID for the web pool, the pool can be stopped using the POST request below.
http://x3instance:8124/api1/syracuse/collaboration/syracuse/soapClassicPools('7f487d15-fd90-44a4-941a-a0d75175bf9e')/$service/stop
The response will include messages indicated whether or not the stop was successful. If there are multiple channels, based on the settings under host, there will be a message for each process stopped.
Using the UUID for the web pool, the pool can be started using the POST request below.
http://x3instance:8124/api1/syracuse/collaboration/syracuse/soapClassicPools('7f487d15-fd90-44a4-941a-a0d75175bf9e')/$service/start
The response will include messages indicated whether or not the start was successful. If there are multiple channels, based on the settings under host, there will be a message for each process started.
Phase 2