frappe trigger field update via custom script - erpnext

I'm customizing an existing DocType(quotation) and I've added fields to the Quotation Item child table which affect the amount field of an Item. By default, i.e. before customizations, the grand_total, and Quotation net_totals get calculated as soon as an Item changes. But now that I have custom fields, how can I call the hypothetical "refresh" functions that do the default calculation?
Here is my current Custom Script that updates the Item amount on Quotation Item child table:
frappe.ui.form.on("Quotation Item", "paint", function(frm, doctype, name) {
let row = locals[doctype][name];
let rate = row.labour + row.trim + row.paint + row.spares;
row.rate = rate;
let total = rate * row.qty
row.amount = total;
refresh_field("items");
});

There are few techniques to achieve your goal.
The most effective one will depend on the HOOKS, specially :
doctype_js
override_doctype_class
As the first will allow you to run your js code along with the original doc js code.
And the second will allow you to override the original doc class and will give you the capability to call the hypothetical method you override.
You can check the below links for more details:
doctype_js
override_doctype_class

Related

How do i poulate a field with a parameter from previous page in a multipage form in gravityforms?

I want to build a multipage from.
The first page asks for first name and last name.
I want to greet the user with his first name in the second page.
The best way to do this is to use Live Merge Tags with Populate Anything:
https://gravitywiz.com/documentation/gravity-forms-populate-anything/#live-merge-tags
If you collected the user's first name in a Name field on page 1, you could great him in the field label for a field on page 2 like so:
Hello, #{Name (First):1.3}
(In this example, the field ID for the Name field is 1. The 3 refers to the first name input of a Name field and will always be 3).
If avoiding another plugin (as useful as that one is), you can use either the pre_submission_filter or pre_submission hooks to do this.
If their name was field 1 and lets say the field you'd like to show is field 2...
// THESE FOUR FILTERS WORK TOGETHER TO PRE-POPULATE ALL SORTS OF STUFF, AND YOU CAN ADD TO THIS AS NECESSARY. MINE IS ABOUT 1500 LINES LONG AND IS USED BY SEVERAL FORMS.
add_filter('gform_pre_render', 'populate_forms');
add_filter('gform_pre_validation', 'populate_forms');
add_filter('gform_pre_submission_filter', 'populate_forms', 10);
add_filter('gform_admin_pre_render', 'populate_forms');
function populate_forms($form) {
$form_id = $form['id'];
$current_form = 2; // pretending the form id you are working on is 2.
$future_form = 10; // imaginary form you'll create later for another purpose.
switch($form_id) {
case $current_form:
$first_name = !empty(rgpost('input_1_3')) ? rgpost('input_1_3') : null; // gets the value they entered into the first-name box of field 1.
foreach ($form['fields'] as &$field) {
if ($field->id === '2') { // Make as many of these as necessary.
if ($first_name) { // make sure there's actually a value provided from field 1.
$field->placeholder = $first_name; // not necessary, just habit since sometimes you'd need to have a placeholder to reliably populate some fields.
$field->defaultValue = $first_name; // this is the piece that will actually fill in the value like you'd expect to see in your question.
}
}
}
break;
//case $future_form: do more stuff.
//break;
}
return $form;
}
That should be a decent start for your functionality plugin where you can populate the current and future forms without much hassle. This can also be done with the gform_field_value hook; I've always found the language a bit clumsy with that one, personally.
The plugin mentioned earlier is definitely neat, but I found myself wanting to rely on that stuff less and less.

Ag-Grid QuickFilter changing programmatically searched columns

I need a quick search filter, where user can select what columns are searched. I didn't succeed to implement this behavior.
I tried this:
this.columns.forEach(column=>{
if (this.globalSearchSelectedColumns.indexOf(column.field)>-1) column.getQuickFilterText = (params)=> params.value.name;
else column.getQuickFilterText = ()=> '';
});
this.grid.api.setColumnDefs(this.columns);
this.grid.api.onFilterChanged();
this.grid.api.resetQuickFilter();
where this.columns is columns defs, this.grid is gridOptions, this.globalSearchSelectedColumns is the selected columns to search for, by column.field.
In order to selectively apply quickFilter form ag-Grid you should rewrite the property getQuickFilterText of the columnDef, by setting it to a function which returns an empty string like so:
First of all, you need to retrieve the column by a key through the gridColumnApi
Then you need to access its colDef
Lastly, all you left to do is to rewrite getQuickFilterText property
Assume, that in your class component you have a method disableFilterCol it can look something like this:
disableFilterCol = () => {
var col = this.gridColumnApi.getColumn("athlete");
var colDef = col.getColDef();
colDef.getQuickFilterText = () => "";
console.log("disable Athlete");
};
Once it called, quickFilter will be applied to your data grid excluding athlete column.
I created live demo for you on ReactJS.
You can improve the way you can select multiple columns that you want to rely on doing filtering.
I suppose that in your case you can try to add set getQuickFilterText = () => "" for either definition of colDef from the very beginning and let the user enabling particular columns, you can set getQuickFilterText property for them to undefined to provide sorting among them.
According to nakhodkiin solution I change my code like this:
this.grid.columnApi.getAllColumns().forEach(column=>{
let def = column.getColDef();
if (this.globalSearchSelectedColumns.indexOf(def.field)>-1) def.getQuickFilterText = undefined;
else def.getQuickFilterText = ()=> '';
});
this.grid.api.onFilterChanged();
And it's working;
I think the problem here lies in setting updated column defs.
Can you try this -
let newColDef= [];
this.columns.forEach(column=>{
if (this.globalSearchSelectedColumns.indexOf(column.field)>-1)
column.getQuickFilterText = (params)=> params.value.name;
else column.getQuickFilterText = ()=> '';
newColDef.push(column);
});
this.grid.api.setColumnDefs(newColDef);
this.grid.api.onFilterChanged();
this.grid.api.resetQuickFilter();
this.grid.api.refreshHeader();
Ag-grid updated its approach of detecting column changes since v19.1
More details here
As per doc -->
When new columns are set, the grid will compare with current columns and work out which > columns are old (to be removed), new (new
columns created) or kept (columns that remain will keep their state
including position, filter and sort).
Comparison of column definitions is done on 1) object reference comparison and 2)
column ID eg colDef.colId. If either the object
reference matches, or the column ID matches, then the grid treats the
columns as the same column.
Ag-grid team is also actively working on fixing this issue for v20.1. You can track it on github

Passing grid panel data via request payload to REST controller

I have a user form that is created in extjs framework. The user form has many user fields which are being passed as part of request payload to the REST controller.
I am trying to add a grid panel(most likely in a tabular format with multiple rows & columns) to the user form.
But I am not sure how to pass the grid panel data as part of request payload to the REST controller.
I will post more code if any more details are needed.
Any help would be appreciated. Thanks.
Ext.define('soylentgreen.view.admin.UserForm', {
extend : 'Ext.form.Panel',
alias : 'widget.userform',
bodyStyle : 'padding:5px 5px 0',
// some userform elements like firstname,lastname, go here.....
name : 'userTeamGrid',
xtype : 'gridpanel',
id : 'userTeamGrid',
itemId : 'userTeamGrid',
multiSelect : true,
selModel : Ext.create(
'Ext.selection.CheckboxModel',
{
injectCheckbox : 'first',
mode : 'MULTI',
checkOnly : false
}),
anchor : '100%',
width : '700px',
height : 250,
flex : 1,
store : 'userTeamStore',
var user = form.getRecord();
form.updateRecord(user);
user.save({
callback : function(records, operation){
//reset the (static) proxy extraParams object
user.getProxy().extraParams = {
requestType: 'standard'
}
if(!operation.wasSuccessful()){
var error = operation.getError();
IMO, That's one of the most complicated yet common issues we face in ExtJS. It has to be solved often, but most solutions have to be slightly different depending on the exact requirements.
Grids are bound to a full store, not to a single record. So if you want to get data from a record (e.g. as an array) into a grid and vice versa, you have to have a mapping between the data from the store and the value in a single field of a record. To e.g. get all data from the store, the generic solution is
store.getRange().map(function(record) { return record.getData(); });
If you need only the grid selection (maybe you want to use a checkboxselection model or similar) and/or only certain fields of the records, you have to change this code to your needs, e.g.
grid.getSelectionModel().getSelection().map(function(record) {return record.get('Id'); });
So, your record is bound to the form, and a form consists of fields. How do you get the grid data to be accepted as part of the form?
You have to add a hiddenfield to your form and, depending on your requirement, overwrite some of the four functions setValue, getValue, getModelData, getSubmitValue. Usually, the hiddenfield tries to convert its value to a string, but obviously, you need to allow for arrays there; and you want to modify the grid whenever setValue is called, or read the value from the grid whenever one of the getters is called. The four functions are used for the following:
setValue should be used to modify the grid based on the value you find in the record.
getValue is used in comparison operations (check whether the value has changed, which means the form is dirty and has to be submitted, etc.) and if you call form.getValues. You should return some value based on the grid state in it.
getModelData is used by the form.updateRecord method; it should return a value that the model field's convert method can work with.
getSubmitValue is used by the form.submit method, it should return a value that can be safely transmitted to the server (has to be a string if the form doesn't have sendAsJson:true set)
I cannot give you an exact recipe for these implementations, as they are specific to your requirements.

Can choices in a list be changed after it has been been rendered?

I have a w2ui form that contains a w2ui Drop List of choices. The choices will be different depending on what the user selected to bring up the form. My question is: can the contents of a Drop List be changed after it has been rendered?
With standard HTML controls, I would do something like this:
$("#mySelect option[value='xyz']").remove();
or
$("#mySelect").append('<option value="abc">abc</option>');
Can these kinds of operations be done with a w2ui Drop List? Any example code?
In w2ui 1.5 you can use $jQueryElement.w2field() to access the w2fild object - and then manipulate it.
Example:
var field = $("#my_input").w2field();
field.options.items = ["my", "new", "items"];
// optionally: pre-select first item
field.setIndex(0);
// if you do NOT use "setIndex" you need to call "refresh" yourself!
// field.refresh();
Note: setIndex() internally calls refresh() - so as stated above, you do not need to call refresh yourself in that case.
If you want to completely clear/empty your field, you can call field.reset().
Edit: after clarification that it's about a form field:
// Note: ``this`` refers to the w2form
// ``field[8]`` refers to a field of type "select"
this.fields[8].options.items = ["my", "new", "items"];
this.record = {
field_select: 'new'
};
this.refresh();

Form grid filters

I want store the filters entered on the grid, is it possible to store the filters entered on filter pane of the grid.
I want to use those filters entered in my class, please help me in this regard.
No, form queries cannot be saved as code (but such functionality could be programmed).
A form query could be passed from the form to a class, using a parmQueryRun method or similar.
See:
How to Create Queries by using the AOT
How to Create Queries by Using X++
Yes you can retrieve the filters by getting the form's queryRun's query and packing that into a container to be stored/passed/unpacked.
The form has a query, that is passed to QueryRun, then the users puts filters/dynamic joins/etc on that query that belongs to the QueryRun. So you need the modified query to store what you want from it.
void clicked()
{
Query q = salestable_ds.queryRun().query();
int i;
container c;
for (i = 1; i <= q.queryFilterCount(); i++)
{
info(strFmt("%1: %2", q.queryFilter(i).field(), q.queryFilter(i).value()));
}
// If we want to store these we can do
c = q.pack();
}
See this post http://dynamicsuser.net/forums/t/63208.aspx