Add rows in smartsheets using python - smartsheet-api

How do I take a list of values, iterate through it to create the needed objects then pass that "list" of objects to the API to create multiple rows?
I have been successful in adding a new row with a value using the API example. In that example, two objects are created.
row_a = ss_client.models.Row()
row_b = ss_client.models.Row()
These two objects are passed in the add row function. (Forgive me if I use the wrong terms. Still new to this)
response = ss_client.Sheets.add_rows(
2331373580117892, # sheet_id
[row_a, row_b])
I have not been successful in passing an unknown amount of objects with something like this.
newRowsToCreate = []
for row in new_rows:
rowObject = ss.models.Row()
rowObject.cells.append({
'column_id': PM_columns['Row ID Master'],
'value': row
})
newRowsToCreate.append(rowObject)
# Add rows to sheet
response = ss.Sheets.add_rows(
OH_MkrSheetId, # sheet_id
newRowsToCreate)
This returns this error:
{"code": 1062, "errorCode": 1062, "message": "Invalid row location: You must
use at least 1 location specifier.",
Thank you for any help.

From the error message, it looks like you're missing the location specification for the new rows.
Each row object that you create needs to have a location value set. For example, if you want your new rows to be added to the bottom of your sheet, then you would add this attribute to your rowObject.
rowObject.toBottom=True
You can read about this location specific attribute and how it relates to the Python SDK here.

To be 100% precise here I had to set the attribute differently to make it work:
rowObject.to_bottom = True
I've found the name of the property below:
https://smartsheet-platform.github.io/smartsheet-python-sdk/smartsheet.models.html#module-smartsheet.models.row

To be 100% precise here I had to set the attribute differently to make it work:
Yep, the documentation isn't super clear about this other than in the examples, but the API uses camelCase in Javascript, but the same terms are always in snake_case in the Python API (which is, after all, the Pythonic way to do it!)

Related

SharePoint REST: Column does not exist error

I'm calling a REST API with a SharePoint Designer workflow on SharePoint online. I'm setting the column name with a variable, and when i put the variable into my URL to call it it says "Column [name] does not exist".
Annoying part is when I call just /items? I can see the column in the result, but if I try select it or filter by it I get 'does not exist'. I have alot of these columns similarly named, and I get the error for all of them.
I am using the internal name, I have tried adding "OData_" to the front. I've tried typing the url manually in the browser and entering values (incase the variable was causing issues) but I get the same error, column does not exist. but i can see it them I call all items. :(
so I have quite a few columns with naming convention "[Q#] Score [#]" eg "Q4 Score 2". The internal name that's clearly appearing in the full items results is "Q4_x0020_Score_x0020_2".
This works:
https://MYSITE.sharepoint.com/sites/portal/intranet/CorpServices/QSR/_api/web/lists/GetbyTitle('Audit')/Items?
and I get big full normal REST results that includes the line:
0
However if I try:
https://MYSITE.sharepoint.com/sites/portal/intranet/CorpServices/QSR/_api/web/lists/GetbyTitle('Audit')/Items?$Select=Q4_x0020_Score_x0020_2
Then I get:
-2146232832, Microsoft.SharePoint.SPExceptionColumn 'Q4_x0020_Score_x0020_2' does not exist. It may have been deleted by another user.
I expect to be able to select that column (and the dozens like it) but none work. I've searched all similar problems on the forum and they've usually got a spelling mistake or forgot the ODATA_ but i cant seem to get the problem. Please help.
It seemed to be working intermittently.... So it was in fact just a naming error...... Half of the columns were [Q#]_x0020_Score_x0020_[#] and half were [Q#]_x0020_score_x0020_[#]. The word "Score" was capitalized on some and not others. I Didn't realize the HTTP Calls were case sensitive. Now I have added a bunch of if statements to handle the different variations haha. Thanks for reading.
Judging by the naming convention you are on an older version of SharePoint. The x0020 is the value for a space. Ideally when you first create the column you would name it without the spacing. For example UserInformation. Then come in and edit the name after the fact and call it User Information. If you click on the title name and look at the URL, you will see what the actual name of the column is at the end of the URL. It is case sensitive because you can have a column named score and Score which is ultimately why it wasn't working.
Must load all fields like this
var lists = context.Web.Lists;
context.Load(lists);
context.ExecuteQuery();
CamlQuery query = new CamlQuery();
query.ViewXml = #"";
var list = lists.GetById("file.guid");
var listitems = list.GetItems(query);
context.Load(listitems);
context.ExecuteQuery();
var creationInformation = new ListItemCreationInformation();
var newItem=list.AddItem(creationInformation);
var fields = list.Fields;
context.Load(fields);
context.ExecuteQuery();

How to get column title for each row entry

I am using a row id to obtain the cells for a single row. However, the response returns the column id but not the title of the column. In an attempt to make the code readable for others it would be helpful to also obtain the column title. I was thinking of doing this by using the column id that is obtained in the getRow function but I am not entirely sure how to catch it. Below is the basic getRow function for reference. I appreciate any assistance. Thank you in advance all.
smartsheet.sheets.getRow(options)
.then(function(row) {
console.log(row);
})
.catch(function(error) {
console.log(error);
});
My preferred way of addressing this is to dynamically create a column map on my first GET /sheets/{sheetId} request.
Let's say we have a sheet with three columns: Japan, Cat, and Cafe. Here is one way to make a column map.
const columnMap = makeColumnMap(<your sheet data>);
function makeColumnMap(sheetData){
const colMap = {};
sheetData.columns.map( column => colMap[column.title] = column.id);
return colMap;
}
Now, you can reference your specific columns like this: columnMap["Japan"], columnMap["Cat"], and columnMap["Cafe"] or you can use dot notation if you prefer.
Basically, what we're doing is creating a dictionary to map the column titles to the corresponding column id.
Posting this as a separate answer based on your response (and for easier formatting).
I have a couple specific recommendations that will help you.
Try to consolidate your API calls.
I then want to use that columnID to call getColumns(columnId) to obtain the title.
This is 'work' that you don't need to do. A single GET /sheets/{sheetId} will include all the data you need in one call. It's just a matter of parsing the JSON response.
Use this as an opportunity to improve your ability to work with JSON.
I do not know how to catch the columnId once getRow() is called.
The response is a single object with nested arrays and objects. Learning to navigate the JSON in a way that makes sense to you will come in really handy.
I would recommend saving the response from a GET sheet call as it's own JSON file. From there, you can bring it into your script and play with your logic to reference the values you want.

Data factory lookup (dot) in the item() name

I am having lookup wherein salesforce query is there. I am using elements (item()) in subsequent activities. Till now i had item().name or item().email but now i have item().NVMStatsSF__Related_Lead__r.FirstName which has (dot) in the field name.
How should i parse it through body tag so that it reads it correctly?
So I have the following data in item()
{
"NVMStatsSF__Related_Lead__c": "00QE000egrtgrAK",
"NVMStatsSF__Agent__r.Name": "ABC",
"NVMStatsSF__Related_Lead__r.Email": "geggegg#gmail.com",
"NVMStatsSF__Related_Lead__r.FirstName": "ABC",
"NVMStatsSF__Related_Lead__r.OwnerId": "0025434535IIAW"
}
now when i use item().NVMStatsSF__Agent__r.Name it will not parse because of (dot) after NVMStatsSF__Agent__r. And it is giving me the following error.
'item().NVMStatsSF__Related_Lead__r.Email' cannot be evaluated because property 'NVMStatsSF__Related_Lead__r' doesn't exist, available properties are 'NVMStatsSF__Related_Lead__c, NVMStatsSF__Agent__r.Name, NVMStatsSF__Related_Lead__r.Email, NVMStatsSF__Related_Lead__r.FirstName, NVMStatsSF__Related_Lead__r.OwnerId'.",
"failureType": "UserError",
"target": "WebActivityToAddPerson"
this is because ADF uses '.' for object reading.
Could you find a way to rename the field name which contains '.'?
Seems like you need a built-in function to get the value of an object according to the key. Like getValue(item(), 'key.nestkey'). But unfortunately, seems there isn't such a function. You may need handle your key first.
Finally, it worked. I was being silly.
Instead of taking the value from the child table with the help of (dot) operator I just used subquery. Silly see.
And it worked.

mirth connect Database Reader automatic column mapping

Please could somebody confirm the following..
I am using Mirth Connect 3.5.08232.
My Source Connector is a Database Reader.
Say, I am using a query that returns multiple rows, and return the result (via JavaScript), as documentation suggests, so that Mirth would treat each row as a separate message. I also use a couple of mappers as source transformers, and save the mapped fields in my channel map (which ends up to contain only those fields that I define in transformers)
In the destination, and specifically, in destination response transformer (or destination body, if it is a JavaScript writer), how do I access the source fields?
the only way I found by trial and error is
var rawMsg = connectorMessage.getRawData();
var xmlMsg = new XML(rawMsg);
logger.info(xmlMsg.some_field); // ignore the root element of rawMsg
Is this the right way to do this? I thought that maybe the fields that were nicely automatically detected would be put in some kind of a map, like sourceMap - but that doesn't seem to be the case, right?
Thank you
If you are using Mapper steps in your transformer to extract the data and put it into a variable map (like the channel map), then you can use any of the following methods to retrieve it from a subsequent JavaScript context (including a JavaScript Writer, and your response transformer):
var value = channelMap.get('key');
var value = $c('key');
var value = $('key');
Look at the Variable Maps section of the User Guide for more information.
So to recap, say you're selecting a column "mycolumn" with a Database Reader. The XML sent to the channel will be something like this:
<result>
<mycolumn>value</mycolumn>
</result>
Then you can choose to extract pieces of that message into specific variables for later use. The transformer allows you to easily drag-and-drop pieces of the sample inbound message.
Finally in your JavaScript Writer (or in any subsequent filter, transformer, or response transformer), just drag the value into the field you want:
And the corresponding JavaScript code will automatically be inserted:
One last note, if you are selecting a lot of variables and don't want to make Mapper steps for each one individually, you can use a JavaScript Step to iterate through the message and extract each column into a separate map variable:
for each (child in msg.children()) {
channelMap.put(child.localName(), child.toString());
}
Or, you can just reference the columns directly from within the JavaScript Writer:
var msg = new XML(connectorMessage.getEncodedData());
var column1 = msg.column1.toString();
var column2 = msg.column2.toString();
...

Get statuscode text in C#

I'm using a plugin and want to perform an action based on the records statuscode value. I've seen online that you can use entity.FormattedValues["statuscode"] to get values from option sets but when try it I get an error saying "The given key was not present in the dictionary".
I know this can happen when the plugin cant find the change for the field you're looking for, but i've already checked that this does exist using entity.Contains("statuscode") and it passes by that fine but still hits this error.
Can anyone help me figure out why its failing?
Thanks
I've not seen the entity.FormattedValues before.
I usually use the entity.Attributes, e.g. entity.Attributes["statuscode"].
MSDN
Edit
Crm wraps many of the values in objects which hold additional information, in this case statuscode uses the OptionSetValue, so to get the value you need to:
((OptionSetValue)entity.Attributes["statuscode"]).Value
This will return a number, as this is the underlying value in Crm.
If you open up the customisation options in Crm, you will usually (some system fields are locked down) be able to see the label and value for each option.
If you need the label, you could either do some hardcoding based on the information in Crm.
Or you could retrieve it from the metadata services as described here.
To avoid your error, you need to check the collection you wish to use (rather than the Attributes collection):
if (entity.FormattedValues.Contains("statuscode")){
var myStatusCode = entity.FormattedValues["statuscode"];
}
However although the SDK fails to confirm this, I suspect that FormattedValues are only ever present for numeric or currency attributes. (Part-speculation on my part though).
entity.FormattedValues work only for string display value.
For example you have an optionset with display names as 1, 2, 3,
The above statement do not recognize these values because those are integers. If You have seen the exact defintion of formatted values in the below link
http://msdn.microsoft.com/en-in/library/microsoft.xrm.sdk.formattedvaluecollection.aspx
you will find this statement is valid for only string display values. If you try to use this statement with Integer values it will throw key not found in dictionary exception.
So try to avoid this statement for retrieving integer display name optionset in your code.
Try this
string Title = (bool)entity.Attributes.Contains("title") ? entity.FormattedValues["title"].ToString() : "";
When you are talking about Option set, you have value and label. What this will give you is the label. '?' will make sure that the null value is never passed.