On the retrieve multiple message, is there a way to know when the user explicitly refreshes a subgrid? My plugin needs to distinguish between a refresh and a search/filter. The problem is the query that comes through in retrieve multiple message has filter criteria and sort order, so I cannot use those conditions to determine if it was refreshed.
thanks in advance
In a plugin's RetrieveMultiple handler it is not possible to determine the origin of the query (Lookup view, Active, Associated or Advanced Find view). Plugins are designed to be transparent and do not keep track of the state of the user session spanning multiple requests.
One solution I could think of is to keep track of the user's subsequent actions trying to recognize a second request for the very same page of data for a specific user. In a multiserver (e.g. load balanced) configuration it will not be easy to make this a robust solution. Also, a scenario like opening a window with a specific page, closing it and reopening the same page could lead to unexpected behaviour. I am sure there are a few other issues such a design would bring with it and therefore I would advise against it.
Related
I want to trigger a NetSuite workflow when the user sets the value of a field, but I don't want to have them submit first. The Workflow state builder looks like it has useful options but I can't get it to work.
There's some useful looking blog posts around but a lot of them seem out of date.
Update - more info
My primary issue is this one: Restrict what customers an employee can see (NetSuite)
The hack I'm currently looking at is populating a custom Transaction Column Field that I've added to a custom Time Recording form. The idea is to load this field on the UI with only valid projects (not customers as well), and this I have been able to do.
The problem is I still (as far as I can tell) still need to populate the "Customer" field, which is mandatory; I'm also assuming that if I don't do that then any time that is recorded won't go against the project. I had thought that if the user selects the project they want then I can populate the customer field with that value. I hate this as an approach but I can't see how else to do it. I do have coding experience (including JavaScript) but haven't made the leap into SuiteScript yet.
You won't be able to do this in a Workflow, as they are currently limited to only work with body level fields and cannot modify Transaction Column Fields (aka sublists).
You should be able to achieve this with a Client Side Script though.
Source (Netsuite login required).
Sublist changes will be available for transactions in the 2018.1 release sometime in Feb/Mar.
I have searched for current solutions, but can't find a set of guidelines or examples as to how to achieve the following:
The original requirements involved models with required fields, so we included annotations to those fields. As usual, there is a last-minute change and we are being asked to allow the users to save drafts. These drafts must allow the user to save the forms without any of the required fields.
I would like to know what the best practices for this problem are.
Solutions I am considering, but I accept they might be a hack (and that's why I am asking the experts)
If the user clicks "Save as Draft" I can capture the fields that have information in another ActionResult and run basic validation on those fields. Since there is a chance that required fields are missing, I am thinking in storing the captured info in a temporal model (without any required annotations). If the user decides to edit such form, I can populate fields in the view with the temp. model until the user clicks on "Submit"
Another option is to remove all required annotations and run client-side validations... but am wondering on the amount of work required to do so.
Any thoughts are very much appreciated.
Just have 2 save methods. 1 which is called from the autosave and 1 that is used to submit the process. In the autosave method do not check if(ModelState.IsValid).
Whether you choose to save the incomplete objects to the same table or a different table is your choice. In a relational world I would likely use a separate table, in a non-relational world I would use a singular object collection.
This will allow you to keep the same set of original models. There is a very high cost to duplicating your models, there are certainly times that warrants pass by value/copy but make sure the cost of mapping is there. In this situtation I do not believe there is value in mapping, except perhaps at the persistence level if you need to map to a different object because of an ORM's constraints.
There is deep value in these partial forms. Recording this on the server will allow you to apply analytics to learn why your users abandon your processes. It also gives you the ability to follow up on users who leave incomplete forms such as sending a reminder (nag) email.
You don't want to save anything to your database until it is complete. Having a duplicate table where everything is nullable is cludgy as hell. Before HTML5, the typical path was to save the information to the session, which you could then pull from to refill the fields, but that's requires having a session with a relatively high expiry to be useful.
Thankfully, HTML5 has local storage, which is really the best way to handle this now. You just watch for onchange events on your fields and then insert that value into local storage. If the user submits the form successfully, you destroy the local storage values. Otherwise, you attempt to read those values from local storage when the page loads and refill the fields.
See: http://diveintohtml5.info/storage.html
There's pretty broad support, so unless you need to worry about IE6 or IE7, you won't have any issues.
Another option (depending on your data obviously) would be to comply with the database but not the model. By this I mean ignore Model.isValid and disable Javascript validation on the front end but then satisfy the database table. In a form, you mostly have:
textboxes - default to "" or " "
checkboxes - easy true/false default
radio buttons - one is probably already selected
dates - default to DateTime.MinValue (or DateTimeUTC)
enums - default to 0 (usually for 'unspecified')
Hopefully you are also saving a flag designating that it is in Draft state so that you know you need to interpret the 'null codes' you have set when it comes to displaying the semi-populated form again.
I have scripts that react off of, for example, a client Recalc client event. For example, on my form I have a subtab that users may add or remove items from. Based on actions on this subtab (housing a child record of the parent) I would like a field on the parent to update (say to show a total from the children records).
As I was saying, these events seem to work fine if in edit mode but they do not work correctly in view mode. (even in view mode these child records have a "Delete" option at the end of each row in the subtab. This was provided by netsuite by default.
I wondered if anyone had any tips to best allow this parent field to update real time while in updating the subtab rows with the form in view mode.
Thanks.
You can make a custom field on the parent (header) whose value is determined by saved search. For instance, make a saved search that totals the line values by transaction. Be sure to make it filter by transaction in the Available Filters tab. Make the search public so everyone can use it.
Create the custom field that sources the total from the saved search. Make sure to uncheck the "Store Value" checkbox, as you don't want to store the data, you want to reference the search results. You do this on the Validation and Defaulting tab. You'll see a field for Saved Search there. Choose the search you created above.
As you remove/add/change lines on the transaction, the field updates accordingly. In essence, you don't need a single line of code to make this work - it's all in how you create the search and the custom field that references it.
I have a similar situation posted here.
The NetSuite team answered me by email, and it happens you can't really achieve this on the view mode: some API methods are not available. Their suggestion to my case (and I think it applies to yours too) was really to force a refresh on the whole page.
Of course, you can always achieve this accessing the DOM elements directly, but this isn't a best practice, as your code can stop working if these elements change on a version update.
I had the same problem, I'm not able to restrict on view or remove edit button. But, there was one alternative solution with workflows, you can deploy workflow on child record edit mode restrictions, then if the user clicks edit on view then the record will not be available to edit. This concern will apply to custom record as well.
I am working on Notes in MS CRM 2011.
I have many roles over many entities.
I want role based security to notes for any entity records.
let me explain what i want:
Suppose i have an entity namely E1.
Role R1 and R2 has read and write access to E1.
But i want that user having role R2 can only upload and view notes for any record of entity E1.
Hope now my requirement is clear to all of you.
Please suggest me how can i achieve it using MS CRM 2011.
I can think of two ways to do this.
You can create a plugin on create/update of the annotation(note) and check if the note is related to entity E1 and check the roles of the user making the change and see if they only have the R2 role. If that is the case you can throw an InvalidPluginExecutionException with a message like 'You do not have permissions to edit/create these records'.
You can try using role based forms or JS to hide the notes area for R1 users.
You probably want to use a combination of #1 & #2. The users can still access the notes via advanced find and thus will be able to edit those notes. The plugin will prevent that fringe case as well.
*Edit
There are a couple more things that you might be able to deal with the advanced find records. You can remove the annotation entity from advanced find via the unsupported method described here.
Otherwise there is one more thing you can do if you want to prevent those results showing up at all, and you want to stay supported. You can write a plugin on Post-RetrieveMultiple of the annotation entity to strip out the results directly from the return result. There are a couple downsides to this though.
You are executing your plug-in every time the retrieve multiple is called on the entity. So this code will need to be as efficient as possible since that delay will be noticeable by the end user whenever they retrieve these records.
Things like advanced find will display odd results. For example if your paging is set to 50 records and you strip out 10, they will only see 40 records on their page and the total record count will include the records you are stripping out.
Through roles i don't know a way to do that, because you configure the access to notes generic, so applies to all entities. You have to access with Javascript navigating in DOM. Check a example:
document.getElementById("notescontrol").contentWindow.document.getElementById("NotesTable")
You can check this with the help of a develeper tool in your browser.
I have an NSTableView which is populated via a CoreData-backed NSArrayController. Users are able to edit any field they choose within the NSTableView. When they select the rows that they have modified and press a button, the data is sent to a third-party webservice. Provided the webservice accepts the updated values, I want to commit those values to my persistent store. If, however, the webservice returns an error (or simply fails to return), I want the edited fields to revert to their original values.
To complicate matters, I have a number of other editable controls, backed by CoreData, which do not need to resort to this behaviour.
I believe the solution to this problem revolves around the creation of a secondary Managed Object context, which I would use only for values edited within that particular NSTableView. But I'm confused as to how the two MOC would interact with each other.
What's the best solution to this problem?
The easiest solution would be to implement Core Data's undo functionality. That way you make the changes to Core Data but if the server returns the error, you just rollback the changes. See the Core Data docs for details.