Error with simple Acumatica contract soap api call - api

I'm trying to get a simple Acumatica contract-based SOAP API Get() or GetList() call to work and all I'm getting is an error:
System.ServiceModel.FaultException: 'System.ArgumentNullException: Value cannot be null. Parameter name: model
See the code below. I first tried the REST API, but couldn't get around different issues (which I'll also probably add in another post). Any ideas what the error is referring to?
using (var soapClient = new ServiceReference1.DefaultSoapClient())
{
//Log in to Acumatica ERP
soapClient.Login
(
"admin",
"admin",
"Company",
null,
null
);
ServiceReference1.SalesOrder orderToFind = new
ServiceReference1.SalesOrder
{
CustomerID = new ServiceReference1.StringValue { Value = "2" },
OrderType = new ServiceReference1.StringValue { Value = "SO" },
OrderNbr = new ServiceReference1.StringValue { Value =
"SO001337" },
};
var getOrder = soapClient.Get(orderToFind);
var getOrders =
soapClient.GetList(orderToFind);
}
Acumatica v17.204.0019.

Just encountered the same error and a little ashamed to admit that solution appeared to be super simply for me: the binding was simply missing allowCookies="true" in app.config
Having enabled cookies, error ArgumentNullException: Value cannot be null. Parameter name: model got resolved:
<binding name="DefaultSoap" allowCookies="true" />

The solution for me was to add the WSDL as a ServiceReference instead of a WebReference, long story. Another thing to check might be the app.config to make sure it has the correct endpoint, bindings, etc. as per Acumatica documentation.

When searching for a record, one must always work with a proper variation of the [FieldType]Search type. In your case the orderToFind object should be declared as follows:
ServiceReference1.SalesOrder orderToFind = new ServiceReference1.SalesOrder
{
OrderType = new ServiceReference1.StringSearch { Value = "SO" },
OrderNbr = new ServiceReference1.StringSearch { Value = "SO001337" }
};
var getOrder = soapClient.Get(orderToFind);
To export orders for the given customer, you should define the ordersToFind object as follows:
ServiceReference1.SalesOrder ordersToFind = new ServiceReference1.SalesOrder
{
CustomerID = new ServiceReference1.StringSearch { Value = "2" },
};
var getOrders = soapClient.GetList(orderToFind);

Related

How to Set with Priority in Angularfire

I'm having trouble understanding how to set with $priority in angularfire. I am trying to add a username with the key as username.
For example if I try:
var object = {user : "name",
$priority : "this"};
var ref = new Firebase(FIREBASE_URL + 'users');
var newBar = $firebase(ref);
newBar.$set(username, object);
The firebase set fails because of the invalid character "$" in priority.
I understand that instead I could try :
var object = {user : "name",
$priority : "this"};
var ref = new Firebase(FIREBASE_URL + 'users');
var newBar = $firebase(ref).$asArray();
newBar.$add(object);
This succeeds in adding the object to the array, but doesn't give me the opportunity to set the key to username as I require.
I can't think of any other way to achieve this currently. Is there any way to use set that allows me to set $priority? Or any alternative method to achieve the same?
Thanks
$priority is a property that exists on synchronized objects and records inside a synchronized array. As you've noted, it's not an allowed key in firebase data, so using it with $firebase::$set doesn't make sense here (since $set takes a valid json object which is stored directly into Firebase). Reading the API specifications can be a big help here.
There is also no need to create a synchronized binding for this use case. Just use the existing Firebase reference:
var ref = new Firebase(URL);
ref.child(username).set(object, function(error){ /* ... */ });
If there is some use case for working within a synchronized binding, then just use the Firebase meta property .priority:
var object = {user: "name", ".priority": "this"};
var ref = new Firebase(URL);
var sync = $firebase(ref);
sync.$set(object).then(/* ... */);
In case anyone else is looking at this, I have now taken the approach of using set first and then setting priority thereafter like this:
var object = {user : "name",
$priority : "this"};
var username = "user1";
var ref = new Firebase(FIREBASE_URL + 'users');
var newBar = $firebase(ref);
newBar.$set(username, object).then(function(){
var ref2 = new Firebase(FIREBASE_URL + 'users/' + username);
var newBar2 = $firebase(ref2).$asObject();
newBar2.$loaded().then(function(){
newBar2.$priority = authUser.uid;
newBar2.$save();
});
});

Rally API 2 query historical velocity

I am doing some processing across iterations in a release and I want to find out what the teams velocity was at that point in time, is there any way to use the lookback API or otherwise get the information for that period?
i.e. the Rally generated velocity at that time or manually calculate the last 10 or all time velocity measures?
So, based on the responses below I have ended up with this code:
_getVelocity: function() {
this.logger.log("_getVelocity");
var me = this;
var deferred = Ext.create('Deft.Deferred');
Ext.Array.each(this.iterations,function(iteration){
iteration.PlanEstimate = 1;
me.logger.log("Fetching velocity for iteration", iteration.Name);
var start_date_iso = Rally.util.DateTime.toIsoString(iteration.StartDate);
var end_date_iso = Rally.util.DateTime.toIsoString(iteration.EndDate);
var type_filter = Ext.create('Rally.data.lookback.QueryFilter', {
property: '_TypeHierarchy',
operator: 'in',
value: this.show_types
});
var date_filter = Ext.create('Rally.data.lookback.QueryFilter', {
property: '_ValidFrom',
operator: '>=',
value:start_date_iso
}).and(Ext.create('Rally.data.lookback.QueryFilter', {
property: '_ValidFrom',
operator: '<=',
value:end_date_iso
}));
var filters = type_filter.and(date_filter);
me.logger.log("Filter ", filters.toObject());
Ext.create('Rally.data.lookback.SnapshotStore',{
autoLoad: true,
filters: filters,
fetch: ['FormattedID','PlanEstimate','ScheduleState'],
hydrate: ['ScheduleState'],
listeners: {
scope: this,
load: function(store,it_snaps,successful) {
if ( !successful ) {
deferred.reject("There was a problem retrieving changes");
} else {
me.logger.log(" Back for ", it_snaps.length, it_snaps);
deferred.resolve(it_snaps);
}
}
}
});
});
deferred.resolve([]);
return deferred;
},
The shape of this code and the filters etc is lifted from another function in the same app that IS working, however this one is NOT working, I get the following errors:
Uncaught TypeError: Cannot read property 'Errors' of null
GET https://rally1.rallydev.com/analytics/v2.0/service/rally/workspace/99052282…ScheduleState%22%5D&pagesize=20000&start=0&jsonp=Ext.data.JsonP.callback49 400 (Bad Request)
Since LookbackAPI gives historic data, you may query stories at the specific point of time and get number of points completed at that time. There is no Rally generated velocity, so this has to be accessed and summed up manually. For example, I have iteration that started on August 7 and ended on August 14, but if I want data from August 10 I use:
https://rally1.rallydev.com/analytics/v2.0/service/rally/workspace/1234/artifact/snapshot/query.js?find={"Iteration":5678,"_TypeHierarchy":"HierarchicalRequirement",_ValidFrom:{$gte:"014-08-10",$lte:"2014-08-14"}}&fields=['FormattedID','ScheduleState','PlanEstimate']&hydrate=['ScheduleState']
UPDATE: As far as the code you posted, change
var start_date_iso = Rally.util.DateTime.toIsoString(iteration.StartDate)
var end_date_iso = Rally.util.DateTime.toIsoString(iteration.EndDate);
to
var start_date_iso = Rally.util.DateTime.toIsoString(iteration.get('StartDate'),true);
var end_date_iso = Rally.util.DateTime.toIsoString(iteration.get('EndDate'),true);
I replicated the bad request error with your syntax, and after changing it to this format it worked: iteration.get('StartDate'),true
App source code is in this repo.

Can't get additionalSearchFields to work

jsonStoreInit = function(pSuccess, pFailure){
collections={};
collections['objects'] = {};
var options = {};
options.localKeyGen = false;
options.clear = false;
options.username = app.username;
options.password = app.password;
options.additionalSearchFields = {key: 'string'};
WL.JSONStore.init(collections, options)
.then(pSuccess)
.fail(pFailure);
};
putObject = function(pObject) {
var keyValue = pObject.getKey();
var object = {myObject : pObject.getKey()};
var options = {};
//options.additionalSearchFields = {key : keyValue};
WL.JSONStore.get("objects")
.add(object, options);
};
I'm on WL 6.0 FP 1
In the code sample above jsonStoreInit is what I use to init my store including the options.additionalSearchFields.
When I come to add the objects in the putObject funciton it works fine with the additionalSearchFields commented out, but when I uncomment it to add the additional fields I get an error
[wl.jsonstore] {"src":"store","err":21,"msg":"INVALID_ADD_INDEX_KEY","col":"objects","usr":"xxxx","doc":{},"res":{}}
When I look this error message up all I get is
21 INVALID_ADD_INDEX_KEY
Problem with additional search fields.
Which I had kinda figured ... can anyone provide any help on this ...
I don't need to you fix my code but if you could point me to a working example that would be excellent.
Many thanks, ownimage
The person that asked the question solved it, but I'm leaving this answer in case someone is wondering how to pass data that uses additionalSearchFields.
Example:
var data = {hello: 'world'};
WL.JSONStore.get('collection').add(data, {additionalSearchFields: {key: 'value'}})
The example assumes the collection was created with a search field for hello as string and an additional search field for key as string. It also assumes there's a collection initialized called collection.

nHibernate set referenced property by id

I have the following method which is called from Ajax:
[Authorize]
[ValidateInput(false)]
[ScriptMethod(ResponseFormat = ResponseFormat.Json)]
public JsonNetResult CreateOrUpdateTimeRecord(TimeRecord tr)
{
TimeRecord trLocal;
if (tr.Id == -1 || tr.Id == 0)
{
trLocal = new TimeRecord
{
Description = tr.Description,
StartTime = tr.StartTime,
EndTime = tr.EndTime,
User =new myTimeMvc.Models.NHibernate.Models.User {Id = tr.User.Id},// _userRepo.Get(tr.User.Id),
Hdt = new Hdt {Id = tr.Hdt.Id}//_hdtRepo.Get(tr.Hdt.Id)
};
_timeRepo.Insert(trLocal);
}
else
{
trLocal = _timeRepo.Get(tr.Id);
trLocal.Description = tr.Description;
trLocal.StartTime = tr.StartTime;
trLocal.EndTime = tr.EndTime;
_timeRepo.Update(trLocal);
}
...
}
As you can see my TimeRecord has a reference to User and Hdt. Now I started to work with NHibernate Profiler which complains when I resolve my properties by loading them from their coresponding repositories. Which is clear to me since I actually don't need to query the database for that since I have the ID's for this objects.
User = _userRepo.Get(tr.User.Id),
Hdt = _hdtRepo.Get(tr.Hdt.Id)
But I'm not 100% sure if I can use this instead:
User =new myTimeMvc.Models.NHibernate.Models.User {Id = tr.User.Id},,
Hdt = new Hdt {Id = tr.Hdt.Id}
I guess NHibernate lazy proxies work the same way since they only contain just the ID of the related object and load the rest when it is needed. Do I have to attach this "new" oject anyway to my session?
Can someone tell me what is the correct way to do this?
Cheers,
Stefan
There are a few ways how to achieve that. One of them could be using the Load() method. Check Ayendes post: NHibernate – The difference between Get, Load and querying by id, an extract:
Load will never return null. It will always return an entity or throw an exception. Because that is the contract that we have we it, it is permissible for Load to not hit the database when you call it, it is free to return a proxy instead.
Other words, we can do something like this
User = _userRepo.Load(tr.User.Id),
Hdt = _hdtRepo.Load(tr.Hdt.Id)
Where the Load would be encapsulating the session.Load()

Changing constraints on the fly

I have a dijit.form.NumberTextBox input field that starts out with these parms:
new dijit.form.NumberTextBox({
id: din1,
style: "width:60px",
constraints: {
places: 0,
pattern: '######'
}
},
din1);
Everything works great..My question is I would like to change 'places' and 'pattern' parms on the fly. So I wrote this to change 'places' and 'patterns' parms:
var myFldObj = dijit.byId(din1);
if (myFldObj) {
var myConstObj = myFldObj.attr('constraints');
if (myConstObj) {
myConstObj.places = 2;
myConstObj.pattern = '#####.0';
}
}
So, after I show the form again, I'd expect the entry field to allow 2 decimal places but the form still acts like places=0 and pattern='######'. When I check the values of 'places' and 'pattern' I get what I'd expect (2 and #####.0). My question:
Can you change these values on the fly??
OR
Do you have to destroy the original dijit object and recreate with new parms??
Thx!!
So, here is what worked for me:
First, I think this is a bug because an input field that starts out like
new dijit.form.NumberTextBox({
id: "fieldID",
style: "width:60px",
constraints: {
places: 0
}
},
"fieldID");
that is then changed on the fly with code like:
NOTE: ntbArry - Array of dijit.form.NumberTextBox objs tied to a html
input tag id.
for (var x=0;x < ntbArry.length;x++) {
var handle = ntbArry[x];
if (handle) {
handle.attr('constraints').places = 2;
handle.attr('constraints').pattern = '#####.0#';
}
}
Does not exhibit the same behavior as a field created this way (no constraints mods on the fly):
new dijit.form.NumberTextBox({
id: "fieldID",
style: "width: 60px",
constraints: {
places: 2,
pattern: '#####.0#'
}
},
"fieldID");
It's close in behavior but every time you type a decimal point, the error message pops up stating invalid entry. This message doesn't pop up when typing the decimal point on a field that was originally created with the constraints places=2 and pattern '#####.0#'.
So, to get original behavior I wanted:
fieldIDEvents is an array of dojo events tied to NumberTextBox fields.
Before continuing disconnect dojo events
for (var x=0;x < fieldIDEvents.length;x++) {
var handle = fieldIDEvents[x];
if (handle) {
dojo.disconnect(handle);
}
}
then destroy the NumberTextBox dojo objects
for (var x=0;x < ntbArry.length;x++) {
var handle = ntbArry[x];
if (handle) {
handle.destroy();
ntbArry[x] = null;
}
}
Next, place the input tag back into the html because it gets destroyed:
NOTE: tdtag and an id on a html td tag which should contain the input tag.
var fld1 = this.document.getElementById("tdtag");
if (fld1) {
//alert("\""+fld1.innerHTML+"\"");
fld1.innerHTML = "<input id=\"fieldID\">";
}
Now, create the NumberTextBox object again:
ntbArry[0] = new dijit.form.NumberTextBox({
id: "fieldID",
style: "width: 60px",
constraints: {
places: 2,
pattern: '#####.0#'
}
},
"fieldID");
It's a few extra steps but, at least I know this is what works for me..If I'm missing something basic, let me know, it's easy to miss the small details with this stuff.
I use Dojo 1.3 and I can see that dijit.form.NumberTextBox has no pattern and places properties, but has editOptions property. So I would try to change the constraints like this:
myConstObj.editOption.places = 2;