The attachments is empty in mailmessageattachments - exact-online

When I execute the query as shown the attachment is always empty. I would expect that the contents of the attachment with name AttachmentFileName would be in the column Attachment.
How do I retrieve the blob of the file?
select /*+ join_set(mat, mailmessageid, 5000) */ mat.Attachment xmlfilecontents
, mat.division || '-' || AttachmentFileName filename
from mailmessagesreceived mre
join MailMessageAttachments mat
on mat.mailmessageid = mre.id
and mat.Type in ( 20, 22 ) /* 20: UBL 2.0, 22: Simplerinvoicing 1.0 */
where mre.SenderMailbox = 'Facturen#ExactOnline.nl'
and mre.created >= add_months(trunc(sysdate, -1), -10)
and mat.FileSize > 0

The column Attachment stores the attachment directly associated with the received Exact Online MailMessage, as long as the mail message hasn't been processed. In that case, the attachment is forwarded to Documents.
However, the Exact Online invoices itself are retrieved indirectly. The Internet location is in the field Url. It is also available in the table using the column AttachmentFromUrl.

Related

VLookup not working on full numbered Value

I created a Google Spreadsheet (File Name Product Test) and I have an ID field on column A which contains the word ID plus some letters and numbers (Example "ID-KNYT-12345"). The KNYT part is different per ID, some KNYT some DMXF etc.
So in column B I added a custom formula (Sample below) which processes the ID. If KNYT only numbers are kept. If DMXF the DMXF part is included plus the numbers.
I then have a vlookup/importrange formula on column C which is supposed to use the converted value in column B to lookup the value from another sheet and retrieve a certain information.
The problem is if the converted value contains all numbers like 12345 the vlookup fails, "Did not find value in lookup evaluation". If the converted value contains letters and numbers like DMXF-25452 the lookup works. If I manually type 12345 on column A the lookup works. Why would the lookup say it didn't find a result when the value is there? More details below
I checked, all cells involved are in format Number>"AUTOMATIC".
I checked, the value 12345 is definitely found on the other sheet (Imported Range)
I checked these values online, I found no hidden characters or spaces
The data is from an email with attached Excel file. I don't download the file, I just click to preview it and copy-paste the entire table over to my Product Test spreadsheet
The custom Formula:
function Convert(Thevalue)
{
Thevalue = Thevalue.toString().replace("ID-KNYT-", "");
Thevalue = Thevalue.toString().replace("ID-DMXF-", "DMXF-");
if (Thevalue == "DMXF-2245"){Thevalue = "Evaluated";}
if (Thevalue == "DMXF-3268"){Thevalue = "Pending";}
return Thevalue;
}
The Vlookup (Not actual sheet url just a sample)
VLOOKUP($B1,IMPORTRANGE("https://docs.google.com/spreadsheets/d/feiugsdfjhsdkjfhiesdfjh-p-dsflkjgsdf/edit#gid=000222333","sheet1!$A:$C"),3,FALSE)
UPDATE: This seem to fix it for me. Looks like if the return value is all numbers and no letters it is a NaN issue
if (!isNaN(Thevalue))
{
return Number(Thevalue);
}
else
{
return Thevalue;
}
Your custom function returns text strings. The vlookup() function does not consider the number 123 and the text string "123" equal. To make it work, convert the lookup keys to text with to_text(), like this:
=vlookup( to_text($B1), Sheet1!$A:$C, columns(Sheet1!$A:$C), false )
As RemcoE33 said, the custom function seems superfluous, because the same thing can be done with a plain vanilla spreadsheet formula that employs regexreplace(), like this:
=arrayformula( regexreplace( to_text(A2:A), "ID(?:-KNYT)?-", "" ) )

Convert a TXT delimited TAB to Google Sheets

I'm looking for a mean to convert my TXT file into a Google Sheets :
function convert_txt_gsheets(){
var file = DriveApp.getFilesByName('file.txt').next();
var body = file.getBlob().getDataAsString().split(/\n/);
var result = body.map( r => r.split(/\t/));
SpreadsheetApp.getActive().getSheets()[0].getRange(1,1,result.length,result[0].length).setValues(result);
return;
}
An error occured "The number of columns in the data does not match the number of columns in the range. The data has 1 but the range has 18."
Does someone have an idea ?
If I import the txt file manually it works but I need to do it through an G apps script.
I only see typos/wrong method names for getBlob and getFilesByName (you used getBlobl and getFileByName), but aside from that, the only possible issue that will cause this is that something from the file is written unexpectedly.
Update:
Upon checking, your txt file has a line at the bottom containing a blank row. Delete that and you should successfully write the file. That's why the error is range is expecting 18 columns but that last row only has 1 due to not having any data.
You could also filter the file before writing. Removing rows that doesn't have 18 columns will fix the issue. See code below:
Modification:
var result = body.map( r => r.split(/\t/)).filter( r => r.length == 18);
Successful run:

How to merge rows with the same column value on Google Apps Script

One of my daily tasks is to clean up data for my company who deals with multiple clients. The data is purchase data wherein we have the client's name in column A and their monthly purchase in the succeeding columns.
The issue I have is that around the March, a few clients had to be re-registered on our system which caused a double entry of rows under the same client name (1 row for purchases from Jan-March and another row for April-September-but both rows' column A value is the same client name), and now I manually merge all the rows under the same client name.
I've attached an image to illustrate better.
How the data looks now and desired output
Hoping to do this on app scripts since I'll be copy pasting this data on sheets everyday. Would any of you have a workaround / code that can merge row data based on an identical column A value? Greatly appreciate any help as it will save A LOT of time!
It is unclear why you would want to use a script here, given that a range can be condensed as requested with a plain vanilla spreadsheet query() formula that uses max(), like this:
=query(
Sheet1!A2:H10,
"select A, max(B), max(C), max(D), max(E), max(F), max(G), max(H)
where A is not null
group by A",
1
)
To replace your original data with the "condensed" data, use ControlC to copy and ControlShiftV to paste values only. On a Mac, use ⌘C and ⌘ShiftV.
The question specifies Apps Script, so here's a custom function to do the same, together with a simple function that uses it to condense a hard-coded range in a spreadsheet.
/**
* Merges rows in 'Sheet1!A2:H' by taking the last non-blank value in each
* column, separately for each row group that has the same key in column A2:A.
* The result will include exactly one copy of each key.
*/
function mergeRows() {
const range = SpreadsheetApp.getActive().getRange('Sheet1!A2:H');
const condensed = condenseRows(range.getValues(), 0);
range
.clearContent()
.offset(0, 0, condensed.length, condensed[0].length)
.setValues(condensed);
}
/**
* Gets exactly one row per each unique key in a key column.
* For each result row, keeps the last non-blank value in each column, separately
* per each row group that has the same key in the key column.
*
* #param {Object[][]} array2D The array to condense.
* #param {Number} columnIndex Optional. The zero-indexed column number where keys appear. Defaults to 0.
* #return {Object[][]} A 2D array where there is just one copy of each key.
* #customfunction
*/
function condenseRows(array2D, columnIndex = 0) {
// version 1.0, written by --Hyde, 16 September 2021
// - see https://stackoverflow.com/a/69205954/13045193
const hash = {};
array2D.forEach(row => {
const key = row[columnIndex];
if (key === '' || ((key == null))) {
return;
}
if (!hash[key]) {
hash[key] = [];
}
row.forEach((value, index) => {
if (value !== '' && ((value != null))) {
hash[key][index] = value;
}
});
});
const result = [];
Object.getOwnPropertyNames(hash).forEach(key => result.push(hash[key]));
return result;
}

Web App with Google Script reads Gsheet Speed Optimization

I made a simple web app with GS and now need to optimize the speed of loading data from a Gsheet. Description of the app:
It is a tool to collect the correct colors of a product in an image.
When user clicks on load image button, the app will read the URL from a Gsheet where all the tasks are stored in rows and load the image. User then select colors from a palette and submit colors. Then the app will save the selected color values to the same row of the image URL.
Each task should be assigned to n users (no more no less, feedbackRequested as below) to avoid bias and the same task should not be assigned to the same user more than once. So I stored the tasks in this way:
index imageID URL feedbackRequested user rgb_value
1 104904677 *** 3
2 104904677 *** 3
3 104904677 *** 3
4 104904678 *** 2
5 104904678 *** 2
I spread n feedbackRequested to n rows to assign the tasks. So when a user clicks on load image, the following will be executed:
get an array with all imageIDs this user has done;
var user = Session.getActiveUser().getEmail();
var data = sheet.getRange(1,2,sheet.getLastRow(),4).getValues();
var filter_user = ArrayLib.filterByText(data, 3, user);
var user_imageIDs = filter_user.map(function(value,index) {return value[0]});
if imageID is in the array or user is not empty, continue looking until we find the row;
var ct = 1;
while ( (user_imageIDs.includes(data[ct][0])) || (data[ct][3] != '') ) {
ct++;
};
set the user value to the user on this row and save his answer to rgb_value.
sheet.getRange(ct+1, 5,1,2).setValues(user, somevalue);
This way it takes a lot of time to find the conditioned row with while loop. Is there other ways to do this?
I know this is a lot of information. Thanks very much in advance! Please let me know if you need the entire code to reproduce.
Create a Set of imageIDs which contain usr:
const imageSet = data.reduce((s,[id,_,_,usr])=>
usr === user ? s.add(id) : s,
new Set)
Use findIndex to find the index of data array, where usr is empty and id is not in imageSet:
const ct = data.findIndex(([id,_,_,usr])=> usr === "" && !imageSet.has(id))

Invalid argument in getContactsByCustomField

I'm writing a google apps script to keep my contacts in sync with a spreadsheet of contacts. We have a lot of contacts with no emails, so I needed to create a custom unique id. As these contacts are added via a Google form (by one staff member only), it made sense (to me) to just use the timestamp as the unique id.
So in my script, I'm checking for matching contacts using this custom field, as follows:
//get the time stamp from the spreadsheet
var timeStamp = sheet.getRange(i+2, 1, 1, 1).getValue();
//find contacts with that timestamp in their Time Stamp field
var contacts = ContactsApp.getContactsByCustomField(timeStamp, 'Time Stamp');
The second line (20th line in my function) throws this error:
Invalid argument (line 20, file "Code")
I notice in the google API reference that the second parameter to getContactsbyCustomField needs to be an 'extended field', but the example provided suggests I can name this what I want.
I'm a bit lost on how to fix this. 10 years since I last did any decent coding, and that was mostly PHP/MySQL stuff, so feeling like I'm back at coding pre-school at the moment!
This is happening because when you get the Timestamp with the following line of code it is casting it to a Date object;
var timeStamp = sheet.getRange(i+2, 1, 1, 1).getValue();
You would expect a value like 12/14/2015 9:50:03 but you are really getting a value like Mon Dec 14 2015 09:50:03 GMT-0500 (EST)
I'm not sure if this is working as intended or if an issue needs to be raised.
I was able to fix this by converting the date when I added it as a custom field.
var c = ContactsApp.createContact(e.namedValues["First Name"],e.namedValues["Last Name"] , e.namedValues["Email"]);
c.addCustomField("Time Stamp", new Date(e.namedValues["Timestamp"]).toString());
You will also need to convert the read in value to a string also.
//get the time stamp from the spreadsheet
var timeStamp = sheet.getRange(i+2, 1, 1, 1).getValue();
//find contacts with that timestamp in their Time Stamp field
var contacts = ContactsApp.getContactsByCustomField(timeStamp.toString(), 'Time Stamp');