appmaker - Error With Email Change Notifications Using Project Tracker Template -


short version:

i using code project tracker template send out emails showing change in status field (contact name changed from: billy -> susan).

everything works expect when have field date instead of string. if have date field in code following error:

'string' value expected 'newvalue' field in model 'systemordershistory', found object. error: 'string' value expected 'newvalue' field in model 'systemordershistory', found object. @ onsystemorderssave_ (datasources:218) @ models.systemorders.onsaveevent:1

modifying records: (error) : 'string' value expected 'newvalue' field in model 'systemordershistory', found object.

(error) : 'string' value expected 'newvalue' field in model 'systemordershistory', found object.

any appreciated!


long version

i using code below (adjusted fit names of models , fields).

whenever add date field (ex: deliverydate) function "notifyaboutitemchanges_" function , "onsystemorderssave_" function error "expecting string, found object".

note: oldvalue , newvalue fields in "history" model both strings.

notifications server script:

/**  * sends email.  * @param {!string} - email address of recipient.  * @param {!string} subject - subject of email message.  * @param {!string} body - body of email message.  */ function sendemail_(to, subject, body) {   try {     mailapp.sendemail({       to: to,       subject: subject,       htmlbody: body,       noreply: true     });    } catch (e) {     // suppressing errors in email sending because email notifications     //   not critical functioning of app.     console.error(json.stringify(e));   } }   /**  * sends email notification recent project item changes item owner  *     , assignee.  * @param {!array<itemhistory>} changes - list of recent project item changes.  */ function notifyaboutitemchanges_(changes) {   if (!changes || changes.length < 2) {     return;   }    var settings = getappsettingsrecord_()[0];    if (!settings.enableemailnotifications) {     return;   }    var data = {     appurl: settings.appurl,     itemshowname: changes[0].showname,     itemusersposition: changes[0].usersposition,     itemdeliveryinfo: changes[0].deliveryinfo,     itemdeliverydate: changes[0].deliverydate,     itemkey: changes[0]._key,     itemname: changes[0].name,     modifiedby: changes[0].modifiedby,     changes: changes   };    // email subject.   var subjecttemplate =       htmlservice.createtemplate(settings.notificationemailsubject);    subjecttemplate.data = data;    var subject = subjecttemplate.evaluate().getcontent();    // email body.   var emailtemplate =       htmlservice.createtemplate(settings.notificationemailbody);    emailtemplate.data = data;    var htmlbody = emailtemplate.evaluate().getcontent();    sendemail_('user@gmail.com', subject, htmlbody); 

datasources server script:

/**  * item key url parameter.  */ var item_key = 'itemkey';   /**  * checks application settings record exists.  *     otherwise creates new one.  * @return {!array<appsettings>} app settings record array.  */ function getappsettingsrecord_() {   var newquery = app.models.appsettings.newquery();   var settingsrecords = newquery.run();    if (settingsrecords.length > 1) {     console.warn('there more one(%s) app settings entries' +                   'in database', settingsrecords.length);   }    if (settingsrecords.length === 0) {     var settingsrecord = app.models.appsettings.newrecord();      settingsrecord.appurl = scriptapp.getservice().geturl();     settingsrecord.notificationemailsubject =       'a change has been made <?= data.itemshowname?>: <?= data.itemusersposition?>';      settingsrecord.notificationemailbody =       'hello!\n<br/>\n<p><b><?= data.modifiedby ?></b> ' +       'made following changes: </p>\n' +       '<? (var = 1; < data.changes.length; i++) {\n' +       '\tvar change = data.changes[i]; ?>\n' +       '\t<b><?= change.fieldname ?>: </b>\n' +       '\t<? if (change.fieldname === "comment") { ?>\n' +       '\t\t<div style="white-space: pre-line;"><?= change.newvalue ?></div>' +       '\n\t<? } else { ?>\n ' +       '\t\t<?= change.oldvalue ?> &#8594; <?= change.newvalue ?>' +       '\n\t<? } ?>\n\t<br/>\n' +       '<? } ?>\n<br/>\n' +       '<a href="<?= data.appurl ?>?' + item_key + '=<?= data.itemkey ?>' +       '#edititem" target="_blank">go project item</a>';      app.saverecords([settingsrecord]);      return [settingsrecord];   } else {     return settingsrecords;   } }  /**  * populates project record required data on project create event.  * @param {!project} project - project being created.  */ function onprojectcreate_(project) {   var date = new date();    project.createddate = date;   project.modifieddate = date;   project.modifiedby = currentuseremail_(); }   /**  * audits project on changes.  * @param {!project} project - project being modified.  */ function onprojectsave_(project) {   project.modifieddate = new date();   project.modifiedby = currentuseremail_(); }   /**  * populates project item required data on item create event, adds  *     comment entry project item history.  * @param {!systemorders} systemorders - project item being created.  */ function onsystemorderscreate_(systemorders) {   var date = new date();   var editor = currentuseremail_();    if (systemorders.comment) {     systemorders.comment = systemorders.comment.trim();   }    systemorders.createddate = date;   systemorders.owner = editor;   systemorders.modifieddate = date;   systemorders.modifiedby = editor;    if (systemorders.comment) {     var history = app.models.systemordershistory.newrecord();      history.createdby = currentuseremail_();     history.createddate = new date();     history.fieldname = 'comment';     history.newvalue = systemorders.comment;      app.saverecords([history]);      systemorders.history.push(history);   }  }   /**  * calculates history entries sum {array<systemorders>}.  * @param {!number} historysum - accumulated number of history entries  *     returned in last invocation of callback, or  *     initialvalue, if supplied.  * @param {!systemorders} systemorders - current {systemorders} being  *     processed in array.  * @return {!number} history entries sum.  */ function sumhistory_(historysum, systemorders) {   return historysum + systemorders.history.length; }   /**  * calculates potential project deletion impact.  * throws error if there no project key provided.  * @param {!string} projectkey - project key calculate deletion impact.  */ function getdeleteprojectimpact(projectkey) {   var projectquery = app.models.project.newquery();    projectquery.prefetch.items._add();   projectquery.prefetch.items.history._add();   projectquery.filters._key._equals = projectkey;    var projects = projectquery.run();    if (projects.length === 0) {     throw new error('project key ' + projectkey + ' not found.');   }    var systemorderss = projects[0].items;    return {     affecteditems: systemorderss.length,     affectedhistory: systemorderss.reduce(sumhistory_, 0)   }; }   /**  * checks project item readonly fields not modified.  * throws error if user attempts modify read fields.  * @param {!systemorders} record - modified project item.  * @param {!systemorders} oldrecord - project item before modification.  */ function validateitemchange_(record, oldrecord) {   var readonlyfields = [     'createddate',     'modifiedby',     'modifieddate',     'owner'   ];    (var = 0; < readonlyfields.length; i++) {     var field = readonlyfields[i];     var newvalue = record[field];     var oldvalue = oldrecord[field];     var isdate = newvalue instanceof date && oldvalue instanceof date;      if (isdate === true) {       newvalue = record[field].getdate();       oldvalue = oldrecord[field].getdate();     }      if (newvalue === oldvalue) {       continue;     }      throw new error(field + ' field read only');   } }   /**  * handles project item change event, creates history entries each changed  *     field.  * @param {!systemorders} record - modified project item.  * @param {!systemorders} oldrecord - project item before modification.  */ function onsystemorderssave_(record, oldrecord) {   validateitemchange_(record, oldrecord);    var editablefields = [     'showname',     'usersposition',     'deliveryinfo',     'deliverydate'     ];    var editor = currentuseremail_();   var date = new date();   var changes = [record];    record.modifiedby = editor;   record.modifieddate = date;    (var = 0; < editablefields.length; i++) {     var field = editablefields[i];     var newvalue = record[field];     var oldvalue = oldrecord[field];      if (newvalue !== oldvalue) {       var history = app.models.systemordershistory.newrecord();        history.item = record;       history.createdby = editor;       history.createddate = date;       history.fieldname = field;       history.newvalue = newvalue;       history.oldvalue = oldvalue;        changes.push(history);     }   }    app.saverecords(changes);    notifyaboutitemchanges_(changes); }   /**  * counts project items grouping criteria(field).  * @param {!string} projectkey - project key calculate stats.  * @param {!string} grouping - project item field group items by.  * @param {!array<string>} groupingvalues - possible field values.  * @return {!array<systemorderssbreakdown>} grouped project items counts.  */ function getsystemorderssbreakdown_(projectkey, grouping, groupingvalues) {   if (!grouping || !groupingvalues || groupingvalues.length === 0) {     return [];   }    var itemsquery = app.models.systemorders.newquery();    itemsquery.prefetch.project._add();   itemsquery.filters.project._key._equals = projectkey;    var items = itemsquery.run();    if (items.length === 0) {     return [];   }    var records = [];   var map = {};    (var = 0; < items.length; i++) {     var itemgrouping = items[i][grouping];      if (!map[itemgrouping]) {       map[itemgrouping] = 0;     }      map[itemgrouping]++;   }    (i = 0; < groupingvalues.length; i++) {     var breakdownrecord = app.models.systemorderssbreakdown.newrecord();     var groupingvalue = groupingvalues[i];      breakdownrecord.grouping = groupingvalue;     breakdownrecord.itemscount = map[groupingvalue] || 0;      records.push(breakdownrecord);   }    return records; } 

it fails here:

// history.newvalue , history.oldvalue strings // newvalue , oldvalue can of type (boolean, number, date, // not relation of now) // getting exception because not casting types history.newvalue = newvalue; history.oldvalue = oldvalue; 
  1. you can fix adding fields of each possible type history model (newstringvalue, newdatevalue, newboolvalue, newnumbervalue, oldstringvalue...). approach you'll benefits of strong typing, code , ui become more complex...

  2. you can store fields' history strings(like doing now), in case you'll need think formatting , localization in advance:

function fieldtostring(field, fieldvalue) {   // todo: pass field metadata individually handle   // different data types.   return fieldvalue !== null ? fieldvalue.tostring() : null; }  ... history.newvalue = fieldtostring(field, newvalue); history.oldvalue = fieldtostring(field, oldvalue); ... 

Comments

Popular posts from this blog

node.js - Node js - Trying to send POST request, but it is not loading javascript content -

javascript - Replicate keyboard event with html button -

javascript - Web audio api 5.1 surround example not working in firefox -