Acumatica - How to update custom field in Customer Location from custom field in Customer - events

I've tried a few different ways to do this and each way has a piece of code I am just not getting right. I need to update a custom field UsrCustomerShipAccount in Customer Locations if it is updated in the Customer Delivery Tab. I tried SetValueExt and creating a graph instance. Sorry about the dumb question.
The way that seemed to get me the closest is below:
protected void LocationExtAddress_UsrCustomerShipAccnt_FieldUpdated(PXCache cache, PXFieldUpdatedEventArgs e, PXFieldUpdated InvokeBaseHandler)
{
if(InvokeBaseHandler != null)
InvokeBaseHandler(cache, e);
var row = (LocationExtAddress)e.Row;
if (row == null) return;
PXSelectBase<Location> locationObj = new PXSelect<Location, Where<Location.bAccountID, Equal<Required<Location.bAccountID>>>>(Base);
Location deliveryLocation = locationObj.Select(row.LocationBAccountID);
var locationExt = PXCache<Location>.GetExtension<LocationExt>(location); <-- This generates error that there is no LocationExt.
deliveryLocation.Cache.SetValueExt(deliveryLocation, "UsrCustomerShipAccount", -->This needs to be the value that changed LocationExtAddress.UsrCustomerShipAccount but I don't see how to get this<--);
deliveryLocation.Cache.IsDirty = true;
deliveryLocation.Update(deliveryLocation); <--I don't know if this doesn't work because it is wrong or if it is because "UsrCustomerShipAccount" is not in deliverLocation.
}

You have
var locationExt = PXCache<Location>.GetExtension<LocationExt>(location);
shouldn't this be
var locationExt = PXCache<Location>.GetExtension<LocationExt>(deliveryLocation );
?

Related

Bing Maps API - mapArea: this parameter value is out of range

I'm using the Bing Maps API to generate images from certain locations using the BotFramework-Location NuGet package. (Which code can be found here)
Sometimes it works, but sometimes the images are not loaded due to an error in the Rest call (which is called by the BotFramework, not by me)
This is my code:
IGeoSpatialService geoService = new AzureMapsSpatialService(this.azureApiKey);
List < Location > concreteLocations = new List < Location > ();
foreach(String location in locations) {
LocationSet locationSet = await geoService.GetLocationsByQueryAsync(location);
concreteLocations.AddRange(locationSet ? .Locations);
}
// Filter out duplicates
var seenKeys = new HashSet < String > ();
var uniqueLocations = new List < Location > ();
foreach(Location location in concreteLocations) {
if (seenKeys.Add(location.Address.AddressLine)) {
uniqueLocations.Add(location);
}
}
concreteLocations = new List < Location > (uniqueLocations.Take(5));
if (concreteLocations.Count == 0) {
await context.PostAsync("No dealers found.");
context.Done(true);
} else {
var locationsCardReply = context.MakeMessage();
locationsCardReply.Attachments = new LocationCardBuilder(this.bingApiKey, new LocationResourceManager()).CreateHeroCards(concreteLocations).Select(card => card.ToAttachment()).ToList();
locationsCardReply.AttachmentLayout = AttachmentLayoutTypes.Carousel;
await context.PostAsync(locationsCardReply);
}
Which responds this:
The reason not all images are shown is because the Rest call to the Bing Maps API returns this:
mapArea: This parameter value is out of range.
Here is one of the image uris that fail (I removed my key):
https://dev.virtualearth.net/REST/V1/Imagery/Map/Road?form=BTCTRL&mapArea=49.5737,5.53792,49.57348,5.53744&mapSize=500,280&pp=49.5737,5.53744;1;1&dpi=1&logo=always&key=NOT_REAL_12758FDLKJLDKJO8769KLJDLKJF
Anyone know what I've been doing wrong?
I think I understood why you got that error. I tried to get this map and got the same result as yours, as you said:
mapArea: This parameter value is out of range.
If you look at the sample url you provided, the mapArea is equal to 49.5737,5.53792,49.57348,5.53744
So I just inverted the coordinates of the 2 points defining this area, putting the one with the smaller latitude value first, I got a reply:
EDIT:
As you commented, this call is made inside BotBuilder-Location code, not on yours. I had a look to it, this is the method to generate the map, called inside LocationCardBuilder class that you are instantiating:
public string GetLocationMapImageUrl(Location location, int? index = null)
{
if (location == null)
{
throw new ArgumentNullException(nameof(location));
}
var point = location.Point;
if (point == null)
{
throw new ArgumentNullException(nameof(point));
}
if (location.BoundaryBox != null && location.BoundaryBox.Count >= 4)
{
return string.Format(
CultureInfo.InvariantCulture,
ImageUrlByBBox,
location.BoundaryBox[0],
location.BoundaryBox[1],
location.BoundaryBox[2],
location.BoundaryBox[3],
point.Coordinates[0],
point.Coordinates[1],
index,
this.apiKey);
}
else
{
return string.Format(
CultureInfo.InvariantCulture,
ImageUrlByPoint,
point.Coordinates[0],
point.Coordinates[1],
index,
apiKey);
}
}
As you can see, there is no restriction on the format of the BoundaryBox item. But if you look at the documentation about location data here:
BoundingBox: A geographic area that contains the location. A bounding box contains SouthLatitude, WestLongitude, NorthLatitude, and EastLongitude values in units of degrees.
As you may know, in code, SouthLatitude is smaller that NorthLatitude (as it expressed with positive and negative values in code depending on the location compared to Ecuador: 43N is 43, 43S is -43). So the problem seems to be here.
I made a quick test to see if I got the error base on the call you are doing before (to GetLocationsByQueryAsync), I wasn't able to reproduce this case. Can you share the query you did that linked to this problem?

Dynamic menu configuration section with conditional inputs on Magento custom module

I've followed this tutorial to create a custom dynamic backend configuration with serialized data, and everything is working as expected. yay
But now I want to take another step and only show some inputs when a specific value is selected in a select box. I know that I can use when doing this with system.xml, but how can I accomplish the same thing via code with dynamics serialized tables?
I ended up doing some kind of Javascript workaround to enable/disable a certain input.
function togleSelect(element)
{
var val = element.value;
var name = element.name;
if (val == 0) // select value to be triggered
{
name = name.substr(0, name.lastIndexOf("[")) + "[name_of_my_input]";
var target = document.getElementsByName(name);
target[0].disabled = false;
}
else
{
name = name.substr(0, name.lastIndexOf("[")) + "[name_of_my_input]";
var target = document.getElementsByName(name);
target[0].disabled = true;
}
}
It's not the best solution but it's working.

UpdateRelatedObject method only works when the sourceProperty is not collection

I am getting the following error when I try to update tree of object using asp.net webapi OData:
"UpdateRelatedObject method only works when the sourceProperty is not collection."
My code is provided below. I got this error when the mehod "UpdateRelatedObject" is called. Can you please advise what is wrong with my code and how to update tree of objects (meaning object contains collection of child objects) using asp.net webapi odata v4.
var container = new Container(new Uri("http://JohnAlbert.com/MyOdataTest/odata"));
Product product = container.Products.Expand(p=> p.ProductItems).Expand(p=>p.ProductInvoices).Where(p => p.PId == Guid.Parse("28C508B8-F2DC-45C2-B401-7F94E79AB347")).FirstOrDefault();
if (product != null)
{
product.Name = product.Name + "_Modified";
var pitem1 = product.ProductItems[0];
product.ProductItems.Remove(pitem1);
container.UpdateRelatedObject(product, "ProductItems", pitem1);
var pitem2 = product.ProductItems[0];
pitem2.Price = 999;
container.UpdateRelatedObject(product, "ProductItems", pitem1);
var pInv1 = product.ProductInvoices[0];
product.ProductInvoices.Remove(pInv1);
container.UpdateRelatedObject(product, "ProductInvoices", pInv1);
}
container.UpdateObject(product);
container.SaveChanges(SaveChangesOptions.BatchWithSingleChangeset);
What you actually want to delete the relationship between some items in a collection-valued navigation property of an entity and itself. In such case DeleteLink() is the right method to use. In this case the following code should do the work:
if (product != null)
{
var pitem1 = product.ProductItems[0];
var pitem2 = product.ProductItems[0];
var pInv1 = product.ProductInvoices[0];
container.DeleteLink(product, "ProductItems", pitem1);
container.DeleteLink(product, "ProductItems", pitem2);
container.DeleteLink(product, "ProductInvoices", pInv1);
container.SaveChanges();
}
You may think the above way isn't as intuitive as directly removing the navigation items from the entity using .Remove() as you did. For this problem, the entity tracking enabled by using DataServiceCollection<T> can help. You can use this blog post as a tutorial for how to use DataServiceCollection<T>: http://blogs.msdn.com/b/odatateam/archive/2014/04/10/client-property-tracking-for-patch.aspx
To delete a contained navigation property, you can use DataServiceContext.DeleteObject.
To delete a relationship between an entity and its navigation property, you can use DataServiceContext.DeleteLink
To update an object, you can use DataServiceContext.UpdateObject.
So according to your scenario, you could use following code
if (product != null)
{
product.Name = product.Name + "_Modified";
dsc.UpdateObject(product);
var pitem1 = product.ProductItems[0];
//This is to remove relationship
container.DeleteLink(product, "ProductItems", pitem1);
// This is to remove the object
//container.DeleteObject(pitem1);
var pitem2 = product.ProductItems[0];
pitem2.Price = 999;
container.UpdateObject(pitem2);
var pInv1 = product.ProductInvoices[0];
//This is to remove relationship
container.DeleteLink(product, "ProductInvoices", pInv1);
// This is to remove the object
//container.DeleteObject(pInv1);
container.SaveChanges(SaveChangesOptions.BatchWithSingleChangeset);
}

How to create a update function in LINQ when object has a list?

I´m still having a hard time with Linq.
I need to write a Update Function tat receives an object that has a list. Actually, A region has a list of cities. I want to pass an object "Region" that has a name filed and a list of cities. The problem, is the city objects came from another context and I am unable to attach them to this context. I have been trying several functions, and always get an error like "EntitySet was modified during enumeration" or other. I am tring to make the code below work, but if anyone has a different approach please help.
public int Updateregion(region E)
{
try
{
using (var ctx = new AppDataDataContext())
{
var R =
(from edt in ctx.regiaos
where edt.ID == E.ID
select edt).SingleOrDefault();
if (R != null)
{
R.name = R.name;
R.description = E.description;
}
R.cities = null;
R.cities.AddRange(Edited.Cities);
ctx.SubmitChanges();
return 0 //OK!
}
}
catch (Exception e)
{
......
}
You can't attach objects retrieved from one datacontext to another, it's not supported by Linq-to-SQL. You need to somehow dettach the objects from their original context, but this isn't supported either. One can wonder why a dettach method isn't available, but at least you can fake it by mapping the list to new objects:
var cities = Edited.Cities.Select(city => new City {
ID = city.ID,
Name = city.Name,
/* etc */
});
The key here is to remember to map the primary key and NOT map any of the relation properties. They must be set to null. After this, you should be able to attach the new cities list, and have it work as expected.

unable to parse the xml query using Linq

I am developing a sample Twitter app for Windows phone 7. In my code to display some details of user, used the following code.
void ShowProfile()
{
WebClient client = new WebClient();
client.DownloadStringCompleted += new DownloadStringCompletedEventHandler(Profile_DownloadCompleted);
client.DownloadStringAsync(new Uri("http://api.twitter.com/1/users/show.xml?user_id=" + this.id));
}
void Profile_DownloadCompleted(object sender, DownloadStringCompletedEventArgs e)
{
if (e.Error != null)
{ return; }
if (e.Result == null) MessageBox.Show("NUlllllllllll");
XElement Profile = XElement.Parse(e.Result);
var ProfileDetails = (from profile in Profile.Descendants("user")
select new UserProfile
{
UserName = profile.Element("screen_name").Value,
ImageSource = profile.Element("profile_image_url").Value,
Location = profile.Element("location").Value,
TweetsCount = profile.Element("statuses_count").Value,
}).FirstOrDefault();
LayoutRoot.DataContext = ProfileDetails;
}
Here, LayoutRoot is the Grid name. But the data binding doesn't work.
Infact, when kept a Break point it seems there is no data in the ProfileDetails object. But I could observe that e.Result contains the required data in the XML format.
Can any body figureout where I am going wrong??
Thanks in advance.
You have used XElement.Parse so Profile represents the single root <user> that API request would have returned. You are then trying to look for user elements inside it which of course makes no sense.
Try XDocument.Parse instead. Also does it really make any sense assigning a IEnumerable<UserProfile> to the data context when that list can only ever contain 1 entry?

Resources