xPages creating Authors and Readers Fields - xpages

I have a querySaveDocument function for my xPage where I set up some backend fields, including Authors and Readers fields.
var authors = new Array("[AdminEditors]");
var user:String=session.getEffectiveUserName();
authors.push( user );
var authitem:NotesItem = doc.replaceItemValue("z_Authors", authors );
authitem.setAuthors(true);
var readitem:NotesItem = doc.replaceItemValue("z_Readers", "[AdminReaders]" );
readitem.setReaders(true);
I thought doc.replaceItemValue() would return a reference to the NotesItem, but authItem is null.
So how does one create a field on the backend Notes Document using SSJS and get a reference to it?
Thanks,
-- Jeff

Make sure to use getDocument(true) to have the backend document synced with changes made in the frontend document.
var doc = document1.getDocument(true);

Related

Retrieve Documents from a Template

I created a template within my DocuSign developer Sandbox that contains one document. I'm using the C# SDK to try and send out an envelope to a user, based on a template.
Here's the code where I retrieve all of the templates.
TemplatesApi templateApi = new TemplatesApi(ApiClient.Configuration);
EnvelopeTemplateResults templateResults = templateApi.ListTemplates(AccountID);
The issue I am having is the EnvelopeTemplateResults does NOT have any documents associated with it.
When I use the REST API using POSTMAN, performing a GET to this URL, I can see that there's an envelopeTemplateDefinition, that has a Document on it, which is the one I want.
My question is, how, using the SDK API, can I get the envelopeTemplateDefinition ?
In order to have the ListTemplates method include the Documents info, you have to set an Include parameter:
var templatesApi = new TemplatesApi(apiClient.Configuration);
var listTemplatesOptions = new TemplatesApi.ListTemplatesOptions { include = "documents" };
var templateResults = templatesApi.ListTemplates(accountId, listTemplatesOptions);
If you are trying to get the Template Definition of a single template, the templatesApi.Get() method can be used with its own set of Include options:
var getTemplateOptions = new TemplatesApi.GetOptions { include = "documents" };
var templateDefinition = templatesApi.Get(accountId, templateId, getTemplateOptions);
Finally, if you're trying to get an actual PDF out of a specific template, that would be the templatesApi.GetDocument() method:
templatesApi.GetDocument(accountId, templateId, documentId);
Where DocumentId is the specific document you want to pull, or "Combined" if you want to pull all the documents in as a single PDF.
Chris, if you are using the v2 API, there's an endpoint:
GET /v2/accounts/{accountId}/templates/{templateId}/documents/{documentId}
you can try it here - https://apiexplorer.docusign.com/#/esign/restapi?categories=Templates&tags=TemplateDocuments&operations=get
the c# SDK inside TemplateAPI has GetDocument() and UpdateDocument() methods

Sending email from netsuite using freemarker template engine

Can someone help me to work my task on netsuite Sending email. The email body should be generated with the freemarker template engine using nlapiCreateTemplateRenderer. I try to used the sample on the help page in netsuite but it doesnt work. Can somebody explain or give me a example on this API.
By the way i can sent email using suitelet, my problem is the email body.
Thank you.
Provided that you have your scriptable template. This should run OK.
var emailTempId = 1; // internal id of the email template
var emailTemp = nlapiLoadRecord('emailtemplate',emailTempId);
var emailSubj = emailTemp.getFieldValue('subject');
var emailBody = emailTemp.getFieldValue('content');
var records = new Object();
records['transaction'] = '1'; //internal id of Transaction
var salesOrder = nlapiLoadRecord('salesorder', 1);
var renderer = nlapiCreateTemplateRenderer();
renderer.addRecord('transaction', salesOrder );
renderer.setTemplate(emailSubj);
renderSubj = renderer.renderToString();
renderer.setTemplate(emailBody);
renderBody = renderer.renderToString();
nlapiSendEmail(-5, 'email#domain.com', renderSubj, renderBody , null, null, records);
The new Scriptable Template that is using the FreeMarker only supports Entity, Transaction, Custom Record, Case, & Project Record. Other records might work but based on Answer Id: 32621 from the SuiteAnswers those record are the ones that will be supported.

Always open the default form in CRM on the case entity

We have two forms for the case entity. The default case form is heavily customized and has become rather slow to work with. The second form, called 'fastcase', is a lightweight version of the default case form. Both forms are being used by the same users. The fastcase form is opened from a link in SharePoint. We want that the default case form is always opened when working from within CRM.
I was wondering if, and how, it is possible to force CRM to always open the default case form when working from within CRM.
The only thing I could find was this link, but I have a feeling that the solution with navigate will also force the SharePoint fastcase form to open in the default case form. Working with different user roles and groups is also not an option as suggested there.
First of all: You are not using forms they are supposed to be used. Forms are role based and you are trying to use them for something else. Anyway, I totally understand your idea and I have been in the same situation :)
You need to do a little magic trick in CRM to make a form sticky. CRM stores the Most Recently Used (MRU) forms in a special entity called UserEntityUISettings. This entity stores UI settings per entity per user in xml.
What you need to do is to prevent CRM from changing this entity whenever the user changes the form for a given entity. Basically you want to control the attribute called lastviewedformxml. You can get some inspiration from this blog post: https://community.dynamics.com/crm/b/gonzaloruiz/archive/2014/11/19/avoiding-form-reload-when-switching-crm-forms-based-on-a-field.aspx
Happy coding...
You can open CRM forms in this way:
function OpenForm()
{
var parameters = {};
var id = GetFormId("account", "FormName");
parameters["formid"] = id;
Xrm.Utility.openEntityForm("account", null, parameters);
}
function GetFormId(formEntity, formName) {
var serverUrl = Xrm.Page.context.getServerUrl();
var oDataEndpointUrl = serverUrl + "/XRMServices/2011/OrganizationData.svc/";
oDataEndpointUrl += "SystemFormSet?$top=1&$filter=ObjectTypeCode eq '" + formEntity + "' and Name eq '" + formName + "'";
var service = new window.XMLHttpRequest;
var id;
if (service != null) {
service.open("GET", oDataEndpointUrl, false);
service.setRequestHeader("X-Requested-Width", "XMLHttpRequest");
service.setRequestHeader("Accept", "application/json, text/javascript, */*");
service.send(null);
var requestResults = eval('(' + service.responseText + ')').d;
if (requestResults != null && requestResults.results.length == 1) {
var rec = requestResults.results[0];
id = rec.FormId;
}
}
return id;
}
Depends the way you are calling the form from sharepoint you call the form you need and from CRM you let it handles in the native way.

xpages custom deleting doc. from view panel

I'm trying to delete selected doc from viewPanel1. The view is categorized ( can be > 1 category ) and is listing documents from 2 different datasources, let say: Cdoc and Pdoc. These docs. are linked by a common field.
my scenario: If the users select a Cdoc => the delete action will take place to the respective Cdoc but also for the all Pdoc being in the same category. If the user selects a Pdoc => delete just the Pdoc. Also, I would like to add some confirmation text with some information ( Value fields ) from the selected documents.
I tried the following
var viewPanel=getComponent("viewPanel1");
var docIDArray=viewPanel.getSelectedIds();
for(i=0;i < docIDArray.length;i++){
var docId=docIDArray[i];
var doc=database.getDocumentByID(docId);
var formName = (doc == null)? null : doc.getItemValueString("Form");
if( formName =="fmPersContact" ){
.....
} // in this case, it works OK.
else if ( formName =="fmCompanie" ){ // here if I selected > 1 Cdoc, it deletes just one Cdoc + the respective PDocs.
var doc:NotesDocument = null;
doc=database.getDocumentByID(docId);
var ky:java.util.Vector = new java.util.Vector();
ky.add(doc.getItemValueString("txt_NumeCompanie"));
... // delete method
}
Could you tell me what I did wrong and what am I missing in the above code? thanks for your time!
The first thing you want to do is confirm. Unlike Lotusscript, you cannot use a function in the middle of a script to open the confirm dialog and get the answer. To do this, I recommend using the confirm simple action before going into an execute script simple action.
<xp:button
value="delete"
id="button1"
>
<xp:eventHandler event="onclick" submit="true" refreshMode="complete">
<xp:this.action>
<xp:actionGroup>
<xp:confirm message="Are you certain?"></xp:confirm>
<xp:executeScript
script="#{javascript:doSomething();}"
>
</xp:executeScript>
</xp:actionGroup>
</xp:this.action></xp:eventHandler></xp:button>
EDIT
In the past, I have also used built my own dialogs with the extension library, filled the text in with SSJS and then called the doWhatever() or close() from the dialog itself. This is not the best solution as it requires an update from the server to get the string. The best solution would be, as Paul Withers says, to use CSJS to perform the confirmation. I have yet to do this though.
/EDIT
For your delete function, I recommend getting the document you want to delete, then tell whether it is a P- or C- doc, either by the form name or whatever mechanism you use, and then either delete the single document or by getting a documentcollection from the view by using getAllDocumentsBykey(), then iterating through them all, deleting them one by one.
var ky:java.util.Vector = new java.util.Vector();
ky.add("MainCat");
ky.add("subCat");
ky.add("subCat2");
var vw:NotesView = database.getView("vw_myView");
var docs:NotesDocumentCollection = vw.getAllDocumentsByKey(ky);
//... delete stuff...
//dont forget to recycle
Post Question Edit
I recommend the following to get the form name:
var getSelectedDoc = function(){
var vwPnl = getComponent("viewpanel");
var ids = vwPnl.getSelectedIds();
var id = null;
var doc:NotesDocument = null;
if(ids.length > 0){ //could use for loop var i = 0; i < ids.length;i++
id = ids[0]; //could pack all ids into java.util.ArrayList and return that list to work on further
//be warned that if the user selects a parent doc and those automatically deleted by it that you need a mechanism to check if the document was already deleted!
}
if(id != null){
doc = database.getDocumentByID(id);
}
return doc;
}
var doc = getSelectedDoc();
var formName = (doc == null)? null : doc.getItemValueString("form");
if(PDOC_FORM_NAME.equalsIgnoreCase(formName)){
deleteFunctionComplete(doc);
} else if (CDOC_FORM_NAME.equalsIgnoreCase(formName)){
deleteFunctionTwo(doc);
} else {
// uh-oh
}
this also allows you to have the document in case you want to delete it right away.
Edits for comments
If Cdoc should delete more than one document, then yes. You should be using the getAllDocumentsBykey keeping in mind that the view needs to be built for it. By that I mean if you have a view with one single category, there is no issue, just plug in the string and you are fine. If you have a view with three categories, you cannot feed a vector into the getalldocs function with only two values, it must be all three. So, you want to delete all for "mycomp" with the underlying pdocs "Greg" "Sally "Bob", just use alldocsbykey("mycomp"), if the view looks like:
mycomp
---Greg
---Sally
---Bob
but if the view looks like
Poland
---mycomp
------Greg
------Sally
------Bob
then the a vector with poland and mycomp must be used. "poland" does not get the correct documents. --just an fyi and pitfall that is sometimes had.
Edit after further question clarification
I prefer this loop style to remove docs
var doc_temp:NotesDocument = null;
var doc_toDelete:NotesDocument = null;
var coll_docs:NotesDocumentCollection = ...; //get document collection
var doc_nextDoc = coll_docs.getFirstDocument();
while(doc_nextDoc != null){
doc_temp = doc_nextDoc; //set document to delete
doc_nextDoc = coll_docs.getNextDocument(doc_nextDoc); // set next document before deletion
try{
doc_temp.remove(true);//lots of errors can happen here, such as ACL settings
} catch(e) {
//handle, or just break
} finally{
if(doc_temp != null) try{doc_temp.recycle()} catch(e){}// try to recycle, could also cause errors
doc_temp = null;// for the sense of completeness
}
}
Even further edit based on the question edits
of course you are only deleting one Pdoc, the way you have that set up, you are only ever returning one document. You could expand the getSelectedDoc() to put all selected documents into an java.util.ArrayList or something, and then use that arraylist to delete more than one at a time, but that could be dangerous depending on what you do because NotesDocuments are not serialisable. In that case, I recommend using the same code that you use for getSelected doc, use a for loop to get the document IDs, get the document, if the document is not null, then delete.
apropos getAllDocumentsByKey(with a vector)
The way this is currently set up, no Vector is necessary.
If you have a view with a category and sub category and you want to get all the documents in that sub category, then you must use a vector to get at it. If you include a simple string or a vector with only one value, then the documents in the sub category will not be returned. The vector can be thought of as "cat1", "subcat", "furtherSubCat"
Furthermore, there is no check here to see if the string returned from the document is empty. This should be done. There is also no check to see if the DocumentCollection is empty. This should also be done. My expectation is that there is an issue retrieving the collection based on above mentioned reasons.

How do I return all conflict documents from a Notes Database?

I want to get all conflict documents from a Notes database. So far, i've got this:
Domino.NotesSession notesSession;
Domino.NotesDatabase notesDatabase = this.OpenDatabase(out notesSession);
Domino.NotesDateTime dateTime = notesSession.CreateDateTime(String.Empty);
Domino.NotesDocumentCollection results =
notesDatabase.Search(this.SearchString, dateTime, 0);
It works with, for example:
searchString = "#Contains(ShortName;\"Bob\")";
How can I do the equivalent for conflict documents?
Try this:
searchString = "#IsAvailable($Conflict)";
There is a field on a document that flags any Notes document as a conflict called "$Conflict". If it's present on the document, then you know it's a conflict, (like Carlos is eluding to).
You can create a view in the database that has the formula.
Select #isAvailable("$Conflict")
and then loop through all documents in the view. It looks like you're doing it in Java so I think it would look like this
import lotus.domino.*;
import java.util.*;
//.....
//.....
Session s = NotesFactory.createSession();
Database db = s.getDatabase("server", "filename");
View vw = db.getView("viewname");
Document doc = null;
doc = vw.getFirstDocument();
while (doc != null) {
// do what you want in here.
doc = vw.getNextDocument(doc);
}
You'll need to make sure you have added the Domino jars to your project. This is a good reference for setting up the eclipse IDE for Domino java development.
PS. You can also modify the design of the database to minimise replication conflicts. But I won't bore you here with the details. Post a comment if you would like to know and ill provide instructions on this thread.

Resources