Using the latest version of Acumatica 5 with the latest and greatest updates, I’m running into a Web API issue that I have not been able to solve. I have code to execute the “Extend To Vendor” action on the Customer screen. It seems to run fine and does not error out but it fails to create the vendor. It seems to me that when performing the same actions through the website interface, the issue is that I’m not sending the correct command to choose the “Yes” button on the popup Warning box “Please confirm if you want to update current Vendor settings with the Vendor Class defaults. Original settings will be perserved otherwise.” I could be totally off though and any help would be greatly appreciated.
Here is my code:
String customerId = "SomeCustomerId";
String vendorClass = “SomeVendorClass”;
AcumaticaApiWS.AR303000Content AR303000 = context.AR303000GetSchema();
AcumaticaApiWS.AP303000Content AP303000 = context.AP303000GetSchema();
context.AR303000Clear();
AR303000.Actions.ExtendToVendor.Commit = true;
AcumaticaApiWS.AR303000Content[] AR303000result = context.AR303000Submit
(
new AcumaticaApiWS.Command[]
{
new AcumaticaApiWS.Value { Value = customerId, LinkedCommand = AR303000.CustomerSummary.CustomerID },
AR303000.Actions.ExtendToVendor
}
);
AcumaticaApiWS.AP303000Content[] AP303000result = context.AP303000Submit
(
new AcumaticaApiWS.Command[]
{
new AcumaticaApiWS.Value { Value = vendorClass, LinkedCommand = AP303000.GeneralInfoFinancialSettings.VendorClass },
new AcumaticaApiWS.Value { Value = "YES", LinkedCommand = AP303000.GeneralInfoFinancialSettings.ServiceCommands.DialogAnswer, Commit = true },
AP303000.Actions.Save
}
);
Thanks!
You're almost there. This is not an easy scenario since it involves multiple screens and dialogs, two things which are not trivial to use. The issues in your code sample are:
The dialog answer has to be set before the value. In your case, you're setting the vendor class first. This is counter-intuitive but the system has to know it before the dialog is displayed
The dialog answer is "Yes", and not "YES". You can see this by using the web browser inspector window and looking at the button title. The text is displayed in uppercase due to CSS styling.
You need to set the dialog answer on the primary view of the form (AP303000.VendorSummary.ServiceCommands.DialogAnswer), where the dialog is being displayed. There's no way to know this without looking at the source code, but I believe this is generally the case with dialog boxes.
The different Commit = true settings are not necessary (but don't hurt in this case).
This is the code I used, and in my case it extends a customer to a vendor and changes the vendor class at the same time:
String customerId = "ACTIVESTAF";
String vendorClass = "DATACENTER";
AcumaticaApiWS.AR303000Content AR303000 = context.AR303000GetSchema();
AcumaticaApiWS.AP303000Content AP303000 = context.AP303000GetSchema();
context.AR303000Clear();
AcumaticaApiWS.AR303000Content[] AR303000result = context.AR303000Submit
(
new AcumaticaApiWS.Command[]
{
new AcumaticaApiWS.Value { Value = customerId, LinkedCommand = AR303000.CustomerSummary.CustomerID },
AR303000.Actions.ExtendToVendor
}
);
AcumaticaApiWS.AP303000Content[] AP303000result = context.AP303000Submit
(
new AcumaticaApiWS.Command[]
{
new AcumaticaApiWS.Value { Value = "Yes", LinkedCommand = AP303000.VendorSummary.ServiceCommands.DialogAnswer },
new AcumaticaApiWS.Value { Value = vendorClass, LinkedCommand = AP303000.GeneralInfoFinancialSettings.VendorClass },
AP303000.Actions.Save
}
);
Related
I am trying to get activities for cases from different instance with all File Attachments and Notes attached to the activities. I have tried with different ways, but unfortunately none of them has worked. Can anyone please suggest what is the best way to get all file attachments and notes for the Case Activities using Acumatica WebService.
Here is the code which I tried--
SP203010WS.Content content = context.GetSchema();
export = context.Export
(
new SP203010WS.Command[]
{
new SP203010WS.Value
{
LinkedCommand = content.Case.CaseID,
Value = currentCaseNo
},
content.Activities.Type,
content.Activities.Summary,
new SP203010WS.Field { FieldName="Body", ObjectName="Activities"},
content.Activities.StartDate,
content.Activities.CreatedBy,
new SP203010WS.Field { FieldName="NoteID", ObjectName="Activities"},
content.Activities.CreatedAt,
new SP203010WS.Field
{
FieldName = content.Activities.ServiceCommands.Attachment.FieldName,
Value = content.Activities.ServiceCommands.Attachment.Value,
LinkedCommand = content.Activities.ServiceCommands.Attachment
},
new SP203010WS.Attachment
{
FieldName = content.Activities.ServiceCommands.Attachment.FieldName,
Value = content.Activities.ServiceCommands.Attachment.Value
},
new SP203010WS.Value
{
FieldName = content.Activities.ServiceCommands.Attachment.FieldName,
Value = content.Activities.ServiceCommands.Attachment.Value,
LinkedCommand = content.Activities.ServiceCommands.Attachment
},
},
new SP203010WS.Filter[]
{
new SP203010WS.Filter
{
Field = content.Activities.StartDate,
Condition = SP203010WS.FilterCondition.Greater,
Value = maxStartDate
}
},
0, true, true
);
Check out the documentation for I200 (screen-based Web Services) pages 75-76. First, you have to get the list of file names, and then loop through each one to get the actual attachments.
I am attempting to retrieve a single sales order based on the Customer Order field in Acumatica with the Contract Based API. See my code below, which I based off of code in the Contract Based Documentation (page 82).
public SalesOrder GetSalesOrder(string orderNumber)
{
var binding = new System.ServiceModel.BasicHttpBinding()
{
AllowCookies = true,
MaxReceivedMessageSize = 655360,
MaxBufferSize = 655360,
SendTimeout = new TimeSpan(0, 2, 0)
};
var soToBeFound = new SalesOrder()
{
OrderType = new StringValue { Value = "SO" },
CustomerOrder = new StringValue { Value = orderNumber }
};
var address = new System.ServiceModel.EndpointAddress(ConfigurationManager.AppSettings["AcumaticaUrl"]);
using (DefaultSoapClient client = new DefaultSoapClient(binding, address))
{
client.Login(_acumaticaUid, _acumaticaPwd, _acumaticaCompany, null, null);
var existingOrder = (SalesOrder)client.Get(soToBeFound);
client.Logout();
return existingOrder;
}
}
When I execute this code I get this exception:
The request channel timed out while waiting for a reply after
00:01:59.9880722. Increase the timeout value passed to the call to
Request or increase the SendTimeout value on the Binding. The time
allotted to this operation may have been a portion of a longer
timeout."
As you can see, I've already increased the timeout to 2 minutes, which seems like forever. Is the Acumatica API really just this slow? Or am I doing something wrong in code?
EDIT:
When I try to get by the "OrderNbr" field instead of "CustomerOrder" field, it works perfectly. Is getting by "CustomerOrder" not allowed in this way? If not, how can I use "CustomerOrder" in a get request?
When you do search via the Contract-Based API, it's required to assign instance of the [FieldType]Search type instead of [FieldType]Value to all fields used in search criteria (StringSearch must be used instead of StringValue in your case):
var soToBeFound = new SalesOrder()
{
OrderType = new StringSearch { Value = "SO" },
CustomerOrder = new StringSearch { Value = orderNumber }
};
Just to confirm, StringSearch is also used in the sample on page 82 from the Contract Based documentation.
Thanks to #DChhapgar for help me figure out how to add "draft email" activity in opportunity, however, when I was trying to run my code I created following #DChhapgar instruction, I got error as follows:
Error #13: Inserting 'Activity' record raised one or more errors. Please review. Error: 'From' may not be empty
My code is as below:
CR304000Content CR304000 = context.CR304000GetSchema();
context.CR304000Clear();
//Email Activity Screen
CR306015Content CR306015 = context.CR306015GetSchema();
context.CR306015Clear();
//Locate Opportunity for which Email Draft needs to be added
CR304000Content[] CR304000result = context.CR304000Submit(
new Command[]
{
new Value { Value = opportunity.ID, LinkedCommand = CR304000.OpportunitySummary.OpportunityID},
//Invoke New Email Actity Action
CR304000.Actions.NewMailActivity
});
//Specify data for Email Activity
if (!string.IsNullOrWhiteSpace(email.Subject))
{
CR306015Content[] CR306015result = context.CR306015Submit(
new Command[]
{
new Value { Value = "abcd#efg.com", LinkedCommand = CR306015.Message.FromMailAccountID},
new Value { Value = email.ToAddress, LinkedCommand = CR306015.Message.To},
new Value { Value = email.Subject, LinkedCommand = CR306015.Message.Subject },
new Value { Value = email.Message, LinkedCommand = CR306015.Message_.ActivityDetails},
CR306015.Actions.Save,
});
}
I saw there were totally three fields related to email "from" in web service specification: CR306015.Message.FromMailAccountID, CR306015.Message.FromEmailAccountID, CR306015.Message.FromMailFrom, however neither of them worked for me.
Am I missing something?
I'm guessing FromMailAccountID needs to be an integer. Look at what the values are for existing records.
I have a userevent script to change the Field in Contract record from PO record. The Script is running fine. But whenever I edit a contract record and try to submit it : It throws the error "Another user has updated this record since you began editing it. Please close the record and open it again to make your changes".
May I know the reason behind this ?
/*---------------------------------------------------------------------------------------------------------------
Description : Whenever the PO vendor is changed(due to Split vendor) that should replace the same in Contract page record automatically.
Script type : User Event Script
Script id : customscript452
Version : 1.0
Applied to : Contract
----------------------------------------------------------------------------------------------------------------*/
function srchfield()
{
var stRecordid = nlapiGetRecordId(); //returns the contract id
if(stRecordid== undefined || stRecordid== null || stRecordid==' ')
{
}
else
{
var stRecordtype = nlapiGetRecordType(); //returns the contract record type = jobs
var stRecord = nlapiLoadRecord(nlapiGetRecordType(), stRecordid);
nlapiLogExecution('debug','Load Object',stRecord);
var stContractID = stRecord.getFieldValue('entityid'); //returns the value of the field contractid whose fieldid is = entityid
nlapiLogExecution('debug','stContractID',stContractID);
var stCompanyName = stRecord.getFieldValue('companyname'); //returns the value of the field company name whose fieldid is = companyname
nlapiLogExecution('debug','stCompanyName',stCompanyName);
var stConcatenate = stContractID+" : "+stCompanyName; //Concatenate the two Fields to get the result which needs to be found in PO
var arrFilters = new Array(); // This is Array Filters all the Purchase Order Record Search
arrFilters.push(new nlobjSearchFilter('type', null, 'anyof',
[
'PurchOrd'
]));
arrFilters.push(new nlobjSearchFilter('mainline', null, 'is', 'T')); //This is to exclude line level results
arrFilters.push(new nlobjSearchFilter('custbodycontract', null, 'is', stRecordid)); //This is Filters in Contracts Search
var arrColumns = new Array();
arrColumns.push(new nlobjSearchColumn('entity')); //This is Search Column Field in Records
var arrSearchresults = nlapiSearchRecord('purchaseorder', null, arrFilters, arrColumns); //This is Filters in Search Result Purchase Order
if(arrSearchresults== undefined || arrSearchresults== null || arrSearchresults==' ')
{
}
else
{
var length = arrSearchresults.length;
}
if(length== undefined || length== null || length==' ')
{
}
else
{
for (var i = 0; arrSearchresults != null && i < arrSearchresults.length; i++)
{
var objResult = arrSearchresults[i];
var stRecId = objResult.getId();
var stRecType = objResult.getRecordType();
var stCntrctName = objResult.getValue('entity'); //This is Value are Get Purchase Order Records and Field for Vendor = entity
}
}
//var record = nlapiLoadRecord(nlapiGetRecordType(), stRecordid, stCntrctName);
if (stCntrctName =='custentityranking_vendor_name')
{
}
else
{
var stChangeName = stRecord.setFieldValue('custentityranking_vendor_name', stCntrctName); //This is Value are the Set in Main Vendor Field = custentityranking_vendor_name
nlapiSubmitRecord(stRecord, null, null); // Submit the Field Value in Record Type
}
}
}
The User Event script executes as the Contract record is being saved to the database. At the same time, you are loading a second copy of the record from the database and trying to submit the copy as well. This is causing the error you're seeing.
You fix this by just using nlapiSetFieldValue to set the appropriate field on the Contract.
I might also recommend getting more familiar with JavaScript by going through the JavaScript Guide over at MDN. In particular, take a look at the Boolean description so that you know how JavaScript evaluates Boolean expressions. This will help you greatly reduce the amount of code you've written here, as many of your conditionals are unnecessary.
What userevent do you have? It is happening depending on what type of user event and API you are using. Looking at your code, you are trying to load contract record that is already updated at the database. So you might consider below to address your issue. Hope, it helps.
If it is a before submit, you don't need to load the record where the script is deployed.
Just use nlapiGet* and nlapiSet* to get and set values. You also don't need to use nlapiSubmitRecord to reflect the change. With before submit, it executes before the record is being saved to the database. So your changes will still be reflected.
Then if it is after submit, it will be executed after the record has been saved to the database, Thus you might use the following API depending on your needs. Actually, this is the best practice to make sure the solution .
nlapiGetNewRecord - only use this if the script only needs to retrieve info from header and sublists. And nothing to set.
nlapiLookupField - use this if the script only needs to get value/s at the header and nothing from the line.
nlapiSubmitField - the script don't need to load and submit record if the changes only on header. Just use this API.
nlapiLoadRecord and nlapiSubmitRecord- use the former if the script will have changes at the line and then use the latter api to commit it on the database.
Being a user event script code, The code you showed is very not good considering performance.
Here is the sample you can merge
var stRecordid = nlapiGetRecordId(); //returns the contract id
// Every record has an internal id associated with it. No need to add condition explicitly to check if its null
var stRecordtype = nlapiGetRecordType();
var fields = ['entityid','companyname'];
var columns = nlapiLookupField(stRecordtype, stRecordid, fields);
var stContractID = columns.entityid;
var stCompanyName = columns.companyname;
nlapiLogExecution('debug','stContractID/stCompanyName',stContractID+'/'+stCompanyName);
var stConcatenate = stContractID+" : "+stCompanyName; //Concatenate the two Fields to get the result which needs to be found in PO
//
//your code of search
//you can improve that code also by using nlapilook up
nlapiSubmitField(stRecordtype, stRecordid, 'custentityranking_vendor_name', 'name to be updated');
I was trying to use web API to prepare invoice by calling "Prepare Invoice" from the top "Actions" menu on Sales Order screen SO301000 and then release this invoice on Invoice SO303000, however, after the invoice was prepared successfully I need to know the invoice reference number in order to release this invoice but I couldn't find a way to get this reference no or verify whether the action was successful or not from the return information. My code is below:
SO301000Content SO301000 = context.SO301000GetSchema();
context.SO301000Clear();
SO301000.Actions.PrepareInvoiceAction.Commit = true;
List<Command> cmds = new List<Command>();
cmds.Add(new Value { Value = soType, LinkedCommand = SO301000.OrderSummary.OrderType});
cmds.Add(new Value { Value = soNbr, LinkedCommand = SO301000.OrderSummary.OrderNbr });
cmds.Add(new Value { Value = customerCD, LinkedCommand = SO301000.OrderSummary.Customer, Commit = true });
cmds.Add(new Value { Value = customerLocation, LinkedCommand = SO301000.OrderSummary.Location});
cmds.Add(SO301000.Actions.PrepareInvoiceAction);
cmds.Add(SO301000.Actions.Save);
SO301000Content[] SO30100content = context.SO301000Submit(cmds.ToArray());
//Check whether invoice is successfully prepared and return reference No if it's successful.
Thread.Sleep(2000);
List<InvoiceInfo> InvoiceList = this.GetInvoiceInfoBySO(soNbr);
if (InvoiceList.Count > 0)
{
//successful
}
else
{
.....//failed
}
Anybody knows how to verify whether the action is successful or not and preferably get invoice reference number somehow?
For now I called an generic inquiry to get invoice reference number based on SO order no, it somewhat worked - that is going to be my another question ( it worked only when I put some sleep in the code otherwise I still couldn't get that new reference number - it seems there is a bug that causes some kind delay), but I will create another question for it.
Thanks.
Update: Sorry, I copied the wrong code and now it has been updated.
ok,
so after you submit the commands, you can do the following to check whether the processing has finished or not.
SO301000Content[] SO30100content = context.SO301000Submit(cmds.ToArray());
var status = context.SO301000GetProcessStatus();
while (status.Status == ProcessStatus.InProcess)
{
status = context.SO301000GetProcessStatus();
}
For getting the prepared invoice number, what i did was, i tried getting the sales order document back and read the invoice number from the shipments tab.