1
votes

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.

3
We have a similar workflow approval setup. We just have a field for rejection reason, that is required, when the reject button is pressed.w3bguy
Is your record locked down at this point? How do you enter data into the field if the record is locked down? Or perhaps that is not a problem?Donald Varona
We have "reason" records that hold all of that information. So when they reject a record, the workflow creates a new rejection reason record, which has all of the information needed. That record is linked with the original record. Then once that record is save, the workflow updates the status of the original record, and you can see any rejection reasons via that sub-tab that we added. This also allows for a nice documented audit trail of everything.w3bguy

3 Answers

0
votes

Well, I've tried several other solutions and none of these seem to work:

  1. 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.
  2. 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.
  3. Setting the "User Interface" context on the workflow action also does not work; the redirection still kills the transition.
  4. 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.

0
votes

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?

0
votes

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