Need to prompt user for text during NetSuite Workflow - javascript

Business logic: when an Approver rejects an expense report, an e-mail must be sent to the creator. This e-mail must contain the reason for rejection.
Existing setup: A multi-state workflow has already been set up, that sends the expense report through two separate approvals. Each Approver can approve or reject the workflow. Rejecting the workflow sends it back to the submission state for correction by the creator. My task is to acquire the rejection text and create the outgoing e-mail.
Obvious solutions rejected:
Send Email workflow action-- this WF action allows only boilerplate e-mails to be sent (with some parameterization). Nothing can be customized from the user's perspective.
Workflow Action Script-- this script context does not allow the use of JavaScript dialog presentations, such as window.confirm() or window.prompt(). There are popup parallels in the workflow action palette, but only for confirm() or alert()-- no prompt(). Unfortunately the technical requirements and restrictions for Workflow Action scripts are horribly documented, so this result was learned only after spending a few days researching and writing the script.
Add a tracking field on the expense report that must be filled in before the report can be Rejected. However, this requires unlocking the record, an issue for Audit concerns. It also must be made visible and hidden for appropriate states, and can be adjacent to only one set of action buttons.
The new state is not an end-state, so e-mail generation is not automatic as it is for end-states. We just want similar functionality.
The only other possiblity I see is to target a new page, such as a Suitelet. However, I only need a single string from the user. A Suitelet seems overkill, plus it makes the workflow more complicated to go back to the correct report.
Any insight or ideas that anyone might have would be most helpful.

Well, I've tried several other solutions and none of these seem to work:
Redirect (via nlapiSetRedirectURL() in a WFA script) on state Exit trigger to a Suitelet that takes the parameters passed from the workflow where the user enters the rejection text; then redirect to the expense report. This fails because the report state does not actually change.
Do the same thing, but from the Entry trigger of the new state. Requires some more detailed parameter handling but this also does not work. Apparently redirecting from any part of the UI experience cancels the workflow transition.
Setting the "User Interface" context on the workflow action also does not work; the redirection still kills the transition.
The nlapiTriggerWorkflow() function also does not seem to have an effect, even when the UI context is set on the action. No errors or debug text generated.
The user may just have to accept manual behaviors like, adding a note and sending a canned e-mail. This appears to be a major feature hole, either deliberate or not. Note that there is a Confirm and a Show Message action, but no Prompt. So why not? No details, just deal with it I guess.

Final solution:
A separate workflow state where a script runs. A new button on the workflow redirects to this new state.
A workflow action script in these special state(s) that has parameter settings that are changed depending on where they are in the workflow. This script redirects to the suitelet (next), which interrupts the workflow transition and keeps the item in the same state.
A suitelet that takes the user text in a textarea, and a non-submit action button. Don't want to use a submit button, because that reloads the same page, creating an extra step.
A client script that takes parameters from the suitelet button event, creates the e-mail, and redirects back to the original record (that is in the same workflow state as before).
Of course this is inelegant. The user must press a button to create the e-mail, and a separate button to transition to the correct state. It fulfills the user's needs, but it requires them to remember to press one button to create the e-mail reason text, and another button to actually reject the record.
The need for this convoluted solution is because of all the roadblocks in NetSuite design:
Can't prompt for text from a server-side WF action script. We can confirm() giving a Y/N (Ok / Cancel) answer, but somehow string returns are not allowed.
Can't complete a transition if a WF action script redirects to another page.
Suitelet submit buttons reload the same page, so we need a client script to do the final e-mail creation work.
Feature hole much?

There is a limitation on the workflow that it cannot accept input from the user. Hence, we need to go ahead with a customized solution for this scenario. I have implemented this in multiple NetSuite projects. Here is the solution which works
(1) Have a workflow action script which would call the suitelet. Please see script sample below for workflow action script
define(['N/record','N/runtime','N/redirect'],
function (record,runtime,redirect){
function callSuitelet(context)
{
try {
var currentRecord = context.newRecord;
var vendorId = currentRecord.id;
var vendorNumber = currentRecord.getValue('entityid');
redirect.toSuitelet({
scriptId: 'customscript_call_rejection_reason',
deploymentId: 'customdeploy_call_rejection_reason',
parameters: {'recid':vendorId,'vbTransactionNo':vendorNumber, trantype: context.newRecord.type}
});
}
catch (err) {
log.error("Error while calling Suitelet", err);
throw err;
}
}
return {
onAction: callSuitelet
};
});
(2) Have a suiteLet designed to capture the "Rejection Reason"
(a) Add a field on the suitelet form labelled as "Rejection Reason" (FieldType.TEXTAREA)
(b) Add a "Submit" button which will add the data to the transaction record
(c) Redirect the suitelet back to the transaction record once "submit" button is clicked
This should solve the problem stated above

Related

Is there any way to detect a drop-in braintree.js form's submit click?

I'm using a braintree.js drop in form. I'm submitting it with ajax, by registering for the onPaymentMethodReceived callback. So far so good, it works fine.
However, after submitting the form, there's a two step process: first the payment details are submitted to braintree and verified (while a spinner shows over the form), then the details on the page are anonymised, and the onPaymentMethodReceived callback fires with a nonce I can use to send to my server.
The problem is I'd like to disable the form submission button when it's clicked, but registering an onClick handler on it causes braintree to ignore the click.
I understand that the customer's card details are visible on the page at this point, but I can't grab them anyway due to the iframe being from a different domain, and any potential method I could use at this point to grab the details I could do with setInterval() anyway, so I don't really see a security case for this.
Is there any way to detect the click here?
Full disclosure: I work at Braintree. If you have any further questions, feel free to contact support.
To my knowledge you can't jump in the middle of the tokenization process with the Drop-In. It sounds like you are looking to create a custom experience for your users that steps beyond the Drop-In use case.
Enabling a form submit button after the onPaymentMethodReceived callback is the common Drop-In use flow, but by creating a custom integration you can directly handle the client-side tokenization process and wrap it with whatever functionality you need:
var client = new braintree.api.Client({clientToken: "CLIENT-TOKEN-FROM-SERVER"});
client.tokenizeCard({
number: "4111111111111111",
expirationDate: "10/20"
}, function (err, nonce) {
// Send nonce to your server
});

Facebook Flex and feedback from Actions

I'm playing around with Facebook Flux (I'm using Fluxxor, but I don't think that's really important) with ReactJS, and so far I think they its a great way of working with the data flow in an application. However, there's one thing that I'm really struggling to get my head around. It might be that this is simply something that shouldn't be done with Flex, or that I'm missing something obvious, but hence why I'm asking...
For example, I'm building a system to log in with. Very simple - there's a Login dialog that pops up, and you enter your username and password and press the button. This calls the LoginAction.login(username, password) Action Creator, which sends the LOGIN Event to the Dispatcher and then triggers the API call to authenticate the user and make sure the credentials are correct. If we get a success back from the API then we trigger the LOGIN_SUCCESS Event to the Dispatcher, the SessionStore handles this and stores the fact that we have successfully logged in, and the details of who we are. This then triggers bits of the UI to update - for example the "Log In" button changes to a "Hello Graham" bit of text, and a "Log Out" button instead. That's all really easy and just works and makes sense.
What I'm getting stuck with is when the login fails. If I enter an invalid username/password then I want the Login Dialog to tell the user this, so that they can correct what they entered and try again. The only way that I can think of to achieve this is to send a LOGIN_FAILED Event to the Dispatcher, which is then handled by some Store that stores the last Login errors for the Dialog to display. This just feels weird though, because these errors are not application state but are instead a transitive piece of information about this one request that failed, that the user will then correct and retry.
It feels to me that this transitive state is going to be very common around API calls that might fail because of user input, and so don't belong as part of the application state but instead belong somewhere else. However, I can't work out how Flux allows this transitive state to get back to the UI to be displayed to the user...
SessionStore handles this and stores the fact that we have successfully logged in
In your case you keep information about successful auths. Why not to keep info about unsuccessful once also at store (the same store or independent once which keeps auth state or permissions state for user)?
It's another side of your state. In this case you've just have to dispatch special event on failure (like in you case about successful login) to store(s), save new state and send changes to the UI.
Here is the example which is similar to what i mean. You send a request to the server ant can dispatch an action if login fails.

Javascript OnPageUnload - on "leave page" must call additional method

This is the problem: my web application (php) has a wizard feature which gathers customer's data page by page, and stores it in session. If customer tries to navigate away from the page before they have completed the wizard, I would like to display a massage to the effect of "You will lose your data". If the customer chooses to navigate away, the session data should be wiped.
I know that I can intercept this action by binding onpageunload event, but is there a way to then make another call, e.g. ajaxClearWizard() if the customer says "yes"?
PS I can see that, perhaps session shouldn't be used here, but I'm using an existing library, and although this wizard-data-persistence used to be a required feature the business now requires it to be removed :(
Any ideas, alternatives?
Thanks in advance!
window.onbeforeunload = function () {
return 'Your content has not been properly saved yet!';
};
This will make the browser display a confirmation box in middle with above content.

able to cause an exception on webportal server after setting webbrowser's javascript to disable

(i am a software tester, not a software developer. i am testing a software developer's webportal (tomcat) / database (mysql) software)
In the client webbroswer, I have to have cookies enabled (default) and javascript enabled (default) in order to log-in. I am using FF3.5.5.
Once successfully logged in, I then disable the javascript setting on the webbrowser.
I am logged into the webportal in order to tail the log -- in order to monitor for exceptions. I am also logged into the database (mysql) -- in order to see any changes in the database.
pwd
/usr/local/tomcat/logs
The webportal provides to the user, four "add/edit form pages" that the user can navigate into and enter data into and then click on the submit button (to write to the database)... AND each of these four "add/edit form pages" are designed with "client side javascript field checking" -- to make sure that the user fills out the 'required' fields (Note: In this case, I am only interested in the case where there is error checking upon clicking on the submit button).
Two of the four "add/edit form pages" do not display when navigated to. I would say that this is a pass -- SINCE javascript is disabled on the client.
Though, there is no message "bubbled up to the user" explaining why the webportal has choosen not to display the "add/edit form" to the user (fail).
The other two allow me to navigate into them. I would say that this is a fail.
One of these "add form pages" -- that I am able to navigate to, allows me to then "submit" the form (with all of the required fields intentionally left in the null state -- upon submit) (fail). This then causes the webportal to throw an exception (fail). The database table is not changed (pass).
One of these "add form pages" -- that I am able to navigate to, allows me to then "submit" the form (with all of the required fields intentionally left in the null state -- upon submit) (fail). This then does NOT cause the webportal to throw an exception (pass). The user is able to write the info to the database table (if it was the first submission using this form for the account) (fail).
I believe that my assessments of the passes and fails above are correct.
I am curious to know what the proposed fix would be in actual code.
it looks to me like the portal is lacking server-side validation and relies on javascript for validating. This is a major security flaw and should be fixed. So i guess the following should pass with javascript turned off
user is able to view the form
user is able to submit the form with valid data
user is able to submit invalid data and gets an exception (or better, a friendly message) from the server

What are techniques to get around the IE file download security rules?

Internet Explorer (with default settings, which I generally assume will be in effect on the desktops of the Great Unwashed) seems to dislike the idea of accepting attachment content in an HTTP response if the corresponding request wasn't made directly from a user action (like a "click" handler, or a native form submit). There are probably more details and nuances, but that's the basic behavior that's frustrating me.
It seems to me that this situation is common: the user interface in front of some downloadable content — say, a prepared PDF report — allows for some options and inputs to be used in the creation of the content. Now, as with all forms that allow the user to stipulate how an application does something, it's possible that the input will be erroneous. Not always, but sometimes.
Thus there's a dilemma. If the client tries to do something fancy, like run an AJAX transaction to let the server vet the form contents, and then resubmit to get the download, IE won't like that. It won't like it because the actual HTTP transaction that carries the attachment back will happen not in the original user-action event handler, but in the AJAX completion callback. Worse, since the IE security bar seems to think that the solution to all one's problems is to simply reload the outer page from its original URL, its invitation to the user to go ahead and download the suspicious content won't even work.
The other option is to just have the form fire away. The server checks the parameters, and if there's anything wrong it responds with the form-container page, peppered appropriately with error messages. If the form contents are OK, it generates the content and ships it back in the HTTP response as an attached file. In this case (I think), IE is happy because the content was apparently directly requested by the user (which is, by the way, a ridiculously flimsy way to tell good content from bad content). This is great, but the problem now is that the client environment (that is, the code on my page) can't tell that the download worked, so the form is still just sitting there. If my form is in some sort of dialog, then I really need to close that up when the operation is complete — really, that's one of the motivations for doing it the AJAX way.
It seems to me that the only thing to do is equip the form dialogs with messaging that says something like, "Close this when your download begins." That really seems lame to me because it's an example of a "please push this button for me" interface: ideally, my own code should be able to push the buutton when it's appropriate. A key thing that I don't know is whether there's any way for client code to detect that form submission has resulted in an attachment download. I've never heard of a way to detect that, but that'd break the impasse for me.
I take it you're submitting the form with a different target window; hence the form staying in place.
There are several options.
Keep the submit button disabled and do ongoing validation in the background, polling the form for changes to fields and then firing off the validation request for a field as it changes. When the form is in a valid state, enable the button; when it isn't, disable the button. This isn't perfect, as there will tend to be a delay, but it may be good enough for whatever you're doing.
Do basic validation that doesn't require round-trips to the server in a handler for the form's submit event, then submit the form and remove it (or possibly just hide it). If the further validation on the server detects a problem, it can return a page that uses JavaScript to tell the original window to re-display the form.
Use a session cookie and a unique form ID (the current time from new Date().getTime() would do); when the form is submitted, disable its submit button but keep it visible until the response comes back. Make the response set a session cookie with that ID indicating success/failure. Have the window containing the form poll for the cookie every second or so and act on the result when it sees it. (I've never done this last one; not immediately seeing why it wouldn't work.)
I expect there are about a dozen other ways to skin this cat, but those are three that came to mind.
(Edit) If you're not submitting to a different target, you might want to go ahead and do that -- to a hidden iframe on the same page. That (possibly combined with the above or other answers) might help you get the user experience you're looking for.
There's a whole number of really good reasons IE does this, and I'm sure it's not something anyone would argue with - so the main objective is to get around it somehow to make things better for your users.
Sometimes its worth re-thinking how things are done. Perhaps disable the button, use javascript to check when all the fields are filled out, and fire off an ajax request once they are. If the ajax was successful, enable the button. This is but one suggestion, I'm sure there will be more...
Edit: more...
Do simple submission (non-AJAX), and if the checks fail, send a page back rather than an attachment. The page sent back could contain all the information originally submitted (plus whatever error message to the user) so the user doesn't need to fill out the entire form again. And I'm also sure there will be more ideas...
Edit: more...
I'm sure you've seen this type of thing before - and yes, it is an extra click (not ideal, but not hard).... an "if your download fails, click here" -> in this case, do it as you want to do it, but add a new link/button to the page when the AJAX returns, so if the download failed, they can submit the already validated form from a "direct user action". And I'm sure I'll think of more (or someone else will).....
I have been fighting a similar issue for a while. In my case, posting to a hidden iframe didn't work if my web app was embedded in an iframe on another site (third party cookie issues) unless our site was added to the Trusted Sites list.
I have found that I could break up the download into POST and GET sequence. The post returns a short lived GUID that can be used in a GET request to initiate the download. The POST can do the form validation as well as return the GUID in a successful response. Once the client has the GUID, you can set the src property of a hidden iframe element to the download URL. The browser sees the 'Content-Disposition': 'attachement' header and gives the user a download ribbon to download the file.
So far it appears to work in all the latest browsers. Unfortunately it requires you to modify you server side API for downloading the file.

Categories

Resources