Easypost Intergration for Acumatica customization broke international shipments - acumatica

A customer needed to override the address information when sending labels to Easypost. We modified the SOShipmentEntry graph and wrote an override for BuildRequest function. It's a duplicate of the info that is in the standard Acumatica graph, but it's using differant addresses.
It sends the request and this all works until we try and send international shipments. It seems that it's not adding in the customs info and then the UPS request from Easypost fails. My confusion is that I can't see anywhere in the code where it's adding in the ELLPFC or other customs info. I'm sure that somehow I'm missing it when I build the packages, but my code for the packages is the same as Acumaticas.
public virtual CarrierBox BuildCarrierPackageTEK(SOPackageDetailEx detail, string pluginUOM)
{
//decimal weightInStandardUnit = ConvertGlobalUnitsTEK(Base, commonsetup.Current.WeightUOM, pluginUOM, detail.Weight ?? 0);
// Edited to use the code at top, this could probably be worked around.
decimal weightInStandardUnit = ConvertGlobalUnitsTEK(Base, commonsetupTEK.Current.WeightUOM, pluginUOM, detail.Weight ?? 0);
CarrierBox box = new CarrierBox(detail.LineNbr.Value, weightInStandardUnit);
box.Description = detail.Description;
box.DeclaredValue = detail.DeclaredValue ?? 0;
box.COD = detail.COD ?? 0;
box.Length = detail.Length ?? 0;
box.Width = detail.Width ?? 0;
box.Height = detail.Height ?? 0;
box.CarrierPackage = detail.CarrierBox;
box.CustomRefNbr1 = detail.CustomRefNbr1;
box.CustomRefNbr2 = detail.CustomRefNbr2;
return box;
}
Does anyone have any thoughts?

Related

C# Revit API, how to create a simple wall using ExternalCommand?

I just wanted to learn Revit API and create a simple wall using ExternalCommand. But I cannot figure it out...
I think my problem is here:
var symbolId = document.GetDefaultFamilyTypeId(new ElementId(BuiltInCategory.OST_Walls));
When I debug it symbolId always -1.
Can you help me what is wrong with this code snippet?
public Autodesk.Revit.UI.Result Execute(
Autodesk.Revit.UI.ExternalCommandData command_data,
ref string message,
Autodesk.Revit.DB.ElementSet elements)
{
var document = command_data.Application.ActiveUIDocument.Document;
var level_id = new ElementId(1526);
// create line
XYZ point_a = new XYZ(-10, 0, 0);
XYZ point_b = new XYZ(10, 10, 10);
Line line = Line.CreateBound(point_a, point_b);
using (var transaction = new Transaction(doc))
{
transaction.Start("create walls");
Wall wall = Wall.Create(doc, line, level_id, false);
var position = new XYZ(0, 0, 0);
var symbolId = document.GetDefaultFamilyTypeId(new ElementId(BuiltInCategory.OST_Walls));
if (symbolId == ElementId.InvalidElementId) {
transaction.RollBack();
return Result.Failed;
}
var symbol = document.GetElement(symbolId) as FamilySymbol;
var level = (Level)document.GetElement(wall.LevelId);
document.Create.NewFamilyInstance(position, symbol, wall, level, StructuralType.NonStructural);
transaction.Commit();
}
return Result.Succeeded;
}
Work through the Revit API getting started material and all will be explained. That will save you and others many further questions and answers.
To address this specific question anyway, GetDefaultFamilyTypeId presumably does not do what you expect it to for wall elements. In the GetDefaultFamilyTypeId method API documentation, it is used for structural columns, a standard loadable family hosted by individual RFA files. Walls are built-in system families and behave differently. Maybe GetDefaultFamilyTypeId only works for non-system families.
To retrieve an arbitrary (not default) wall type, use a filtered element collector to retrieve all WallType elements and pick the first one you find.
Here is a code snippet that picks the first one with a specific name, from The Building Coder discussion on Creating Face Wall and Mass Floor
:
WallType wType = new FilteredElementCollector( doc )
.OfClass( typeof( WallType ) )
.Cast<WallType>().FirstOrDefault( q
=> q.Name == "Generic - 6\" Masonry" );

How to Create a Purchase Receipt with Document Details via code

The Goal is creating a Purchase Order and then its corresponding Purchase Order receipt via code with 2 separate actions/buttons.
The PO (Type Normal) is created without any issues. And is then Approved via code making it visible in the "Add Purchase Order" smartpanel from the Purchase Receipt page.
The UI workflow would be the selection of the PO order and then pressing on "ADD PO".
I'm looking to replicate that via code.
Looking at the page's ASPX definition I can see that the smartpanel button is associated to action AddPOOrder2
I'm creating the Purchase receipt like this:
if (orderRecord.Approved == true)
{
poReceiptEntryGraph = PXGraph.CreateInstance<POReceiptEntry>();
receiptRow = new POReceipt();
//Summary
receiptRow.ReceiptType = "RT";
receiptRow = poReceiptEntryGraph.Document.Insert(receiptRow);
receiptRow.Hold = false;
receiptRow.ReceiptDate = DateTime.Now;
receiptRow.VendorID = orderRecord.VendorID;
receiptRow.InvoiceNbr = "123";
poReceiptEntryGraph.Document.Update(receiptRow);
poReceiptEntryGraph.Actions.PressSave();
Then I create a PXView:
int startActualRow = PXView.StartRow;
int totalActualRows = 1;
List<Object> createdView = new PXView(poReceiptEntryGraph, false, PXSelect<POOrder, Where<POOrder.orderNbr, Equal<Required<POOrder.orderNbr>>>>
.GetCommand()).Select(PXView.Currents, /*Filter value from the BQL Required*/ new object[] { "PO000683"/*orderRecord.OrderNbr*/ },
PXView.Searches, PXView.SortColumns, PXView.Descendings, PXView.Filters,
ref startActualRow, PXView.MaximumRows, ref totalActualRows);
PXView dummyActualView = new DummyView(poReceiptEntryGraph, poReceiptEntryGraph.Document.View.BqlSelect, createdView);
Finally, the PXView is used to press on the AddPOOrder2 action:
poReceiptEntryGraph.addPOOrder2.Press(new PXAdapter(dummyActualView));
poReceiptEntryGraph.Actions.PressSave();
No error messages are received and the summary section of the Receipt gets created correctly but without any content in the grid.
I also attempted to use addPOOrder which is another Acumatica action that executes addPOOrder2 but the result was the same.
Any ideas if I'm missing something?
Thanks.
I found the solution for this.
Acumatica's AddPOOrder2 action iterates over the selected records and invokes method AddPurchaseOrder
Invoking the method directly in my action worked correctly:
if (orderRecord.Approved == true)
{
poReceiptEntryGraph = PXGraph.CreateInstance<POReceiptEntry>();
receiptRow = new POReceipt();
receiptRow.ReceiptType = "RT";
receiptRow = poReceiptEntryGraph.Document.Insert(receiptRow);
receiptRow.Hold = false;
receiptRow.ReceiptDate = DateTime.Now;
receiptRow.VendorID = orderRecord.VendorID;
poReceiptEntryGraph.Document.Update(receiptRow);
poReceiptEntryGraph.Actions.PressSave();
poReceiptEntryGraph.AddPurchaseOrder(orderRecord);
poReceiptEntryGraph.Actions.PressSave();
}
However, I wonder, had the method not existed, was I in the correct path with the use of the PXView and the PXAdapter? Is it possible to execute other similar actions that may not have a method?

Creating a shortcut for Gmail canned response

I'm currently using Gmail Lab feature - canned responses. I have a lot of these canned responses and using their menu to find the right one, proves to be time-consuming. It would be way easier to find a canned response by:
linking a canned response to a keyword
using that keyword in the body or subject field. Something like this.
Would this be possible by using Gmail API or would you suggest another way to do it?
How is this workflow? Add the label "CannedResponses" to all your prepared replies. Then mark each with the particular label the reply applies to, eg 'TestLabel1'. Then as new emails come in you label them, and after that you run a script like this:
function CannedReply() {
var label = "<mylabel>"; //eg <myLabel> = TestLabel1
var myemail = "<me#gmail.com>";
var responsebody = GmailApp.search(
"label:" + label + " label:CannedResponses"
)[0].getMessages()[0].getBody();
var threads = GmailApp.search("label:" + label + " -label:CannedResponses label:unread");
for (var i = 0; i < threads.length; i++) {
for (var j = 0; j < threads[i].getMessageCount(); j++) {
message = threads[i].getMessages()[j];
message.reply("", {htmlBody: responsebody, from: myemail});
GmailApp.markMessageRead(message);
}
}
}
using that keyword in the body or subject field
Autohotkey would support this, it's an app that lets you map key combinations or keywords to text macros. You wouldn't be using any native Gmail features this way, including their canned responses feature, but it might suit your need well enough.

Is there a C# implementation of Redis-rdb-tools?

Taking a look at Redis-RDB-Tools, it looks like there are some useful functions for monitoring the health of your Redis server.
ServiceStack.Redis seems to have a good set of client functions (but I'm using BookSleeve).
Are there any C# implementations that give me some basic health checks - consumed memory, disk usage, etc?
-- UPDATE --
Thanks to BookSleeve's GetInfo() command, the following is returned... however I should have been more specific: Is there a way of getting back the server info as parameters/object properties or a pre-packaged way of parsing the output values?
Here is the output from GetInfo():
"# Server\r\nredis_version:2.6.10\r\nredis_git_sha1:00000000\r\nredis_git_dirty:0\r\nredis_mode:standalone\r\nos:Linux 2.6.32-279.19.1.el6.x86_64 x86_64\r\narch_bits:64\r\nmultiplexing_api:epoll\r\ngcc_version:4.4.6\r\nprocess_id:2492\r\nrun_id:62402d583871f4b83f469917966aed8d163d02f3\r\ntcp_port:6379\r\nuptime_in_seconds:502354\r\nuptime_in_days:5\r\nlru_clock:1928056\r\n\r\n# Clients\r\nconnected_clients:7\r\nclient_longest_output_list:0\r\nclient_biggest_input_buf:175\r\nblocked_clients:0\r\n\r\n# Memory\r\nused_memory:1402576\r\nused_memory_human:1.34M\r\nused_memory_rss:9719808\r\nused_memory_peak:1675192\r\nused_memory_peak_human:1.60M\r\nused_memory_lua:31744\r\nmem_fragmentation_ratio:6.93\r\nmem_allocator:jemalloc-3.2.0\r\n\r\n# Persistence\r\nloading:0\r\nrdb_changes_since_last_save:3035\r\nrdb_bgsave_in_progress:0\r\nrdb_last_save_time:1360955487\r\nrdb_last_bgsave_status:ok\r\nrdb_last_bgsave_time_sec:-1\r\nrdb_current_bgsave_time_sec:-1\r\naof_enabled:0\r\naof_rewrite_in_progress:0\r\naof_rewrite_scheduled:0\r\naof_last_rewrite_time_sec:-1\r\naof_current_rewrite_time_sec:-1\r\naof_last_bgrewrite_status:ok\r\n\r\n# Stats\r\ntotal_connections_received:18822\r\ntotal_commands_processed:12547\r\ninstantaneous_ops_per_sec:3\r\nrejected_connections:0\r\nexpired_keys:0\r\nevicted_keys:0\r\nkeyspace_hits:374\r\nkeyspace_misses:39\r\npubsub_channels:1\r\npubsub_patterns:0\r\nlatest_fork_usec:0\r\n\r\n# Replication\r\nrole:master\r\nconnected_slaves:0\r\n\r\n# CPU\r\nused_cpu_sys:57.82\r\nused_cpu_user:208.63\r\nused_cpu_sys_children:0.00\r\nused_cpu_user_children:0.00\r\n\r\n# Keyspace\r\ndb0:keys=6,expires=0\r\n"
With regards to the updated question: the information there is not currently exposed as "parsed", but that sounds like a reasonable thing to add; I suspect I'll hide the GetInfo() method, move it to .Server.GetInfo(), and expose it in a parsed form. The code to split it already exists, though - but as a private method: RedisConnectionBase.ParseInfo:
static Dictionary<string, string> ParseInfo(string result)
{
string[] lines = result.Split(new[] { "\r\n" }, StringSplitOptions.RemoveEmptyEntries);
var data = new Dictionary<string, string>();
for (int i = 0; i < lines.Length; i++)
{
string line = lines[i];
if (string.IsNullOrEmpty(line) || line[0] == '#') continue; // 2.6+ can have empty lines, and comment lines
int idx = line.IndexOf(':');
if (idx > 0) // double check this line looks about right
{
data.Add(line.Substring(0, idx), line.Substring(idx + 1));
}
}
return data;
}
Call Redis's INFO command, it provides all the different server info stats inside a redis-server.
Here's a page dump of all the available stats on a 2.5.12 version of redis-server.

JavaScript global variable to store kml model object

I'm developing a webpage to display google earth and a kml object. There will be two frames, one is the earth + kml object, the other is to display kml object's info like altitude, latitude, longitude...
I'm done with load the kml object and display its info on the page. Now, I want to add some events to control the kml object with keyboard, to move it and reflect all the changes in coordination onto the display frame.
In order to do that, I create my own object:
//Constructor for object ModelInfo
function ModelInfo(name) {
var me = this;
me.model = null;
me.name = name;
me.lon = 120.89250214028388;
me.lat = 22.17480037801846;
me.alt = 15.00;
me.heading = 0.0;
me.tilt = 0.0;
me.roll = 0.0;
me.kmlUrl = "";
me.ALTITUDE_MODE = ge.ALTITUDE_RELATIVE_TO_GROUND;
me.scaleX = 0.3;
me.scaleY = 0.3;
me.scaleZ = 0.3;
}
When I fetchKml, I store the kml model into my objectInfo.model:
// Fetch a KML file and show it
function finished(object, objInfo) {
if (!object) {
// wrap alerts in API callbacks and event handlers
// in a setTimeout to prevent deadlock in some browsers
setTimeout(function() {
alert('Bad or null KML.');
}, 0);
return;
}
var modelPlacemark;
walkKmlDom(object, function() {
if (this.getType() == 'KmlPlacemark' && this.getGeometry()
&& this.getGeometry().getType() == 'KmlModel') {
modelPlacemark = this;
}
});
var model = modelPlacemark.getGeometry();
objInfo.model = model;
This is how I call fetchKml
shutter = new ModelInfo("Shutter"); //shutter is global variable
shutter.kmlUrl = 'http://120.125.80.113/kml/student/space_shuttle_23_20110812a/space_shuttle_23_20110812a_SP.kmz';
google.earth.fetchKml(ge, shutter.kmlUrl, function(obj) {
finished(obj, shutter);
});
But the problem is, after fetchKml finishes, I try to access shutter.model, it is always null, but when I access shutter.model from within function finished, it is not null
So my question is how did it happen? Is there anyway to store kml object in a global variable to modify its attribute later?
Thanks,
Hans
After several hrs trying to figure out why, I decided to use Firebug to debug the code and found out the reason. I still don't know why though.
The name I used for my variable "shutter" somehow isn't listed as a member of this page when I debugged using Firebug. When I changed it to flying_obj then everything is ok, I was able to store the kml object inside my flying_obj.model
Anyone knows what's wrong with the name "shutter" please explain it to me. It'd be great!!
Hans

Resources