Google Docs Invoice template with dynamically items row from Google Sheets - google-sheets

I really need your help with this.
I have created an invoice template in Google Docs with databases flowed from Google sheets.
The problem is:
In the template (Google Docs), I only put a specific items line (eg 3 lines).
When the data is changed, such as the number of items lines are changing, how it's automatically gone through Google Docs if there are more than 3 items lines
Many thanks for your help.
Below is my script to get data from G-sheets to G-Docs template.
function Invoice() {
let copyFile = DriveApp.getFileById('id URL').makeCopy(),
copyID = copyFile.getId(),
copyDoc = DocumentApp.openById(copyID),
copyBody = copyDoc.getBody()
let activeSheet = SpreadsheetApp.getActiveSheet(),
numOfCol = activeSheet.getLastColumn(),
activeRowIndex = activeSheet.getActiveRange().getRowIndex(),
activeRow = activeSheet.getRange(activeRowIndex, 1, 1, numOfCol).getValues(),
headerRow = activeSheet.getRange(1, 1, 1, numOfCol).getValues(),
columnIndex = 0
for (; columnIndex < headerRow[0].length; columnIndex++){
copyBody.replaceText('%' + headerRow[0][columnIndex] + '%', activeRow[0][columnIndex])
}
copyDoc.saveAndClose()
Here is screenshot of the files.
Data in G-sheet with the additional item (Item 4)
G-Docs template with specific 3 rows for 3 items lines
When I have 4 items, I must manually amend the G-Docs template. Is there any way to get its automatically.

#Duc I don't think it's possible to pass the new header as placeholder in the GDoc, it sounds like an endless loop.
Unless you pass it as List_ITEM, but I am pretty sure you will lose formatting.

Related

Is there a way to use arrayformula with match/index in google script? Or at least get it to autofill the entire column? Scripts are an option

I have the following formula: =ArrayFormula(INDEX(Items!F2:F,MATCH(C2,Items!E2:E,0)))
I would like to extend it such that the entire C column runs the same formula for values. Please help. If a script is necessary to achieve this, I'd like to explore that option too.
Use Apps Script!
Sheet functions (formulae) work great (especially if you are a master like player0), but I find it much easier to work within Apps Script for anything much more complicated than a simple INDEX MATCH. If you are willing to learn some JavaScript, I highly recommend learning some.
Custom Functions
You can write custom sheet functions in Apps Script that you can call with the traditional =FUNCTION() from a cell.
The way it works is that you write a function in Apps Script that returns a two dimensional array corresponding to the area that it needs to fill.
For example, if wanted a function to fill a 2 x 2 block with 1, you would need to make your function return:
[[1,1],[1,1]]
Or you can write it like this:
[
[1, 1],
[1, 1]
]
Implementing Index Match
There are many ways you can implement it, here is an example.
The example spreadsheet has 2 tabs, "Ledger" and "Items".
The goal of the function that follows is to get the costs of the items from the "Items" tab.
function ledgerIndexMatch(){
// Initializing the location of data
let ss = SpreadsheetApp.getActive();
let ledger = ss.getSheetByName("Ledger");
let source = ss.getSheetByName("Items");
let ledgerRange = ledger.getDataRange();
let sourceRange = source.getDataRange();
// Getting the values into a 2D array
let ledgerValues = ledgerRange.getValues();
let sourceValues = sourceRange.getValues();
// Discarding the first row (headers)
ledgerValues.shift();
sourceValues.shift();
// Initializing the output array
let output = [];
// This is where the INDEX MATCH happens
// For each row in ledger
ledgerValues.forEach(ledgerRow => {
// Get the second column (index 1)
let item = ledgerRow[1];
// Initialize the column
let value = [];
// For each row in the source
sourceValues.some(sourceRow => {
// Check if the item is there
if (item == sourceRow[0]) {
// if so, add to value
value.push(sourceRow[1]);
// stop looking for values
return true
// if not matched, keep looking
} else return false
})
// Add the found value (or blank if not found)
// to the output array.
output.push(value);
})
return output;
}
Which can be used like this:
Whats nice about Apps Script is that you can customize it to your heart's content. In this example, the function automatically detects the height of the respective tables, so you don't need to fiddle around with ranges.
You might want to extend this function with arguments so that its more flexible. Or you could just have a few versions of it for different operations, if you don't have too many. Or refactor it... its up to you.
References
Apps Script
Custom Functions
Tutorials
SpreadsheetApp
use:
=ARRAYFORMULA(IFNA(VLOOKUP(C2:C, Items!E2:F, 2, 0)))

How do I compare a specific cell with a column range and return a string associated with the column range?

Thanks for reading my first question. I'm just starting out with google sheets to please bear with me.
Here is the sheet I'm working with
So,this sheet if for a game I play and we assign guild attacks based on power levels. I'm looking to create a function or script and put it in Column O. I'd like this function to compare Column F to a specific cell in Column M and then return the user associated with Column F that is >= than the specific cell in Column M. Like this enter image description here
I highlighted the first three as an example.
I can obviously do this manually but I takes time, and was looking to automate this process so it becomes more efficient. I've tried Vlookups, MATCH, IF and I've been unsuccessful. Any help would be greatly appreciated. Again, I'm just a beginner with google sheets so please go easy on me. :)
Solution
As you metioned that you would also be happy with an scripted solution I have created this script that I believe solves your issue. It has comments explaining step by step how it works:
function myFunction() {
// Get our sheet
var ss = SpreadsheetApp.getActive().getSheetByName('Automate Test');
// Get the values of the ranges of F and M. Flat will convert the 2D array we get from getValues() into a 1D one which is easier to work with
var valuesF = ss.getRange('F2:F16').getValues().flat();
var valuesD = ss.getRange('D2:D16').getValues().flat();
var valuesM = ss.getRange('M2:M16').getValues().flat();
var valuesN = ss.getRange('N17:N31').getValues().flat();
// We will iterate through all the players in column M to find their opponents
for(i=0;i<valuesM.length;i++){
// We create an empty array to be filled with the list of possible opponents to then choose a random one of the list
var playersHigherEqual = [];
// Iterate through the opponent list
for(j=0;j<valuesF.length;j++){
// If the opponent meets the condition
if(valuesF[j]>= valuesM[i]){
// Add it to the array of possible opponents
playersHigherEqual.push(ss.getRange(j+2, 2).getValue());
}
}
//Finally we will set the opponent by choosing a random one out of the list. Note that i+2 is because the arrays start from 0
ss.getRange(i+2, 15).setValue(playersHigherEqual[Math.floor(Math.random()*playersHigherEqual.length)]);
}
// We will iterate through all the players in column M to find their opponents
for(i=0;i<valuesN.length;i++){
// We create an empty array to be filled with the list of possible opponents to then choose a random one of the list
var playersHigherEqual = [];
// Iterate through the opponent list
for(j=0;j<valuesD.length;j++){
// If the opponent meets the condition
if(valuesD[j]>= valuesN[i]){
// Add it to the array of possible opponents
playersHigherEqual.push(ss.getRange(j+2, 2).getValue());
}
}
//Finally we will set the opponent by choosing a random one out of the list. Note that i+2 is because the arrays start from 0
ss.getRange(i+17, 15).setValue(playersHigherEqual[Math.floor(Math.random()*playersHigherEqual.length)]);
}
}
Please let me know if you also need a sheet formula solution for this question. For more information about Apps Script check out the documentation.
I hope this has helped you. Let me know if you need anything else or if you did not understood something. :)

How to optimize pulling multiple results of text comparison across multiple tabs in a Google Sheet? (QUERY vs FILTER vs other functions)

new as heck here and I trying to find the best way to further optimize a set of sheets functions.
The starting function was essentially 26 stacked filter functions being used to reference individual cells beneath containing names(strings), find the IDs associated with the names in these cells, pull the IDs from the "ref" sheet, and create a url that contains these IDs. The function, stripped of confidential data:
=HYPERLINK(CONCATENATE("https://url.com/stuff?ids=",if(isna(filter(ref!$B:$B,ref!$A:$A=B3))=true,"",filter(ref!$B:$B,ref!$A:$A=B3)),",",if(isna(filter(ref!$B:$B,ref!$A:$A=B4))=true,"",filter(ref!$B:$B,ref!$A:$A=B4)),",",if(isna(filter(ref!$B:$B,ref!$A:$A=B5))=true,"",filter(ref!$B:$B,ref!$A:$A=B5)),",",if(isna(filter(ref!$B:$B,ref!$A:$A=B6))=true,"",filter(ref!$B:$B,ref!$A:$A=B6)),",",if(isna(filter(ref!$B:$B,ref!$A:$A=B7))=true,"",filter(ref!$B:$B,ref!$A:$A=B7)),",",if(isna(filter(ref!$B:$B,ref!$A:$A=B8))=true,"",filter(ref!$B:$B,ref!$A:$A=B8)),",",if(isna(filter(ref!$B:$B,ref!$A:$A=B9))=true,"",filter(ref!$B:$B,ref!$A:$A=B9)),",",if(isna(filter(ref!$B:$B,ref!$A:$A=B10))=true,"",filter(ref!$B:$B,ref!$A:$A=B10)),",",if(isna(filter(ref!$B:$B,ref!$A:$A=B11))=true,"",filter(ref!$B:$B,ref!$A:$A=B11)),",",if(isna(filter(ref!$B:$B,ref!$A:$A=B12))=true,"",filter(ref!$B:$B,ref!$A:$A=B12)),",",if(isna(filter(ref!$B:$B,ref!$A:$A=B13))=true,"",filter(ref!$B:$B,ref!$A:$A=B13)),",",if(isna(filter(ref!$B:$B,ref!$A:$A=B14))=true,"",filter(ref!$B:$B,ref!$A:$A=B14)),",",if(isna(filter(ref!$B:$B,ref!$A:$A=B15))=true,"",filter(ref!$B:$B,ref!$A:$A=B15)),",",if(isna(filter(ref!$B:$B,ref!$A:$A=B16))=true,"",filter(ref!$B:$B,ref!$A:$A=B16)),",",if(isna(filter(ref!$B:$B,ref!$A:$A=B17))=true,"",filter(ref!$B:$B,ref!$A:$A=B17)),",",if(isna(filter(ref!$B:$B,ref!$A:$A=B18))=true,"",filter(ref!$B:$B,ref!$A:$A=B18)),",",if(isna(filter(ref!$B:$B,ref!$A:$A=B19))=true,"",filter(ref!$B:$B,ref!$A:$A=B19)),",",if(isna(filter(ref!$B:$B,ref!$A:$A=B20))=true,"",filter(ref!$B:$B,ref!$A:$A=B20)),",",if(isna(filter(ref!$B:$B,ref!$A:$A=B21))=true,"",filter(ref!$B:$B,ref!$A:$A=B21)),",",if(isna(filter(ref!$B:$B,ref!$A:$A=B22))=true,"",filter(ref!$B:$B,ref!$A:$A=B22)),"&morestuff=true"),"Group A")
The best I could do to optimize this was to compile the IDs in one cell (B1) with this QUERY function within a TEXTJOIN:
=TEXTJOIN(",",TRUE, QUERY(ref!$A$2:$B, "select B where A = '"&B3&"' or A = '"&B4&"' or A = '"&B5&"' or A = '"&B6&"' or A = '"&B7&"' or A = '"&B8&"' or A = '"&B9&"' or A = '"&B10&"' or A = '"&B11&"' or A = '"&B12&"' or A = '"&B13&"' or A = '"&B14&"' or A = '"&B15&"' or A = '"&B16&"' or A = '"&B17&"' or A = '"&B18&"' or A = '"&B19&"' or A = '"&B20&"' or A = '"&B21&"' or A = '"&B22&"' or A = '"&B23&"' or A = '"&B24&"' or A = '"&B25&"' or A = '"&B26&"' or A = '"&B27&"' or A = '"&B28&"' or A = '"&B29&"' "))
Then do the url generation in another cell (B2), referencing B1 for the IDs:
=HYPERLINK(CONCATENATE("https://url.com/stuff?ids=", ",", B1, "&morestuff=true"), "Group A")
I then copied these across Groups B-Z
I tried multiple variations of FILTER stacked in ARRAYFORMULA but I couldn't get it to work. I'm unsure if there is a syntax I should be using to better handle matching text that I am not quite figuring out. Simply matching by first letter is not an option as there are names that do not qualify for the groupings contained within the "ref" sheet for use in other data sets.
So my question here is really: is there an easier way to compile this where I don't have to reference each cell individually for matches on the "ref" sheet?
For an example of the sheet I am working with, this link should work:
https://docs.google.com/spreadsheets/d/1ykSldWyQnPcar9G21ljLOzm3dWC1i82kMaQJuSKHajc/edit?usp=sharing
Just use another textjoin to construct your query string as follows:
="select B"&if(counta(B3:B)=0,""," where A='")&textjoin("' or A='",true,B3:B)
Not only is this much shorter than manually typing each cell but it will also expand infinitely downward as required.

Google Spreadsheets: match multiple variables in multiple columns using match

Google Spreadsheets: I am trying to match multiple variables in multiple columns
I have tried this code
=match(T7&C7&"v";T$2:T6&C$2:C6&K$2:K6)
that I expected would woork, but it does not .... any ideas how I can do this?
Try this:
=ARRAYFORMULA(match(T7&C7&"v",ARRAYFORMULA(TRANSPOSE(Split(CONCATENATE(T$2:T6&C$2:C6&K$2:K6&"|"),"|"))),0))
If this does not work, please give us an example of your data
This is the final formula
=if(D2<>""; vlookup(arrayformula(MAX(( T$1:T1 = T2 )*4 + ( C$1:C1 = C2 )*2 + ( K$1:K1 = "✓" )*1));Lookup!D:E;2);"")
First check if cell empty
Then find mathcing values above the current row, start with most
important first
Then verify/code-label the results (7 = full match, 6 = site +
link, 4 = only site)
Setup a lookup table to translate the results to values you
understand

Getting the Item Count of a large sharepoint list in fastest way

I am trying to get the count of the items in a sharepoint document library programatically. The scale I am working with is 30-70000 items. We have usercontrol in a smartpart to display the count . Ours is a TEAM site.
This is the code to get the total count:
SPList VoulnterrList = web.Lists[ListTitle];
SPQuery query = new SPQuery();
query.ViewAttributes = "Scope=\"Recursive\"";
string queries = "<Where><Eq><FieldRef Name='ApprovalStatus' /><Value Type='Choice'>Pending</Value></Eq></Where>";
query.Query = queries;
SPListItemCollection lstitemcollAssoID = VoulnterrList.GetItems(query);
lblCount.Text = "Total Proofs: " + VoulnterrList.Items.Count.ToString() + " Pending Proofs: " + lstitemcollAssoID.Count.ToString();
The problem is this has serious performance issue it takes 75 to 80 sec to load the page. if we comment this page load will decrees to 4 sec. Any better approch for this problem
Ours is sharepoint 2007
Use VoulnterrList.ItemCount instead of VoulnterrList.Items.Count.
When List.Items is used, all items in the list are loaded from the content database. Since we don't actually need the items to get the count this is wasted overhead.
This will fix performance at line 8, but you may still have issues at line 9 depending on the number of results returned by the query.
You can do two optimizations here:
Create an index on one of the column of your list
Use that column in <ViewFields> section of your CAML query so that only that indexed column is retrieved.
This should speed up. See this article on how to create index on column:
http://sharepoint.microsoft.com/Blogs/GetThePoint/Lists/Posts/Post.aspx?ID=162

Resources