Google app maker 使用Project Tracker模板发送电子邮件更改通知时出错
短版: 我正在使用Project Tracker模板中的代码发送电子邮件,显示某个字段状态的更改(联系人姓名从:Billy->Susan更改) 当我有一个字段是日期而不是字符串时,一切都能正常工作。如果代码中有日期字段,则会出现以下错误: 模型“SystemOrdersHistory”中的“NewValue”字段应为“string”值,但找到了对象。错误:“SystemOrdersHistory”模型中的“NewValue”字段应为“string”值,但找到了对象。at onSystemOrdersSave(数据源:218)at models.SystemOrders.onSaveEvent:1 修改记录:(错误):“SystemOrdersHistory”模型中的“NewValue”字段需要“string”值,但找到了对象。 (错误):“SystemOrdersHistory”模型中的“NewValue”字段应为“string”值,但找到了对象。 任何帮助都将不胜感激Google app maker 使用Project Tracker模板发送电子邮件更改通知时出错,google-app-maker,Google App Maker,短版: 我正在使用Project Tracker模板中的代码发送电子邮件,显示某个字段状态的更改(联系人姓名从:Billy->Susan更改) 当我有一个字段是日期而不是字符串时,一切都能正常工作。如果代码中有日期字段,则会出现以下错误: 模型“SystemOrdersHistory”中的“NewValue”字段应为“string”值,但找到了对象。错误:“SystemOrdersHistory”模型中的“NewValue”字段应为“string”值,但找到了对象。at onSystemOrde
长版本 我正在使用下面的代码(根据模型和字段的名称进行调整) 每当我向函数“notifyAboutItemChanges”和“onSystemOrdersSave”添加日期字段(例如:DeliveryDate)时,我都会收到关于“需要字符串,但找到对象”的错误 注意:“历史”模型中的OldValue和NewValue字段都是字符串 通知服务器脚本:
/**
* Sends email.
* @param {!string} to - email address of a 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
// are not critical for the functioning of the app.
console.error(JSON.stringify(e));
}
}
/**
* Sends email notification about recent project item changes to item owner
* and 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);
/**
*发送电子邮件。
*@param{!string}收件人的电子邮件地址。
*@param{!string}subject-电子邮件的主题。
*@param{!string}body-电子邮件正文。
*/
功能发送电子邮件(收件人、主题、正文){
试一试{
MailApp.sendmail({
致:致,,
主题:主题,,
htmlBody:body,
诺雷普利:是的
});
}捕获(e){
//抑制电子邮件发送中的错误,因为电子邮件通知
//对于应用程序的功能来说并不重要。
console.error(JSON.stringify(e));
}
}
/**
*向项目所有者发送有关最近项目项更改的电子邮件通知
*和受让人。
*@param{!Array}更改-最近项目项更改的列表。
*/
函数notifyAboutItemChanges(更改){
如果(!changes | | changes.length<2){
返回;
}
var settings=getAppSettingsRecord([0];
如果(!settings.enableMailNotifications){
返回;
}
风险值数据={
appUrl:settings.appUrl,
itemShowName:更改[0]。ShowName,
itemUsersPosition:更改[0]。UsersPosition,
itemDeliveryInfo:更改[0]。DeliveryInfo,
itemDeliveryDate:更改[0]。DeliveryDate,
itemKey:更改[0]。\u键,
itemName:更改[0]。名称,
modifiedBy:更改[0]。modifiedBy,
变化:变化
};
//电子邮件主题。
var主题模板=
HtmlService.createTemplate(settings.NotificationEmailSubject);
subjectTemplate.data=数据;
var subject=subjectTemplate.evaluate().getContent();
//电子邮件正文。
var电子邮件模板=
HtmlService.createTemplate(settings.NotificationEmailBody);
emailTemplate.data=数据;
var htmlBody=emailTemplate.evaluate().getContent();
发送电子邮件user@gmail.com,主题,正文);
数据源服务器脚本:
/**
* Item key URL parameter.
*/
var ITEM_KEY = 'itemKey';
/**
* Checks that Application Settings record already exists.
* Otherwise creates a new one.
* @return {!Array<AppSettings>} app settings record as an array.
*/
function getAppSettingsRecord_() {
var newQuery = app.models.AppSettings.newQuery();
var settingsRecords = newQuery.run();
if (settingsRecords.length > 1) {
console.warn('There is more than one(%s) App Settings entries' +
'in the 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 to <?= data.itemShowName?>: <?= data.itemUsersPosition?>';
settingsRecord.NotificationEmailBody =
'Hello!\n<br/>\n<p><b><?= data.modifiedBy ?></b> ' +
'made the following changes: </p>\n' +
'<? for (var i = 1; i < 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 ?> → <?= change.NewValue ?>' +
'\n\t<? } ?>\n\t<br/>\n' +
'<? } ?>\n<br/>\n' +
'<a href="<?= data.appUrl ?>?' + ITEM_KEY + '=<?= data.itemKey ?>' +
'#EditItem" target="_blank">Go to the project item</a>';
app.saveRecords([settingsRecord]);
return [settingsRecord];
} else {
return settingsRecords;
}
}
/**
* Populates project record with 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 with required data on item create event, adds
* comment entry to the 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 for {Array<SystemOrders>}.
* @param {!number} historySum - the accumulated number of history entries
* previously returned in the last invocation of the callback, or
* initialValue, if supplied.
* @param {!SystemOrders} SystemOrders - the current {SystemOrders} being
* processed in the array.
* @return {!number} history entries sum.
*/
function sumHistory_(historySum, SystemOrders) {
return historySum + SystemOrders.History.length;
}
/**
* Calculates potential project deletion impact.
* Throws an error if there is no project with the key provided.
* @param {!string} projectKey - project key to 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 with key ' + projectKey + ' was not found.');
}
var SystemOrderss = projects[0].Items;
return {
affectedItems: SystemOrderss.length,
affectedHistory: SystemOrderss.reduce(sumHistory_, 0)
};
}
/**
* Checks that project item readonly fields were not modified.
* Throws an error if user attempts to modify read only fields.
* @param {!SystemOrders} record - modified project item.
* @param {!SystemOrders} oldRecord - project item before modification.
*/
function validateItemChange_(record, oldRecord) {
var readonlyFields = [
'CreatedDate',
'ModifiedBy',
'ModifiedDate',
'Owner'
];
for (var i = 0; i < 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 is read only');
}
}
/**
* Handles project item change event, creates history entries for 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;
for (var i = 0; i < 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 by some grouping criteria(field).
* @param {!string} projectKey - project key to calculate stats.
* @param {!string} grouping - project item field to 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 = {};
for (var i = 0; i < items.length; i++) {
var itemGrouping = items[i][grouping];
if (!map[itemGrouping]) {
map[itemGrouping] = 0;
}
map[itemGrouping]++;
}
for (i = 0; i < 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;
}
/**
*项目键URL参数。
*/
var ITEM_KEY='itemKey';
/**
*检查应用程序设置记录是否已存在。
*否则将创建一个新的。
*@return{!Array';
应用程序保存记录([settingsRecord]);
返回[设置记录];
}否则{
返回设置记录;
}
}
/**
*使用项目创建事件上的必需数据填充项目记录。
*@param{!Project}Project-正在创建项目。
*/
函数onProjectCreate(项目){
变量日期=新日期();
project.CreatedDate=日期;
project.ModifiedDate=日期;
project.ModifiedBy=currentUserEmail_u2;();
}
/**
*审核项目变更。
*@param{!Project}Project-正在修改项目。
*/
函数onProjectSave(项目){
project.ModifiedDate=新日期();
project.ModifiedBy=currentUserEmail_u2;();
}
/**
*在项目创建事件中使用所需数据填充项目项目,添加
*项目项历史记录的注释条目。
*@param{!SystemOrders}SystemOrders-正在创建项目项。
*/
函数onSystemOrdersCreate(系统订单){
变量日期=新日期();
var editor=currentUserEmail_();
if(SystemOrders.Comment){
SystemOrders.Comment=SystemOrders.Comment.trim();
}
SystemOrders.CreatedDate=日期;
SystemOrders.Owner=editor;
SystemOrders.ModifiedDate=日期;
SystemOrders.ModifiedBy=编辑器;
if(SystemOrders.Comment){
var history=app.models.SystemOrdersHistory.newRecord();
history.CreatedBy=currentUserEmail_u2;();
history.CreatedDate=新日期();
history.FieldName='Comment';
history.NewValue=SystemOrders.Comment;
应用程序保存记录([历史]);
SystemOrders.History.push(历史);
}
}
/**
*计算{Array}的历史记录项总和。
*@param{!number}historySum-历史记录条目的累积数量
*以前在最后一次调用回调时返回的,或
*初始值(如果提供)。
*@param{!SystemOrders}SystemOrders-当前{SystemOrders}为
*在数组中处理。
*@return{!number}历史记录项总和。
*/
函数sumHistory(历史总和,系统订单){
返回historySum+SystemOrders.History.length;
}
/**
*计算潜在的项目删除影响。
*如果没有提供密钥的项目,则引发错误。
*@param{!string}projectKey-用于计算删除影响的项目密钥。
*/
函数getDeleteProjectImpact(projectKey){
var projectQuery=app.models.Project.newQuery();
projectQuery.prefetch.Items._add();
projectQuery.prefetch.Items.History._add();
projectQuery.filters.\u key.\u=projectKey;
var projects=projectQuery.run();
如果(projects.length==0){
抛出新错误('Project with key'+projectKe