In Odoo Treeview, I can add a sequencing column like this:
<field name="sequence" widget="handle"/>
The widget handle support auto arrange sequences by drag and drop.
But if I shift the first item to another position, the new first item's sequence isn't 1 but another number. My question is:
1. How can I make the first item's sequence is always 1?
2. Is there any other way to add a sequencing order column in Odoo Treeview? I just want a column to show row num of items.
This works for me.
class TestModel(models.Model):
_name = 'test.model'
_description = 'test.model'
sequence = fields.Integer()
index = fields.Integer(compute='_compute_index')
#api.one
def _compute_index(self):
cr, uid, ctx = self.env.args
self.index = self._model.search_count(cr, uid, [
('sequence', '<', self.sequence)
], context=ctx) + 1
If you show the field "index" in the tree, it won't change, you have to reload the view :(.
Related
I want to sort real-time when a number is calculated in a "Total" column, which is a sum based on other cells, inputted by the user. The sort should be descending and I did achieve this functionality using the following:
function onEdit(event){
var sheet = event.source.getActiveSheet();
var range = sheet.getDataRange();
var columnToSortBy = 6;
range.sort( { column : columnToSortBy, ascending: false } );
}
It's short and sweet, however empty cells in the total column which contain the following formula, blanking itself if the sum result is a zero, otherwise printing the result:
=IF(SUM(C2:E2)=0,"",SUM(C2:E2))
It causes these rows with an invisible formula to be included in the range selection and upon descending sort, they get slapped up top for some reason. I want these blank rows either sorted to the bottom, or in an ideal scenario removed from the range itself (Without deleting them and the formula they contain from the sheet) prior to sorting.
Or maybe some better way which doesn't require me dragging a formula across an entire column of mostly empty rows. I've currently resorted to adding the formula manually one by one as new entries come in, but I'd rather avoid this.
EDIT: Upon request find below a screenshot of the sheet. As per below image, the 6th column of total points needs to be sorted descending, with winner on top. This should have a pre-pasted formula running lengthwise which sums up the preceding columns for each participant.
The column preceding it (Points for Tiers) is automatically calculated by multiplying the "Tiers" column by 10 to get final points. This column could be eliminated and everything shifted once left, but it's nice to maintain a visual of the actual points awarded. User input is entered in the 3 white columns.
You want to sort the sheet by the column "F" as the descending order.
You want to sort the sheet by ignoring the empty cells in the column "F".
You want to move the empty rows to the bottom of row.
You don't want to change the formulas at the column "F".
You want to achieve this using Google Apps Script.
If my understanding is correct, how about this answer?
Issue and workaround:
In the current stage, when the empty cells are scattered at the column "F", I think that the built-in method of "sort" of Class Range cannot be directly used. The empty cells are moved to the top of row like your issue. So in this answer, I would like to propose to use the sort method of JavaScript for this situation.
Modified script:
In order to run this function, please edit a cell.
function onEdit(event){
const columnToSortBy = 6; // Column "F"
const headerRow = 1; // 1st header is the header row.
const sheet = event.source.getActiveSheet();
const values = sheet.getRange(1 + headerRow, 1, sheet.getLastRow() - headerRow, sheet.getLastColumn())
.getValues()
.sort((a, b) => a[columnToSortBy - 1] > b[columnToSortBy - 1] ? -1 : 1)
.reduce((o, e) => {
o.a.push(e.splice(0, columnToSortBy - 1));
e.splice(0, 1);
if (e.length > 0) o.b.push(e);
return o;
}, {a: [], b: []});
sheet.getRange(1 + headerRow, 1, values.a.length, values.a[0].length).setValues(values.a);
if (values.b.length > 0) {
sheet.getRange(1 + headerRow, columnToSortBy + 1, values.b.length, values.b[0].length).setValues(values.b);
}
}
In this sample script, it supposes that the header row is the 1st row. If in your situation, no header row is used, please modify to const headerRow = 0;.
From your question, I couldn't understand about the columns except for the column "F". So in this sample script, all columns in the data range except for the column "F" is replaced by sorting. Please be careful this.
Note:
Please use this sample script with enabling V8.
References:
sort(sortSpecObj)
sort()
Added:
You want to sort the sheet by the column "F" as the descending order.
You want to sort the sheet by ignoring the empty cells in the column "F".
You want to move the empty rows to the bottom of row.
In your situation, there are the values in the column "A" to "F".
The formulas are included in not only the column "F", but also other columns.
You don't want to change the formulas.
You want to achieve this using Google Apps Script.
From your replying and updated question, I could understand like above. Try this sample script:
Sample script:
function onEdit(event){
const columnToSortBy = 6; // Column "F"
const headerRow = 1; // 1st header is the header row.
const sheet = event.source.getActiveSheet();
const range = sheet.getRange(1 + headerRow, 1, sheet.getLastRow() - headerRow, 6);
const formulas = range.getFormulas();
const values = range.getValues().sort((a, b) => a[columnToSortBy - 1] > b[columnToSortBy - 1] ? -1 : 1);
range.setValues(values.map((r, i) => r.map((c, j) => formulas[i][j] || c)));
}
A much simpler way to fix this is to just change
=IF(SUM(C2:E2)=0,"",SUM(C2:E2))
to
=IF(SUM(C2:E2)=0,,SUM(C2:E2))
The cells that are made blank when the sum is zero will then be treated as truly empty and they will be excluded from sort, so only cells with content will appear sorted at the top of the sheet.
Why your original formula doesn't work that way is because using "" actually causes the cell contain content so it's not treated as a blank cell anymore. You can test this by entering ISBLANK(F1) into another cell and check the difference between the two formulas.
Hi i have been trying to make a user defined function that allows the user to select the values which the function will use from a list.
I have tried setting the parameter i want as a list to type list in my function but this only seems to accept columns rather than a list of values a user can select from.
let
ListOfDays = {1.1,0.5,2,3,1},
DayOfTheWeek = (Day as list, HoursWorked ) =>
let
Earnings = Day * HoursWorked
in
Earnings
in
DayOfTheWeek
What i would like is for me to allow the user to select a single value from the ListOfDays list. I used typed list within my function parameters so that it can give the user a dropdown list kind of option.
I believe this is the relevant documentation you are looking for:
github.com/microsoft/DataConnectors/docs/function-docs.md: Adding Function Documentation
In particular, look at the definition for Documentation.AllowedValues:
List of valid values for this parameter. Providing this field will change the input from a textbox to a drop down list. Note, this does not prevent a user from manually editing the query to supply alternate values.
This (and other Documentation fields) are part of the meta typing of the function arguments. Scroll down to the code snippet which shows how to use them:
[DataSource.Kind="HelloWorldWithDocs", Publish="HelloWorldWithDocs.Publish"]
shared HelloWorldWithDocs.Contents = Value.ReplaceType(HelloWorldImpl, HelloWorldType);
HelloWorldType = type function (
message as (type text meta [
Documentation.FieldCaption = "Message",
Documentation.FieldDescription = "Text to display",
Documentation.SampleValues = {"Hello world", "Hola mundo"}
]),
optional count as (type number meta [
Documentation.FieldCaption = "Count",
Documentation.FieldDescription = "Number of times to repeat the message",
Documentation.AllowedValues = { 1, 2, 3 }
]))
as table meta [
Documentation.Name = "Hello - Name",
Documentation.LongDescription = "Hello - Long Description",
Documentation.Examples = {[
Description = "Returns a table with 'Hello world' repeated 2 times",
Code = "HelloWorldWithDocs.Contents(""Hello world"", 2)",
Result = "#table({""Column1""}, {{""Hello world""}, {""Hello world""}})"
],[
Description = "Another example, new message, new count!",
Code = "HelloWorldWithDocs.Contents(""Goodbye"", 1)",
Result = "#table({""Column1""}, {{""Goodbye""}})"
]}
];
HelloWorldImpl = (message as text, optional count as number) as table =>
let
_count = if (count <> null) then count else 5,
listOfMessages = List.Repeat({message}, _count),
table = Table.FromList(listOfMessages, Splitter.SplitByNothing())
in
table;
They also provide a screenshot of what this should look like when invoked:
If the user is able to open up the Query Editor, then they can choose a Day parameter from a dropdown list and have this automatically apply to the query.
You would create the parameter from the Manage Parameters > New Parameter menu
The drop-down at the upper right of the image is how the user would select the choice.
Your User Defined Function fn_DayOfTheWeek would be the following:
let
DayOfTheWeek = (Day as number, HoursWorked as number) =>
let
Earnings = Day * HoursWorked
in
Earnings
in
DayOfTheWeek
Note that Day is a number, not a list. You want to choose from a list, not pass a list into the function.
Now you can invoke your function with your parameter to actually produce a result.
let
Source = fn_DayOfTheWeek(Day, <HoursWorked value here>)
in
Source
This result will update when you change the parameter.
As you can see, whether a user has access to the Query Editor is rather a critical question for this approach. I'm not sure if it's possible to somehow set a parameter directly within a custom connector dialog box or not but this should be equivalent in functionality.
I'm new in Lotus Notes programming and I need your advices and your help.
My main form contains a table with 8 rows and 2 columns. ( there are 16 cells ) Every each cell has a numeric field. My fields name are :
txt_n1 and txt_i1 ( for 1st row )
txt_n2 and txt_i2 ( for 2nd row )
....
txt_n8 and txt_i8 ( for 8th row )
What I want to do is:
I have a view called vwMarketing with just one column. I want this view to display only those docs. in which there is at least one or more rows which its cells contains equal values.
So, if let say txt_n4 = txt_i4 => OK
row(k) (where k=1..8) : if cell 1 value is 5 and cell 2 value is 5 => OK.
There could be more than one row with this property, important is to exist at least one, and the values not to be null.
I hoped i was pretty clear, thanks !
PS: Actually, the formula statement i want to be in the column, so if it is OK => "A" and if not => "" ( in the view property, I checked : Don't show empty categories )
if you have small amount of documents in the view, then as u were suggested use Selection Formula to exclude documents with wrong condition.
you can add computed item/flag into your documents, field will compute if the document should be displayed in the view or not. then you will not have performance issue. i.e.
but code you need should look like that (that will check if documents is fine to be displayed in view or not), if you use it in view - just put after all Select _res = 1 otherwise if you decide to use flag into document (to increase performance) then Select youritem = 1
_res := 0;
#For(i:=1;i<=8;i:=i+1;
_post := #Text(i);
_txt_n := #GetField("txt_n"+_post);
_txt_i := #Text(#GetField("txt_i"+_post));
#If( (_txt_n=_txt_i) & (_txt_n!="");
#Do( _res := 1; i:=9);
0
)
);
_res
I would solve it slightly different:
Create a hidden text field on your form called 'DisplayInView' (or similar).
Modify the view selection: SELECT DisplayInView="Yes"
Add the code below to the PostSave event of your form:
Dim thisdoc As NotesDocument
Dim isSame As Boolean
isSame = False
Set thisdoc = source.Document
'*** Loop through all fields in document and compare the field pairs
Forall i In thisdoc.Items
If Left(i.Name,5) = "txt_n" Then
If i.Text = thisdoc.GetItemValue( Replace(i.Name,"txt_n","txt_i") )(0) Then
isSame = True
Exit Forall
End If
End If
End Forall
If isSame Then
Call doc.ReplaceItemValue("DisplayInView","Yes")
Call doc.Save(True,False)
End If
I haven't tested it, but I believe it should work.
Consider the following html
http://www.carbide-red.com/prog/test_table.html
I have worked out that I can move left to right on the columns using
browser.td(:text => "Equipment").parent.td(:index => "2").flash
to flash the 3rd column over on the line containing "Equipement"
But how can I move down a certain number of rows? I am having terrible luck using .tr & .rows, no matter how I try it just crashes out when using those. Even something as simple as
browser.tr(:text => "Equipment").flash
Am I just misunderstanding how tr/row works?
Specific Row/Column
It sounds like you have already calculated which row/column you want. You can get the cell at a specific row/column index by simply doing:
browser.table[row_index][column_index]
Where row_index and column_index are integers for the row and column you want (note that it is zero-based index).
Specific Row
You can also do the following to select rows based on an index:
browser.table.tr(:index, 1).flash
browser.table.row(:index, 2).flash
Note that .tr includes nested tables while .row ignores nested tables.
Update - Find Rows After Specific Row
To find a row after a specific row containing a certain text, determine the index of the specific row first. Then you can locate the other rows in relation to it. Here are some examples:
#Get the 3rd row down from the row containing the text 'Equipment'
starting_row_index = browser.table.rows.to_a.index{ |row| row.text =~ /Equipment/ }
offset = 3
row = browser.table.row(:index, starting_row_index + offset)
puts row.text
# => CAT03 ...
#Get the 3rd row down from the row containing a cell with yellow background colour
starting_row_index = browser.table.rows.to_a.index{ |row| row.td(:css => "td[bgcolor=yellow]").present? }
offset = 3
row = browser.table.row(:index, starting_row_index + offset)
puts row.text
# => ETS36401 ...
#Output the first column text of each row after the row containing a cell with yellow background colour
starting_row_index = browser.table.rows.to_a.index{ |row| row.td(:css => "td[bgcolor=yellow]").present? }
(starting_row_index + 1).upto(browser.table.rows.length - 1){ |x| puts browser.table[x][0].text }
# => CAT03, CAT08, ..., INTEGRA10, INTEGRA11
Let me know if that helps or if you have a specific example you want.
i feeding my Data table from excel sheet upload,i face the problem when i look for a particular columns, ironically i don't know the position of column ,That can be anywhere or may be not present
so i cant Use indexing,when i go with column name then white spaces causing the problem
i assume the i know the index of Column but how can i handle the whitespaces
so far what i tried
Code:
if (ds.Tables[0].Columns[3].Caption.Replace(" ", "").Equals("XXXX"))
{
var ds = from r in ds.Tables[0].AsEnumerable() select new { Fname=r.Field<String>("XX XX") , Lname=r.Field<string>(" Yy YY Y ") };
ds.ToList();
}
Do i need to care About the case sensitiveness in Column Name ?
how can i find the Column index if it matched with a given String ?
You can find the column like:
DataColumn yourColumn = ds.Tables[0].Columns.Cast<DataColumn>()
.Where(r => r.Caption.Trim().Equals("XXXX",StringComparison.InvariantCultureIgnoreCase))
.FirstOrDefault();