Hello,
you must add eSignature field to your entity. it's a new type of field like varchar, integer, float, image,....
go admin section, entity manager, contact, add field "eSignature".
same for opportuinity.
Announcement
Collapse
No announcement yet.
Tutorial - How to add electronic signature capability to espoCRM
Collapse
X
-
2) Make sure that you are using the "print" icon at the top of the document to print and not the Print to Pdf Espo option
this is my mistake, it looks like eSignature only works for "Work Order". I am trying to use it on an existing Entity - "Contact" and "Opportunity". I do not have "Display eSignature Document" in the menu, only "Print to PDF"
if there is a solution to how to connect "eSignature", I will be very grateful for the hint
Leave a comment:
-
Originally posted by alexisc View PostEspo Version 6.0.8
eSignature version 2.0.0
everything works perfectly, until the moment the signature is printed
place holder @@sig[{{eSignature}}]/sig@@ displays SVG code, not the image itself
Suggestions:
1) Try: @@sig[eSignature]/sig@@ (no double bracket)
2) Make sure that you are using the "print" icon at the top of the document to print and not the Print to Pdf Espo option
Originally posted by alexisc View Postcode "<img src="{{field-name}}">" - does not workLast edited by telecastg; 01-12-2021, 07:55 PM.
Leave a comment:
-
Espo Version 6.0.8
eSignature version 2.0.0
everything works perfectly, until the moment the signature is printed
place holder @@sig[{{eSignature}}]/sig@@ displays SVG code, not the image itself
code "<img src="{{field-name}}">" - does not work
Leave a comment:
-
New version (2.0.0) released, compatible with Espo 6.0.6 https://github.com/telecastg/esignat...ts-for-espocrm
- Likes 2
Leave a comment:
-
Off-topic but there are some great coders in here. Do you know what would need to be done to embed a WordPress page in an iframe dashlet? If anybody knows that would be great!
Leave a comment:
-
I would use a generic "start date" field and create different templates for each type of agreement, since each document should have difference verbiage and all you want to do is to fill in placeholders with field information.
Leave a comment:
-
I'm quite interested in this new post of yours too telecastg! We have multiple agreement (of which is one Lease one type of agreement we also do).
Food for thought though.
How do should field be created? For example with Lease you have have a "move in date", so a field you would want a field for that. But if we do something like a "Employment agreement", then there is no such thing as a "Move in date", maybe a "start working date".
Would you create a Generic field such as "Start date" which would be applicable in general. Or would it be more wise to create Multiple Layout, and depend on Agreement type field and or layout get show and hidden.
Leave a comment:
-
This is fantastic!! I really appreciate your post and knowledge. I'm going to use this and create this tomorrow. I can't thank you enough!
-Marcus
- Likes 2
Leave a comment:
-
5) Create the custom entry point invoked by the controller in Step 4 above, to retrieve the Lease template id from the database
custom/Espo/Custom/EntryPoints/Lease.php
PHP Code:namespace Espo\Custom\EntryPoints;
use \Espo\Core\Exceptions\NotFound;
use \Espo\Core\Exceptions\Forbidden;
use \Espo\Core\Exceptions\BadRequest;
class Lease extends \Espo\Core\EntryPoints\Base
{
public static $authRequired = true;
// default action
public function run() {
// excecute actions invoked, if none specified throw error
if(empty($_GET['action'])) {
throw new BadRequest();
} else {
$action = $_GET['action'];
}
switch ($action) {
case 'getTemplateIdByTenancy':
if (empty($_GET['tenancyId'])) {
throw new BadRequest();
} else {
$tenancyId = $_GET['tenancyId'];
}
$tenancyObject = $this->getEntityManager()->getRepository('Tenancy')->where(['id'=>$tenancyId,'status'=>'Active'])->findOne();
$templateObject = $this->getEntityManager()->getRepository('Template')->where(['id'=>$tenancyObject->get("templateId")])->findOne();
$templateData['templateId'] = $templateObject->get('id');
echo(json_encode($templateData));
break;
default:
//code to be executed if $action is different from all labels;
}
}
}
6) Create a "Tenant" role and give that role access to "My Lease" (the human friendly name for "Lease") like this:
7) Include the Tab "My Lease" in the Tenant Portal:
8) Clear cache and Rebuild.
Now, when a Tenant clicks on the My Lease menu item, the lease document displays like this, with the esignature panel at the bottom.
Bonus benefit: if a user is accessing the portal from a mobile phone, the document will span the full screen and the esignature panel will have a decent size so it can be easily signed, so this feature is already "mobile" friendly and you can adapt these techniques to implement other mobile centric projects with Espo.
Also, is it possible to get notified once a person does e-sign a document?
We don't use that functionality so I can't provide any code samples but you can check the documentation if you are not familiar with hooks and notifications.Last edited by telecastg; 08-05-2020, 08:21 PM.
Leave a comment:
-
Hi Marcus,
I am thinking of using this as an onboarding tool. As an example, when new agents are looking to get hired we currently send them a document that requires a custom signature. What I'm thinking of doing is creating a document/role-based where I give them access to the CRM via login credentials. Once they login they only see a document where they can agree and sign. Once this is completed I would change their role (in essence, unlock other parts of the CRM), etc.
Thoughts and do you think that would be a good use of this technology?
I think that you could adapt this to your application. This is how we did it:
1) Create a custom "Lease" scope (NOT an entity) so we are able to create a menu option and add it to the navbar:
custom/Espo/Custom/Resources/metadata/scopes/Lease.json
Code:{ "entity": false, "tab": true, "acl": "true", "aclPortal": true, "aclPortalLevelList": [ "all", "account", "contact", "own", "no" ], "disabled": false, "module": "Custom", "isCustom": true }
2) Create or update the language file to make the scope name "human friendly"
custom/Espo/Custom/Resources/i18n/en_US/Global.json
Code:{ "scopeNames": { "Lease": "My Lease" }, "scopeNamesPlural": { "Lease": "My Lease" } }
custom/Espo/Custom/Resources/metadata/clientDefs/Lease.json
Code:{ "controller": "custom:controllers/lease", "color": "#00ff66", "iconClass": "fas fa-file-contract" }
client/custom/src/controllers/lease.js
Code:Espo.define('custom:controllers/lease', 'controllers/base', function (Dep) { return Dep.extend({ leaseScope: "Tenancy", // default action actionIndex: function () { var options = {}; var isPortal = '0'; if(this.getUser().attributes.isPortalUser) { isPortal = '1'; } var self = this; this.viewFactory.create('views/modals/select-records', { scope: 'Tenancy', multiple: false, createButton: false, triggerCreateEvent: false, filters: {}, massRelateEnabled: false, primaryFilterName: '', boolFilterList: [] }, function(dialog) { if(dialog.collection.length > 1) { // this will apply only if the tenant is linked to 2 or more tenancies dialog.render(); Espo.Ui.notify(false); dialog.listenToOnce(dialog, 'select', function (selectObj) { var data = {}; if (Object.prototype.toString.call(selectObj) === '[object Array]') { var ids = []; selectObj.forEach(function (model) { ids.push(model.id); }); data.ids = ids; } else { if (selectObj.massRelate) { data.massRelate = true; data.where = selectObj.where; } else { data.id = selectObj.id; } } options = { entityType: 'Tenancy', entityId: data.id, isPortal: isPortal, templateId: '' }; self.actionRenderLease(options); }, this); } else { options = { entityType: 'Tenancy', entityId: dialog.collection.models[0].attributes.id, isPortal: isPortal, templateId: '' }; self.actionRenderLease(options); } }, this); }, actionRenderLease: function (options) { var entityType = options.entityType; var entityId = options.entityId; var isPortal = options.isPortal; var templateId = ''; var templateName = ''; var self = this; // get the complete lease object this.collectionFactory.create(options.entityType, function (scopeList) { scopeList.fetch().then(function(){ var leaseObject = scopeList.get(entityId); // get the template data var url = '?entryPoint=lease&tenancyId='+entityId+'&action=getTemplateIdByTenancy'; var xmlhttp = new XMLHttpRequest(); xmlhttp.onreadystatechange = function() { if (xmlhttp.readyState === XMLHttpRequest.DONE) { // XMLHttpRequest.DONE == 4 // if the ajax call is successful load the template values into the options object if (xmlhttp.status === 200) { var templateObject = JSON.parse(xmlhttp.responseText); templateId = templateObject.templateId; // build the options object to pass to the view which will render the lease var options = { entityType: entityType, entityId: entityId, templateId: templateId, model: leaseObject, isPortal: isPortal }; // invoke the esignature front end controller esignature-document function "showDocument" that will render the document in full page view self.getRouter().dispatch("EsignatureDocument", 'showDocument', options); } else if (xmlhttp.status === 400) { alert('There was an error 400'); } else { alert('something else other than 200 was returned'); } } }; xmlhttp.open("POST",url , true); xmlhttp.send(); }); }); } }); });
This post is going to exceed the maximum number of characters so it will continue below.Last edited by telecastg; 08-05-2020, 07:47 PM.
- Likes 1
Leave a comment:
Leave a comment: