Prevent record deletion with SuiteScript - netsuite

I want to prevent a record from being deleted based on certain conditions in NetSuite. However, I can't seem to find a failure event on validation? BeforeSubmit on a UserEvent has a delete type, but it doesn't have a return value for the function, so I can't just say return false, can I?
How do I then prevent the deletion of a record, or fail a record submission of a certain type?

Instead of returning false, just throw an error. Not user friendly but it is the only option, as far as I know.
Since it is in the Before Submit User Event, the submission or deletion will fail.

You'll want to use a beforeSubmit user event script and throw an error using nlapiCreateError. Here's an example:
function beforeSubmit(type) {
if(type == 'delete') {
// NOTE `nlapiGetFieldValue` returns nil/empty during a delete event
// `nlapiGetOldRecord` needs to be used to pull the entire record
var payment = nlapiGetOldRecord();
if(payment.getFieldText('paymentmethod') == 'cash') {
throw nlapiCreateError(
'AN_ERROR',
'Message to the user!',
true
);
}
}
}

You can also use a Workflow to prevent the Delete button to display to the user:

You could add client-side code to pop up a message to the user when trying to delete a record you want to prevent. With that said, you would still want to put a UserEvent script preventing the delete actions as well. This would prevent the user from by passing the restriction

Related

Firebase doc changes

thanks for your help, I am new to firebase, I am designing an application with Node.js, what I want is that every time it detects changes in a document, a function is invoked that creates or updates the file system according to the new structure of data in the firebase document, everything works fine but the problem I have is that if the document is updated with 2 or more attributes the makeBotFileSystem function is invoked the same number of times which brings me problems since this can give me performance problems or file overwriting problems since what I do is generate or update multiple files.
I would like to see how the change can be expected but wait until all the information in the document is finished updating, not attribute by attribute, is there any way? this is my code:
let botRef = firebasebotservice.db.collection('bot');
botRef.onSnapshot(querySnapshot => {
querySnapshot.docChanges().forEach(change => {
if (change.type === 'modified') {
console.log('bot-changes ' + change.doc.id);
const botData = change.doc.data();
botData.botId = change.doc.id;
//HERE I CREATE OR UPDATE FILESYSTEM STRUCTURE, ACCORDING Data changes
fsbotservice.makeBotFileSystem(botData);
}
});
});
The onSnapshot function will notify you anytime a document changes. If property changes are commited one by one instead of updating the document all at once, then you will receive multiple snapshots.
One way to partially solve the multiple snapshot thing would be to change the code that updates the document to commit all property changes in a single operation so that you only receive one snapshot.
Nonetheless, you should design the function triggered by the snapshot so that it can handle multiple document changes without breaking. Given that document updates will happen no matter if by single/multiple property changes your code should be able to handle those. IMHO the problem is the filesystem update rather than how many snaphots are received
You should use docChanges() method like this:
db.collection("cities").onSnapshot(querySnapshot => {
let changes = querySnapshot.docChanges();
for (let change of changes) {
var data = change.doc.data();
console.log(data);
}
});

How to capture only the fields modified by user

I am trying to build a logging mechanism, to log changes done to a record. I am currently logging previous and new record. However, as the site is very busy, I expect the logfile to grow seriously huge. To avoid this, I plan to only capture the modified fields only.
Is there a way to capture only the modifications done to a record (in REACT), so my {request.body} will have fewer fields?
My Server-side is build with NODE.JS and the client-side is REACT.
One approach you might want to consider is to add an onChange(universal) or onTextChanged(native) listener to the text field and store the form update in a local state/variables.
Finally, when a user makes an action (submit, etc.) you can send the updated data to the logging module.
The best way I found and works for me is …
on the api server-side, where I handle the update request, before hitting the database, I do a difference between the previous record and {request.body} using lodash and use the result to send to my update database function
var _ = require('lodash');
const difference = (object, base) => {
function changes(object, base) {
return _.transform(object, function (result, value, key) {
if (!_.isEqual(value, base[key])) {
result[key] = (_.isObject(value) && _.isObject(base[key])) ? changes(value, base[key]) : value;
}
});
}
return changes(object, base);
}
module.exports = difference
I saved the above code in a file named diff.js and included it in my server-side file.
It worked good.
Thanks for giving the idea...

socket.emit() fires twice - socket.io

I'm making a one-to-one chatroom.
Here is my basic algorithm:
accept user's input (nickname) by a form
fetch all the existing connections and rooms from server
check if this nickname already exists:
if exists, form submission return false ; if not exists, ......
Now I'm having a socket.emit() twice bug on step 2.
Here is my client side code:
$('#login').submit(function(e){
socket.emit('getRoomInfo');
socket.on('receiveRoomInfo',function(info){
//Here has some code to fetch person_room list from server.
//e.g, person_room[nickname]= roomNO
if(person_room[nickname]){
alert('User already exists!');
}else{
//show chat
//hide the form
//update person_room list
//do something
}
});
return false;
});
Here is my server side code:
socket.on('getRoomInfo',function(){
socket.emit('receiveRoomInfo', {'person_room': person_room, 'roomNO': roomNO});
});
Bug Description:
Suppose I open up one form (index.html), and input 'John Snow', submit the form. Everything works fine, form gets hidden, chat shows up. Waiting for
the other connection...
Then I open up another form (index.html), and input 'John Snow', submit the form. Window alerts 'User already exists!'. Form isn't submitted.
I erase 'John Snow' and input 'Arya Stark', submit the form. Window still alerts
'User already exists!', but this time, form gets hidden, chat shows
up.
What I've test:
Login form is only submitted once
On client side, socket.emit('getRoomInfo') is triggered twice under Bug Description 3, which means socket.on('receiveRoomInfo') is triggered twice as well. So what happens is, 'Arya Stark' gets pushed into the list by the first time, and in the second time, it turns out she already exists in the list, Hence window still alerts 'User already exists!'.
I've researched a lot of similar questions, but none of them is the same case as this one.
Thanks for help.
I can fix the code, but I'm not able to tell the reason behind this bug.
I discovered that under once form submission, socket.on('receiveRoomInfo') is triggered twice.
So I set a variable var userExists=false under form.submit(),
after detected if(person_room[nickname]), set userExists=true.
Under socket.on('receiveRoomInfo'), surround all the code implementation with if(!userExists), so that we can make sure socket.on('receiveRoomInfo') is only executed once under once form submission.
I will be waiting for few days for a better idea before I vote my own answer.

DocuSign "delete envelope lock" not working

I'm using the DocuSign REST API to automate document signing. I use the sender view to allow my clients to place signing tabs on their documents and ultimately send them.
However, I'm running into a problem where the client, for whatever reason, needs to start over in our workflow, and so abandons the embed without saving it and contacting us to restart the process.
Normally, we'd call Update to mark the Envelope as voided and then create a new one, but because the client didn't exit the embed properly, the Envelope is still marked as locked.
I thought the Delete Lock endpoint would allow us to remove the lock so that we could edit the envelope, but it's returning an error message saying that we can't delete the lock as we weren't the ones who put it there.
Given that the same credentials were used for both the embed window and the delete lock call, why does DocuSign treat us like two different users? And is there a way to get around the lock?
This might help some folks in the future.
"by appending a lockToken parameter to the view URL, you can give your
integration control over the envelope lock, enabling it to make
changes to the envelope without having to wait for the DocuSign token
to expire."
http://m.mmffs.com/the-trenches-whos-locking-my-envelopes.html
The article shows how to accomplish this using the API directly. In the code snippet below, this is how you would do it going against the DocuSign Nuget package.
var lockInfo = envelopesApi.CreateLock(accountID, envelopeID, new LockRequest()
{
LockedByApp = "[Your App]",
LockType = "edit"
});
existingViewUrl += "&lockToken={lockInfo.LockToken}";
Note, the third LockRequest parameter is required for this to work even though it is not required by the CreateLock method. Credit to Inbar Gazit - Error trying to add a document to envelope and getting a user lock error message
Now, the normal DeleteLock method will work.
try
{
var lockInfo = envelopesApi.GetLock(accountId, envelopeID);
if (lockInfo?.LockDurationInSeconds?.Length > 0)
{
envelopesApi.ApiClient.Configuration.AddDefaultHeader("X-DocuSign-Edit", $"{{\"lockToken\":\"{lockInfo.LockToken}\"}}");
envelopesApi.DeleteLock(accountId, envelopeID);
}
}
catch(ApiException e)
{
// Not locked.
}
Lock is done by NDSE not your credentials, solution is to wait for sometime and lock will be released by NDSE or you have to redirect user to same screen again and the user needs to select Save and Close instead of Discard Changes. Once user selects Discard Changes then envelope is moved to Deleted folder.
You can try code below:
var config = new Configuration(new ApiClient(basePath));
config.AddDefaultHeader("Authorization", "Bearer " + accessToken);
var envelopesApi = new EnvelopesApi(config);
try
{
// this line will throw error if envelope is not locked, so handle it using try & catch block
LockInformation lockInfo = envelopesApi.GetLock(accountId, envelopeId);
// check if this app locked it
if (lockInfo?.LockDurationInSeconds?.Length > 0)
{
// add a header with the LockToken to ensure this app has the right to unlock
string LockHeader = $"{{\"lockToken\":\"{lockInfo.LockToken}\"}}";
envelopesApi.Configuration.AddDefaultHeader("X-DocuSign-Edit", LockHeader);
envelopesApi.DeleteLock(accountId, envelopeId);
}
}
catch (ApiException exp)
{
// Do Whatever you want to do
}

Suite Script for User Event is not getting triggered for xedit operaration

I have a SuiteScript which is getting triggered on AfterSubmit of any Case update. It is working fine for normal updates.
But when I try to edit a Case in-line(through case search), the event is not getting triggered.
Do I need to configure anything specific to handle the in-line edit during the script deployment?
Please find the script which I am using to identify the xedit operation.
function handleSupportCaseCreateUpdateReqeust(type, form, request) {
try {
if(type == 'xedit'){
nlapiLogExecution('AUDIT', 'TFSNSIntegrator Log', 'Type of the event is :'+ type);
}
} catch (e) {
nlapiLogExecution('ERROR', 'Exception', e.message);
}
This is a simple thought, but may as well check - have you confirmed that your Deployment's Log Level is set to Audit? If not, that could be why you aren't seeing that in the execution log.
Through NetSuite Support, I figured out the issue.
The issue was with the option I selected to deploy the SuiteScript. I selected 'Edit' event to trigger the script, since we dont have a option "xedit". Actually we should not select any particular event. I just deployed it with our selecting any specific event and it started to work.
Thanks all for your replies!

Resources