NetSuite Work Orders have a few different status depending on the fields Buildable and Built quantity:
“Released” (when the Built quantity is 0),
“In Progress” (when Built quantity > 0 but not equal to the Buildable quantity) and
“Closed” (when Built quantity = Buildable)
NetSuite Work Orders can also be closed via the blue Close button in the UI. This last can be problematic if there is still work to be performed in the Work Order. Reopening a Work Order is the same as any NetSuite Transaction: Uncheck the IsClosed column of one or more Work Order line items. The problem is there is no way to do this in the UI. Instead, we can run SuiteScript in the Script Debugger (Customization | Scripting | Script Debugger) to update the line items. In the gist below, we load the workorder by ID, set each line item’s isclosed property to False and commit the record to the database. The last nlapiLoadRecord() call is just so we can examine the record is how we expect.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
Information sharing between systems is critical to business agility with REST and SOAP being the two main standards used. With REST, responses are JSON encoded so Salesforce designed the JSONParser library. When looking for example usage of this library I found some blog posts that simply use the readValueAs() method. This is very convenient to parse well structured data into a class, but you don’t always get such nicely structured responses. For example, this endpoint on geonames.org returns:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
{"adminName2":"La Magdalena Contreras","adminName3":"Ciudad de Mexico","adminCode2":"9008","postalcode":"10509","adminCode1":"DIF","countryCode":"MX","lng":-98.99779722222222,"placeName":"Residencial San Carlos","lat":19.20726277777778,"adminName1":"Distrito Federal"}
As can be seen, results always contain the “postalcode”, “countryCode”, and “placeName” (among others) fields. But the fields “adminName2” and “adminName1” may or may not appear. This is inconvenient because readValueAs() won’t work properly so I needed to manually parse the response. Salesforce’s JSON library example and this developer blog post helped my understanding, but I was still left wondering what methods to use and how. To figure this out, I ended up printing every token the JSONParser encountered and its corresponding text. So, I wrote up my findings hoping to save you from that tedious task!
Firstly, in the JSON response, every character except the colon (:) is a token – unless it’s encapsulated in double quotes (“). Within double quotes, the entire string is the token. So, many parsing routines traverse the JSON response with:
while (parser.nextToken() != null) {
Secondly, getCurrentToken() returns type JSONToken enum and getText() method returns the character(s) of that token. So the calling getCurrentToken() at the very start of the JSON above returns START_OBJECT and getText() returns “{”
Thirdly, from the documentation we know:
{ and } are identified by the tokens START_OBJECT and END_OBJECT, respectively
[ and ] are identified by the tokens START_ARRAY and END_ARRAY, respectively
I’ll also add FIELD_NAME is the token on the left side of a colon and the token to the right of a colon is VALUE_xx (e.g. VALUE_STRING, VALUE_TRUE, VALUE_NULL, etc).
Let’s look at this example:
“countryCode”:”PL”
Calling getCurrentToken() returns FIELD_NAME and getText() returns countryCode. If nextToken() is called then getCurrentToken() returns VALUE_STRING and getText() returns PL
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
Line 1 initializes the parser to the start of the JSON stream (the first “{“).
Lines 6 – 9 skip through the JSON stream until the deserializer points inside the first object (adminName2 in this case).
Lines 11 – 46 loop through the JSON stream until I run into an END_OBJECT. When END_OBJECT is found I’ve traversed one object’s data in the response.
Within the loop, lines 14 – 31 check if the token is a FIELD_NAME and matches the desired info. This is safe because we’re inside an object so we will only find FIELD_NAMEs in this example.
Lines 33 – 39 appends the data into my zips variable for display in the VF page’s pageBlockTable. A couple of notes:
The variable found indicates a valid result to display to the user. This way I don’t create empty entries in zips. This only occurs if no results were found for a user’s input.
zipListIndex identifies the radio buttons on the VF page. So, the user selected radio button identifies which location they chose. To see how all this in action refer to my previous post.
Lines 41 – 45 skip the current END_OBJECT token and breaks out of the loop if the array’s end is reached.
So, that’s how I used the JSON Parser library to deserialize a JSON response. While not a very complex example, it’s useful to illustrate the basics of operation. If I find a more sophisticated response I’ll post about it.
I wrote two prior How To’s doing zip code lookups in a VisualForce page and in a trigger. This post expands on the zip code lookup functionality using geonames web services because the service I used previously, ziptasticapi.com, only supports zip codes in the United States. Geonames.org also offers richer results and additional webservices beyond postal code lookup.
Creating a free account on geonames.org gives a generous limit of 30k API calls per day or 2k calls per hour. As with all freemium models there’s also a paid subscription with better SLAs. One complication is the website returns more hits (unless filtered) and the format of the results have more variability. This requires a deeper understanding of Salesforce’s JSON Parser beyond the readValueAs() method. For example, lookup “10509” on geonames yields the below return. More on this in another post.
{"postalcodes":[
{"adminName2":"Olsztyn","postalcode":"10-509","countryCode":"PL","lng":20.4833333,"placeName":"Olsztyn","lat":53.7833333,"adminName1":"Warmińsko-Mazurskie"},
{"adminName2":"Putnam","adminCode2":"079","postalcode":"10509","adminCode1":"NY","countryCode":"US","lng":-73.599179,"placeName":"Brewster","lat":41.409704,"adminName1":"New York"},
{"postalcode":"10509","countryCode":"DO","lng":-70.24743589230769,"placeName":"Carmen Amelia ","lat":18.721794876923077},
{"postalcode":"10509","countryCode":"DO","lng":-70.24743589230769,"placeName":"La Agustinita ","lat":18.721794876923077},
{"adminName2":"La Magdalena Contreras","adminName3":"Ciudad de Mexico","adminCode2":"9008","postalcode":"10509","adminCode1":"DIF","countryCode":"MX","lng":-98.99779722222222,"placeName":"Residencial San Carlos","lat":19.20726277777778,"adminName1":"Distrito Federal"}]}
Visual Force Page
The VisualForce page looks similar to the previous example but lists results in a table. In addition, logic is added so users can choose one of the results via a radio button. See the below screenshot.
Zip code lookup results
The VisualForce page source code is
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
Lines 5 – 12 which contains the apex:actionRegion is nearly the same as the first version.
Lines 15 – 35 use the apex:pageBlockTable component to list the returned array of results.
Lines 37 – 43 use apex:actionFunction to call the controller’s sendZipSelection() method with the user’s selection.
One interesting detail is <input type = “radio”> on line 19. Since VisualForce supports HTML pass-thru, we can use HTML input tags to create radio buttons. At first, I tried the apex:selectRadio component but the radio buttons only showed horizontally which was visually unappealing. Subsequently, I discovered layout=”pageDirection” attribute which organizes radio buttons vertically, but I digress… The onclick attribute of the input tag invokes the actionFunction component to call the controller’s sendZipSelection() method with the number of the user selected radio button (z.zipCount) as the parameter.
Controller Code
The controller has evolved to support the new requirements.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
Lines 13 – 21 are properties to accept user input for zip code & country.
Lines 24 – 27 are called by actionFunction so the controller knows what radio button was selected.
Lines 29 – 37 display the list of results in the pageBlockTable.
Lines 39 – 80 is an inner class storing details about a zip code and the methods to expose those details.
Lines 92 – 118 calls geonames’ web service.
Lines 119 – 165 parses the returned JSON stream and saves the data.
While it feels like overkill to make zipInfo’s member variables private thus requiring all those set methods, i thought it best to maintain a separation of concerns. This way, if the code get re-used, access is controlled through member functions instead of letting any code manipulate member variables on a whim.
I recently passed Salesforce’s Winter 15 ADM201 Administrator certification test! Although I spend as much time as I can doing development I’m also the solo admin of an org and have a broad range of responsibilities. So, I decided ADM201 certification was important and having it as an MBO ensured I made the time to do it. 🙂
Salesforce offers test prep classes, but they’re expensive. Instead, I joined certifiedondemand.com for a very worthwhile $40. John does a good job organizing the material and his practice test is effective. I also found a number of other practice test questions online. One site I like is abetterstudyguide.com. A few questions show up verbatim on the test, but the scenario-based questions are invaluable because it forces you to think the answer through. This is helpful as Salesforce changes the form of questions you might find online, but not the topic.
While reading and studying is very necessary there’s no substitute for actual hand’s on practice. For example, just days before my test date one user asked about why mass edits with enhanced list views didn’t work. Turns out, they hadn’t set the record type in their filter. Was there a question on the test about this? You betcha!
Lastly, I took the online-proctored test due to convenience. Allot yourself extra time for test setup as the ‘take test’ button is enabled 15 minutes prior to your appointment. Even though I installed Sentinel well ahead of time, it wasn’t until I tried starting the exam that I realized an external webcam was required! Since I used the built-in webcam to register I wrongly assumed I could use it to take the test. Fortunately, the Krypterion support guy was able to reschedule my test 30 minutes later so I could go find an external webcam. He also helped me setup the webcam as it needs to show your face, hands and keyboard. So, it worked out in the end, but this is not the kind of stress you want right before your exam!
Our case assignment rules assign newly created web-to-case and email-to-cases to a queue which emails our support team. Unfortunately, a single email isn’t sufficient and we needed a way to quickly see unassigned cases. It had to auto-refresh, so the data did not grow stale, and use a minimum amount of screen space. I decided a VisualForce page was best as it could be fully customized, but I had to figure out how to get the data.
I went through three different approaches. Ultimately, I implemented a custom list controller to populate the data on the VisualForce page and then used the apex:actionPoller component to refresh the page. Here’s a screenshot of the results:
VisualForce List Controller
This is the VF page I used:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
Incidentally the div tag and CSS styling is needed to enforce size restrictions because I couldn’t get the width attribute to work. That needs to be figured out at another time.
This is the list view controller code:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
As I said, I took three different approaches. My first thought was the Streaming API was ideal. Alas, this didn’t work because PushTopic queries do not support relationships. Since my SOQL query needed to use the Case Owner’s Name as a filter ( SELECT CaseNumber FROM Case WHERE Owner.Name = ‘Open Cases’) I could not use the Streaming API.
My second approach used apex:enhancedList component. This component referenced a specific, predefined list view which showed these unassigned cases. I cribbed Kevin Carothers suggestion to get Javascript to refresh the page. Here’s what I ended up with:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
This worked except I wasn’t sure reloading the whole page was a good idea. I found ways to refresh a part of a page, but I’d have to learn jQuery just to refresh a part of a page. In the end, I killed this idea because I couldn’t rid of the styling, the buttons and reducing the size of the list view made things ugly. See this screenshot:
The recent “POODLE” vulnerability announcement articulates a vulnerability in OpenSSL’s SSL protocol 3.0. As a result, many organizations have disabled the usage of that security protocol. Salesforce.com’s announcement they would no longer support SSL 3.0 for any in-bound or out-bound traffic left me scrambling to figure out what protocols we used. Fortunately, I work at a company with a bunch of sharp networking engineers who helped me check the actual wire traffic being sent. Use tcpdump to capture the packet traffic with the following command line:
tcpdump -i eth0 -s0 -nxX tcp and port 443 -w out.pcap
-i = The interface to listen on (use ifconfig to list your interfaces).
port 443 = Port number for SSL with 443 being the default.
-w out.pcap = Specify the output capture file.
After running tcpdump, run a transaction to access Salseforce and use Wireshark to open the capture file (out.pcap in my case). In the screenshot below I highlighted the relevant bits with a red square showing the security protocol used. As an aside, TLSv1 is not the latest & greatest so it’s time to update my openssl library!
Pitfall #1 – A trigger cannot make a callout due to latency so a new function must be called that’s annotated with “@future“.
Pitfall #2 – Another annotation (callout = true) must be included to allow callouts
Pitfall #3 – SObjects cannot be passed to an @future method. Instead, IDs must be passed limiting processing to “after insert” triggers instead of “before insert” (because before the record is created the ID is unknown).
Pitfall #4 – Because of pitfall #3, we must safeguard we don’t cause an infinite loop.
Here’s my trigger stub:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
With the above restrictions in mind here’s the Apex class I wrote to do the work. I put comments in to show what code is dealing with which pitfall listed above.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
Without too much work this can also be modified to support a ‘before update’ trigger. This would always check the account’s city and state matches its zip code anytime an account changes.
Doing a zip code lookup to get city and state is such a common task and yet the Salesforce platform does not natively support this. This simple function benefits both the user by making entering addresses easier and the Salesforce administrator by ensuring data cleanliness and uniformity. Although a number of App-exchange packages support this functionality the ones I browsed are very fully featured and way overkill for a simple zip code lookup. So, I went looking for a free zip code lookup service I could use. There are a number of sources – even the US Postal Service does this! I used ziptasticapi.com because it’s very straightforward to implement as we shall see.
I created a VisualForce page for the UI and a matching Apex custom controller to implement the REST callout and supporting logic. Below is a screenshot of the VF page. Users enter their 5 digit zip code and click Lookup! The bottom half then displays the city, state and country.
Here’s the VF source code. A bit of explanation for orientation: The first <apex:pageBlock> component accepts the user input and includes the Lookup! button. The second <apex:pageBlock> component refreshes with the city, state and country when the Lookup button is pushed. For more details and examples of VF development, I recommend checking out the VisualForce Workbook. Tutorial #11 describes the refresh technique shown here. For completeness, here’s the VisualForce Developer’s Guide as well.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
Below is the matching controller. The top half of the class contains the property declarations the VF page binds to for I/O. The lookup() method in the bottom half is where all the good stuff happens. After building the end point, making the callout and basic error checking, I invoke Salesforce’s JSONparser class. This handy class contains functions to aid in parsing of JSON responses. Here’s Salesforce’s example of using the class. One feature not used in the example is the readValueAs() method. As I looked for examples of JSON parsing (because let’s face it who wants to write Yet Another Parser from scratch?) I came across Abhinav Gupta’s blog post about parsing JSON in one line of code. All that’s needed is to declare a class matching the JSON response, advance the stream pointer to desired data and call readValueAs(). In one fell swoop the response is slurped up into your class for easy digestion. For more details take a gander at the Apex Developer’s Guide.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
One last detail: If you want to try the above code, you’ll need to add permissions for Salesforce to make the callout to ziptastic. You can do this by going to Setup | Security Controls | Remote Site Settings and adding a new Remote site to the list.
I recently ran into a problem trying to install a managed package in my org. Salesforce gave a “This will take a while so I’ll email you when it’s done” message. Although I’d get the email, package would fail to install. I discovered the failure was because my unit tests (UTs) failed during the package installation. Oddly, the UTs passed when run manually. By using the debug logs, I discovered the the failure managed package because it used API v31 whereas my UT class used v24. By changing my UT to use API v31, it failed every time. Debugging & fixing the problem then became the standard exercise of examining debug logs to ascertain what went wrong.
To change your class’s API version use Setup | Develop | Apex Classes and hit Edit next to your class (see below).
Edit Apex class attributes
Next, click the Version settings tab and use the picker to choose the desired Salesforce.com API as per below.
Changing API versions from the SFDC UI
Note – Changing API versions like this can only be done in a sandbox or developer org. You cannot directly change production like this, though.
You can also use Developer Console to change the API version. Simply File | Open | <class name> and there’s an API version drop down available to you. Developer Console still won’t let you directly change production so you’ll have to deploy the change from sandbox into production to update the metadata.
I started using Salesforce’s Cloud Flow (aka Visual Flow) to implement some business logic and was looking to implement the equivalent of a user selectable lookup option in a flow. I ran across this question about handling multiple records and Elcalvo Mike suggested a dynamic choice. BigWill asked how this could be used to do a partial match on account names. So, I created a simple flow to demonstrate this.
The screenshot in the below left shows a user entered the string “test” into a Screen Input Field that I named “Account_to_search_for”. The screenshot in the below right is the dynamic choice drop down listing accounts with “test” in their name. The user clicks a selection to save their choice.
This next screenshot illustrates creating the dynamic choice. It performs a record lookup on Accounts whose Name is a partial match for the user input (the blue highlighted “Account_to_search_for” is the Screen Input Field from the above left screenshot). The data listed in the drop down are all the returned records’ Names (specified in the Choice Selected Value).
Dynamic Choice Screenshot
One last feature is under the “Additional Options” which lets you specify what fields get saved for the user selected record. For my example, I saved the account name and Salesforce ID for display.