3
0

Add service-cloud configs

Change file naming for CRM configs so it can go side-to-side with
service-cloud.
This commit is contained in:
Denis Arh 2019-10-24 10:48:58 +02:00
parent 876f3a7ed0
commit 4cf522ddab
14 changed files with 4805 additions and 3 deletions

View File

@ -0,0 +1,3 @@
namespaces:
service-cloud:
name: Service Cloud

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,361 @@
namespace: service-cloud
charts:
ActiveEntitlements:
name: Number of active entitlements
config:
reports:
- dimensions:
- conditions: {}
field: Status
modifier: (no grouping / buckets)
filter: ""
metrics:
- backgroundColor: '#11ff57'
field: count
fixTooltips: true
type: pie
module: Entitlement
AverageTimeSpentPerCase:
name: Average time spent per case
config:
reports:
- dimensions:
- conditions: {}
field: created_at
modifier: MONTH
filter: ""
metrics:
- aggregate: AVG
backgroundColor: '#ff9937'
beginAtZero: true
field: TotalTime
fixTooltips: false
label: Average case time (in hours)
type: bar
module: Case
CaseUpdatesPerType:
name: Case updates per type
config:
reports:
- dimensions:
- conditions: {}
field: Type
modifier: (no grouping / buckets)
filter: ""
metrics:
- backgroundColor: '#b51392'
field: count
fixTooltips: true
relativeValue: true
type: doughnut
module: Update
CasesByCategory:
name: Cases by category
config:
reports:
- dimensions:
- conditions: {}
field: Category
modifier: (no grouping / buckets)
skipMissing: true
filter: ""
metrics:
- backgroundColor: '#ff0074'
field: count
fixTooltips: true
label: Category
relativePrecision: "2"
relativeValue: true
type: doughnut
module: Case
CasesByPriority:
name: Cases by priority
config:
reports:
- dimensions:
- conditions: {}
field: Priority
modifier: (no grouping / buckets)
filter: ""
metrics:
- backgroundColor: '#f50d23'
field: count
fixTooltips: true
label: Priority
relativeValue: true
type: doughnut
module: Case
CasesByStatus:
name: Cases by status
config:
reports:
- dimensions:
- conditions: {}
field: Status
modifier: (no grouping / buckets)
filter: ""
metrics:
- backgroundColor: '#13b1dc'
field: count
fixTooltips: true
label: Cases by status
relativeValue: true
type: doughnut
module: Case
ClosedCasesPerMonth:
name: Closed cases per month
config:
reports:
- dimensions:
- conditions: {}
field: CloseDate
modifier: MONTH
skipMissing: true
filter: ""
metrics:
- backgroundColor: '#4ec811'
beginAtZero: true
field: count
fill: true
fixTooltips: false
label: Closed cases
type: line
module: Case
CostPerCategory:
name: Total costs per category
config:
reports:
- dimensions:
- conditions: {}
field: Category
modifier: (no grouping / buckets)
skipMissing: false
filter: ""
metrics:
- aggregate: SUM
axisType: null
backgroundColor: '#ffac45'
field: TotalCost
fixTooltips: true
label: Cost per category (in $)
relativeValue: false
type: bar
module: Case
CostPerProductFamily:
name: Total costs per product family
config:
reports:
- dimensions:
- conditions: {}
field: Family
modifier: (no grouping / buckets)
filter: ""
metrics:
- aggregate: SUM
axisType: null
backgroundColor: '#03ad3b'
beginAtZero: true
field: TotalCost
fixTooltips: true
label: Total (in $)
relativeValue: false
type: bar
module: Product
CostsPerAccount:
name: Total costs per account
config:
reports:
- dimensions:
- conditions: {}
field: AccountSelect
modifier: (no grouping / buckets)
filter: ""
metrics:
- aggregate: SUM
backgroundColor: '#6dc6fb'
field: TotalCost
fixTooltips: true
label: Total cost ($)
type: bar
module: Account
KnowledgeBaseArticlesPerType:
name: Knowledge Base articles per type
config:
reports:
- dimensions:
- conditions: {}
field: Category
modifier: (no grouping / buckets)
filter: ""
metrics:
- backgroundColor: '#ffc623'
field: count
fixTooltips: true
label: Knowledge Base articles per type
relativeValue: false
type: pie
module: KnowledgeBase
KnowledgeBaseItemsCreatedPerDay:
name: Knowledge Base items created per day
config:
reports:
- dimensions:
- conditions: {}
field: created_at
modifier: DATE
filter: ""
metrics:
- backgroundColor: '#ffc623'
beginAtZero: true
field: count
fill: false
label: Total (per day)
type: line
module: KnowledgeBase
NewCasesByMonth:
name: New cases per month
config:
reports:
- dimensions:
- autoSkip: true
conditions: {}
field: created_at
modifier: MONTH
skipMissing: true
filter: ""
metrics:
- backgroundColor: '#3baef0'
beginAtZero: true
field: count
fill: true
fixTooltips: false
label: New cases
type: line
module: Case
TimePerAccount:
name: Total time spent per account
config:
reports:
- dimensions:
- conditions: {}
field: AccountSelect
modifier: (no grouping / buckets)
filter: ""
metrics:
- aggregate: SUM
backgroundColor: '#41aeee'
field: TotalTime
fixTooltips: true
label: Hours
type: pie
module: Account
TimeSpentPerProductFamily:
name: Total time Spent per product family
config:
reports:
- dimensions:
- conditions: {}
field: Family
modifier: (no grouping / buckets)
filter: ""
metrics:
- aggregate: SUM
axisType: null
backgroundColor: '#03ad3b'
beginAtZero: true
field: TotalTime
fixTooltips: true
label: Time spent (in hours)
relativeValue: false
type: pie
module: Product
TotalCostPerDepartment:
name: Total costs per department
config:
reports:
- dimensions:
- conditions: {}
field: DepartmentSelect
modifier: (no grouping / buckets)
skipMissing: true
filter: ""
metrics:
- aggregate: SUM
backgroundColor: '#bf94ff'
beginAtZero: true
field: TotalCost
fixTooltips: true
label: Total (in $)
type: bar
module: Department
TotalCostPerMonth:
name: Total costs per month
config:
reports:
- dimensions:
- conditions: {}
field: created_at
modifier: MONTH
filter: ""
metrics:
- aggregate: SUM
backgroundColor: '#189d00'
beginAtZero: true
field: Cost
label: Total cost per month (in $)
type: bar
module: Update
TotalTimeSpentPerCategory:
name: Total time spent per category
config:
reports:
- dimensions:
- conditions: {}
field: Category
modifier: (no grouping / buckets)
skipMissing: true
filter: ""
metrics:
- aggregate: SUM
backgroundColor: '#ffac45'
field: TotalTime
fixTooltips: true
label: Total time spent per category (in hours)
type: pie
module: Case
TotalTimeSpentPerDepartment:
name: Total time spent per department
config:
reports:
- dimensions:
- conditions: {}
field: DepartmentSelect
modifier: (no grouping / buckets)
skipMissing: true
filter: ""
metrics:
- aggregate: SUM
backgroundColor: '#bf94ff'
field: TotalTime
fixTooltips: true
label: Total
type: pie
module: Department
TotalTimeSpentPerMonth:
name: Total time spent per month
config:
reports:
- dimensions:
- conditions: {}
field: created_at
modifier: MONTH
filter: ""
metrics:
- aggregate: SUM
backgroundColor: '#0d83e4'
beginAtZero: true
field: TimeSpend
fixTooltips: false
label: Total time spent (in hours)
type: bar
module: Update

View File

@ -0,0 +1,983 @@
namespace: service-cloud
scripts:
AccountSetValues:
source: |-
$record.values.AccountSelect = $record.values.AccountName
async: false
runInUA: false
critical: true
enabled: true
timeout: 0
triggers:
- event: beforeCreate
module: Account
resource: compose:record
- event: beforeUpdate
module: Account
resource: compose:record
CaseAddUpdate:
source: |-
const { toJSON, ...values } = $record.values
$record = new Record($record.module, { ...$record, values })
//Get the default settings
return Compose.findLastRecord('Settings').then(settings => {
let department = settings.values.DefaultDepartment
let timeSpend = settings.values.DefaultTimeUpdate
let defaultCostPerHour = settings.values.DefaultCostPerHour
let updateCost = 0
if (timeSpend) {
updateCost = parseFloat(defaultCostPerHour) * parseFloat(timeSpend)
}
// Create the related update
return Compose.makeRecord({
'CaseId': $record.recordID,
'AccountId': $record.values.AccountId,
'ContactId': $record.values.ContactId,
'Department': settings.values.DefaultDepartment,
'Cost': updateCost,
'TimeSpend': timeSpend
}, 'Update')
.then(myUpdate => {
return Compose.saveRecord(myUpdate)
}).then(mySavedUpdate => {
ComposeUI.gotoRecordEditor(mySavedUpdate)
}).catch(err => {
// solve the problem
console.error(err)
})
}).catch(err => {
// solve the problem
console.error(err)
})
async: false
runInUA: true
critical: true
enabled: true
timeout: 0
triggers:
- event: manual
module: Case
resource: compose:record
CaseInsertCaseNumber:
source: |-
let d = new Date()
let y = d.getFullYear()
let m = d.getMonth() + 1
if (m < 10) {
m = '0' + m
}
let day = d.getDate()
if (day < 10) {
day = '0' + day
}
let h = d.getHours()
if (h < 10) {
h = '0' + h
}
let min = d.getMinutes()
if (min < 10) {
min = '0' + min
}
let sec = d.getSeconds()
if (sec < 10) {
sec = '0' + sec
}
let mil = d.getMilliseconds()
if (mil < 10) {
mil = '00' + mil
} else if (mil < 100) {
mil = '0' + mil
}
let caseNumber = 'Ticket#' + y + m + day + h + min + sec + mil
$record.values.Number = caseNumber
$record.values.Status = 'New'
$record.values.PreviousStatus = 'New'
async: false
runInUA: false
critical: true
enabled: true
timeout: 0
triggers:
- event: beforeCreate
module: Case
resource: compose:record
- enabled: false
event: beforeUpdate
module: Case
resource: compose:record
CaseSendEmail:
source: |-
const { toJSON, ...values } = $record.values
$record = new Record($record.module, { ...$record, values })
function procTemplate(tpl, pairs = {}) {
return tpl.replace(/{{\s*(.+?)\s*}}/g, (match) => {
// remove {{, }} and extra spaces
const token = match.substr(2, match.length - 4).trim().split('.', 2)
// return the placeholder if we do not find the value
const miss = '{{' + token.join('.') + '}}'
if (token.length === 1) {
// handle simpe key-value pairs
return pairs[token] || miss
} else {
// handle complex key-key-value (ie: modulename: recordvalues)
const [key, field] = token
return pairs[key] && pairs[key][field] ? pairs[key][field] : miss
}
})
}
// Get the default template from the settings.
return Compose.findLastRecord('Settings').then(settings => {
let templateId = settings.values.DefaultCaseEmailTemplate
if (templateId) {
// Get the template
Compose.findRecordByID(templateId, 'EmailTemplate').then(templateRecord => {
let subject = templateRecord.values.Subject
let body = templateRecord.values.Body
subject = procTemplate(subject, { "Case": $record.values })
body = procTemplate(body, { "Case": $record.values })
// Find the contact (there will always be a contact)
Compose.findRecordByID($record.values.ContactId, 'Contact').then(contactRecord => {
subject = procTemplate(subject, { "Contact": contactRecord.values })
body = procTemplate(body, { "Contact": contactRecord.values })
return
}).then(() => {
// Create the email
return Compose.makeRecord({
'HtmlBody': body,
'Subject': subject,
'Status': 'Draft',
'EmailTemplateId': templateId,
'CaseId': $record.recordID,
'ContactId': $record.values.ContactId
}, 'EmailMessage')
.then(myEmailMessage => {
return Compose.saveRecord(myEmailMessage)
}).then(mySavedEmailMessage => {
// Redirect to the email record
ComposeUI.gotoRecordEditor(mySavedEmailMessage)
}).catch(err => {
// solve the problem
console.error(err)
})
}).catch(err => {
// solve the problem
console.error(err)
})
}).catch(err => {
// solve the problem
console.error(err)
})
}
}).catch(err => {
// solve the problem
console.error(err)
})
async: false
runInUA: true
critical: true
enabled: true
timeout: 0
triggers:
- event: manual
module: Case
resource: compose:record
CaseStatusChange:
source: |-
// Get the current status of the case
let currentStatus = $record.values.Status
let previousStatus = $record.values.PreviousStatus
// Check if there is no status. If so, the case is new and set it as new.
if (!currentStatus) {
currentStatus = 'New'
}
if (!previousStatus) {
previousStatus = 'None'
}
// Check if we need to insert a status change update
if (currentStatus != previousStatus) {
// Insert the status update
// First, get the default settings
return Compose.findLastRecord('Settings').then(settings => {
let defaultTimeSpend = settings.values.DefaultTimeUpdate
let defaultCost = settings.values.DefaultCostPerHour
let defaultDepartment = settings.values.DefaultDepartment
// Get the record from the department
return Compose.findRecordByID(defaultDepartment, 'Department').then(departmentRecord => {
// Get the cost associated to the department
if (departmentRecord.values.HourCost) {
defaultCost = departmentRecord.values.HourCost
}
return departmentRecord
}).then(departmentRecord => {
// calculat the total cost
let totalCost = parseFloat(defaultCost) * parseFloat(defaultTimeSpend)
// Make the update record
return Compose.makeRecord({
'CaseId': $record.recordID,
'Type': 'Status change',
'Subject': 'Status changed from ' + previousStatus + ' to ' + currentStatus,
'AccountId': $record.values.AccountId,
'From': 'Automatic message',
'Department': defaultDepartment,
'TimeSpend': defaultTimeSpend,
'Cost': totalCost
}, 'Update')
.then(myUpdate => {
return Compose.saveRecord(myUpdate)
}).catch(err => {
// solve the problem
console.error(err)
})
}).then(departmentRecord => {
// Calculate and store the total price of the ticket
let totalCost = $record.values.TotalCost
if (!totalCost || totalCost === '' || isNaN(totalCost)) {
totalCost = 0
}
let totalTime = $record.values.TotalTime
if (!totalTime || totalTime === '' || isNaN(totalTime)) {
totalTime = 0
}
// Update the total time and cost in the ticket
$record.values.TotalCost = parseFloat(totalCost) + (parseFloat(defaultCost) * parseFloat(defaultTimeSpend))
$record.values.TotalTime = parseFloat(totalTime) + parseFloat(defaultTimeSpend)
// Store the new state in the previous state field
$record.values.PreviousStatus = currentStatus
return
}).catch(err => {
// solve the problem
console.error(err)
})
}).catch(err => {
// solve the problem
console.error(err)
})
}
async: false
runInUA: false
critical: true
enabled: true
timeout: 0
triggers:
- event: beforeUpdate
module: Case
resource: compose:record
ContactSetRecordLabel:
source: |-
// Set the record label string
let recordLabel = ''
// Get the first name
let firstName = $record.values.FirstName
if (!firstName) {
firstName = ''
}
// Get the last name
let lastName = $record.values.LastName
if (!lastName) {
lastName = ''
}
// Create the full name
let fullName = ''
if ((firstName !== '') && (lastName === '')) {
recordLabel = firstName
}
if ((firstName === '') && (lastName !== '')) {
recordLabel = lastName
}
if ((firstName !== '') && (lastName !== '')) {
recordLabel = firstName + ' ' + lastName
}
// Get the company name from the account
// Check if there is a related account, to map the fields of the account
let accountId = $record.values.AccountId
if (accountId) {
return Compose.findRecordByID(accountId, 'Account').then(accountRecord => {
// Add to the record label
recordLabel = recordLabel + ' (' + accountRecord.values.AccountName + ')'
$record.values.RecordLabel = recordLabel
}).catch(err => {
// solve the problem
$record.values.RecordLabel = recordLabel
console.error(err)
})
}
async: false
runInUA: false
critical: true
enabled: true
timeout: 0
triggers:
- event: beforeCreate
module: Contact
resource: compose:record
- event: beforeUpdate
module: Contact
resource: compose:record
DepartmentSetValues:
source: |-
$record.values.DepartmentSelect = $record.values.Name
async: false
runInUA: false
critical: true
enabled: true
timeout: 0
triggers:
- event: beforeCreate
module: Department
resource: compose:record
- event: beforeUpdate
module: Department
resource: compose:record
EmailSend:
source: |-
const { toJSON, ...values } = $record.values
$record = new Record($record.module, { ...$record, values })
Compose.findRecordByID($record.values.ContactId, 'Contact').then(contactRecord => {
return Compose.sendMail(contactRecord.values.Email, $record.values.Subject, { html: $record.values.HtmlBody }).then(() => {
ComposeUI.success(`The email "${$record.values.Subject}" has been sent to "${contactRecord.values.RecordLabel}: ${contactRecord.values.Email}".`)
$record.values.Status = "Sent"
$record.values.ToAddress = contactRecord.values.Email
var m = new Date()
var dateString = m.getUTCFullYear() + "/" + (m.getUTCMonth() + 1) + "/" + m.getUTCDate() + " " + m.getUTCHours() + ":" + m.getUTCMinutes() + ":" + m.getUTCSeconds()
$record.values.MessageDate = dateString
Compose.saveRecord($record).then(mySavedRecord => {
ComposeUI.gotoRecordViewer(mySavedRecord)
return
}).then(mySavedRecord => {
// Add the email as an update
if ($record.values.CaseId) {
// First, get the default settings
return Compose.findLastRecord('Settings').then(settings => {
let defaultTimeSpend = settings.values.DefaultTimeUpdate
let defaultCost = settings.values.DefaultCostPerHour
let defaultDepartment = settings.values.DefaultDepartment
// Get the record from the department
return Compose.findRecordByID(defaultDepartment, 'Department').then(departmentRecord => {
// Get the cost associated to the department
if (departmentRecord.values.HourCost) {
defaultCost = departmentRecord.values.HourCost
}
return departmentRecord
}).then(departmentRecord => {
// calculat the total cost
let totalCost = parseFloat(defaultCost) * parseFloat(defaultTimeSpend)
// Make the update record
return Compose.makeRecord({
'CaseId': $record.values.CaseId,
'Type': 'Outgoing email',
'Subject': 'Email: ' + $record.values.Subject,
'ContactId': $record.values.ContactId,
'From': 'Service Cloud',
'To': contactRecord.values.Email,
'Content': $record.values.HtmlBody,
'Department': defaultDepartment,
'TimeSpend': defaultTimeSpend,
'Cost': totalCost
}, 'Update')
.then(myUpdate => {
return Compose.saveRecord(myUpdate)
}).catch(err => {
// solve the problem
console.error(err)
})
}).catch(err => {
// solve the problem
console.error(err)
})
}).catch(err => {
// solve the problem
console.error(err)
})
}
}).catch(err => {
// solve the problem
console.error(err)
})
}).catch(err => {
// solve the problem
console.error(err)
})
}).catch(err => {
// solve the problem
console.error(err)
})
async: false
runInUA: true
critical: true
enabled: true
timeout: 0
triggers:
- event: manual
module: EmailMessage
resource: compose:record
EmailTemplateLoad:
source: |-
const { toJSON, ...values } = $record.values
$record = new Record($record.module, { ...$record, values })
function procTemplate(tpl, pairs = {}) {
return tpl.replace(/{{\s*(.+?)\s*}}/g, (match) => {
// remove {{, }} and extra spaces
const token = match.substr(2,match.length-4).trim().split('.', 2)
// return the placeholder if we do not find the value
const miss = '{{' + token.join('.') + '}}'
if (token.length === 1) {
// handle simpe key-value pairs
return pairs[token] || miss
} else {
// handle complex key-key-value (ie: modulename: recordvalues)
const [key, field] = token
return pairs[key] && pairs[key][field] ? pairs[key][field] : miss
}
})
}
if (!$record.recordID) {
ComposeUI.success(`Please save the record before loading the template`)
return
}
// Check if there is a template
let templateId = $record.values.EmailTemplateId
if (templateId) {
// Get the template
Compose.findRecordByID(templateId, 'EmailTemplate').then(templateRecord => {
let subject = templateRecord.values.Subject
let body = templateRecord.values.Body
// Find the contact (there will always be a contact)
Compose.findRecordByID($record.values.ContactId, 'Contact').then(contactRecord => {
subject = procTemplate(subject, {"Contact": contactRecord.values})
body = procTemplate(body, {"Contact": contactRecord.values})
return
}).then(() => {
// Get all the possible placeholders for the case, if there is a case selected
if ($record.values.CaseId) {
return Compose.findRecordByID($record.values.CaseId, 'Case').then(caseRecord => {
subject = procTemplate(subject, {"Case": caseRecord.values})
body = procTemplate(body, {"Case": caseRecord.values})
}).catch(err => {
// solve the problem
console.error(err)
})
}
}).then(() => {
$record.values.Subject = subject
$record.values.HtmlBody = body
//Save the record
return Compose.saveRecord($record)
.then(mySavedRecord => {
ComposeUI.success(`The template has been loaded in to the email.`)
ComposeUI.gotoRecordEditor(mySavedRecord)
}).catch(err => {
// solve the problem
ComposeUI.warning(`The template could not be loaded.`)
console.error(err)
})
}).catch(err => {
// solve the problem
console.error(err)
})
}).catch(err => {
// solve the problem
console.error(err)
})
}
async: false
runInUA: true
critical: true
enabled: true
timeout: 0
triggers:
- event: manual
module: EmailMessage
resource: compose:record
KnowledgeBaseInsertKBNumber:
source: |-
//Get the default settings
return Compose.findLastRecord('Settings').then(settings => {
// Map the case number
let KBNextNumber = settings.values.KBNextNumber
if (typeof KBNextNumber == "undefined" || KBNextNumber === '' || isNaN(KBNextNumber)) {
KBNextNumber = 0
}
console.log(KBNextNumber)
$record.values.Number = KBNextNumber
let KBNextNumberUpdated = parseInt(KBNextNumber,10) + 1
// Update the config
settings.values.KBNextNumber = KBNextNumberUpdated
return Compose.saveRecord(settings).then(mySavedSettings => {
console.log('Record saved, new ID', mySavedSettings.recordID)
}).catch(err => {
// solve the problem
console.error(err)
})
}).catch(err => {
// solve the problem
console.error(err)
})
async: false
runInUA: false
critical: true
enabled: true
timeout: 0
triggers:
- enabled: false
event: beforeUpdate
module: KnowledgeBase
resource: compose:record
- event: beforeCreate
module: KnowledgeBase
resource: compose:record
UpdateSendNotificationsAndCalculateTimeAndCost:
source: |-
// Check if the type is NOT an incoming email. If it's not, handle it as an internal update and send notifications
if ($record.values.Type !== 'Incoming email') {
//Get the cost related to the department that updated the case
return Compose.findRecordByID($record.values.Department, 'Department').then(departmentRecord => {
let hourCost = 0
if (departmentRecord.values.HourCost) {
hourCost = parseFloat(departmentRecord.values.HourCost)
}
return hourCost
}).catch(err => {
// solve the problem
let hourCost = 0
return hourCost
})
.then((hourCost) => {
// Calculate the cost of the update
let updateTime = $record.values.TimeSpend
let UpdateCost = 0
if (updateTime) {
UpdateCost = parseFloat(hourCost) * parseFloat(updateTime)
}
// Add the cost to the update
$record.values.Cost = UpdateCost
// Set the notifications values to "1" (sent)
if ($record.values.SendToMailingList) {
$record.values.NotificationCaseMailingList = 1
}
$record.values.NotificationCaseCreator = 1
// Find the related case
Compose.findRecordByID($record.values.CaseId, 'Case').then(caseRecord => {
// Create the update text to send out via email.
// Only when the Update record has a subject or type.
if (($record.values.Subject) || ($record.values.Type)) {
let html = 'Hi,'
html += '<br>'
html += '<br>'
html += 'The following case has been updated:'
html += '<br>'
html += '<ul>'
html += '<li><strong>Case ID:</strong> ' + caseRecord.values.Number + '</li>'
html += '<li><strong>Subject:</strong> ' + caseRecord.values.Subject + '</li>'
html += '<li><strong>Type:</strong> ' + caseRecord.values.Category + '</li>'
html += '<li><strong>Status:</strong> ' + caseRecord.values.Status + '</li>'
html += '<li><strong>Priority:</strong> ' + caseRecord.values.Priority + '</li>'
html += '</ul>'
html += '<br>'
html += 'Update:'
html += '<br>'
html += '<ul>'
html += '<li><strong>Type:</strong> ' + $record.values.Type + '</li>'
html += '<li><strong>Subject:</strong> ' + $record.values.Subject + '</li>'
html += '<li><strong>Content:</strong> ' + $record.values.Content + '</li>'
html += '</ul>'
html += '<br>'
html += 'Kind regards,'
html += '<br>'
html += '<br>'
html += 'Service Cloud'
html += '<br>'
html += '<br>'
html += '--'
html += '<br>'
html += 'Ticket Summary:'
html += '<hr>'
html += caseRecord.values.Description
return Compose.findLastRecord('Settings').then(settings => {
let defaultChannel = settings.values.DefaultSupportChannel
let defaultCaseRecordLink = settings.values.DefaultCaseRecordLink
// Get default settings to find if there is a channel to inform
if (defaultChannel && defaultCaseRecordLink) {
return Messaging.sendMessage('Automatic update. "' + caseRecord.values.Number + '" has been updated: ' + $record.values.Subject + ' (type: ' + $record.values.Type + '). Direct link: ' + defaultCaseRecordLink + $record.recordID, defaultChannel)
}
}).then(() => {
// Get the contact of the case record to infor via email
if (caseRecord.values.ContactId) {
Compose.findRecordByID(caseRecord.values.ContactId, 'Contact').then(contactRecord => {
// Check if the contact has an email address
if (contactRecord.values.Email) {
// Send the update text
return Compose.sendMail(contactRecord.values.Email, '[' + caseRecord.values.Number + '] Update: ' + caseRecord.values.Subject, { html: html })
}
}).catch(err => {
// solve the problem
console.error(err)
})
}
}).catch(err => {
// solve the problem
console.error(err)
})
}
}).catch(err => {
// solve the problem
console.error(err)
})
}).catch(err => {
// solve the problem
console.error(err)
})
}
async: false
runInUA: false
critical: true
enabled: true
timeout: 0
triggers:
- event: beforeUpdate
module: Update
resource: compose:record
UpdateSetCaseTimeAndCost:
source: |-
// Find the related case
Compose.findRecordByID($record.values.CaseId, 'Case').then(caseRecord => {
// Find all updates in the case
return Compose.findRecords(`CaseId = ${$record.values.CaseId}`, 'Update')
.then(({ set, filter }) => {
// Start the time and cost with the values of the current update, because the update
// is not saved until after the complete script has run
let caseTime = 0
let caseCost = 0
// Loop through the updates of the case, to sum the totals
set.forEach(r => {
// Get the time
let caseUpdateTime = r.values.TimeSpend
if (typeof caseUpdateTime == "undefined" || caseUpdateTime === '' || isNaN(caseUpdateTime)) {
caseUpdateTime = 0
}
caseTime = parseFloat(caseTime) + parseFloat(caseUpdateTime)
// Get the cost
let caseUpdateCost = r.values.Cost
if (typeof caseUpdateCost == "undefined" || caseUpdateCost === '' || isNaN(caseUpdateCost)) {
caseUpdateCost = 0
}
caseCost = parseFloat(caseCost) + parseFloat(caseUpdateCost)
})
// Set the values in the case
caseRecord.values.TotalTime = caseTime
caseRecord.values.TotalCost = caseCost
// Save the case
return Compose.saveRecord(caseRecord).then(mySavedCase => {
console.log('Record saved, ID', mySavedCase.recordID)
}).then(mySavedCase => {
// After saving the case, update the total for the account
// Find the related case
if (caseRecord.values.AccountId) {
Compose.findRecordByID(caseRecord.values.AccountId, 'Account').then(accountRecord => {
// Find all updates in the case
return Compose.findRecords(`AccountId = ${accountRecord.recordID}`, 'Case')
.then(({ set, filter }) => {
// Start the time and cost with the values of the current update, because the update
// is not saved until after the complete script has run
caseTime = 0
caseCost = 0
// Loop through the updates of the case, to sum the totals
set.forEach(r => {
// Get the time
let caseUpdateTime = r.values.TotalTime
if (typeof caseUpdateTime == "undefined" || caseUpdateTime === '' || isNaN(caseUpdateTime)) {
caseUpdateTime = 0
}
caseTime = parseFloat(caseTime) + parseFloat(caseUpdateTime)
// Get the cost
let caseUpdateCost = r.values.TotalCost
if (typeof caseUpdateCost == "undefined" || caseUpdateCost === '' || isNaN(caseUpdateCost)) {
caseUpdateCost = 0
}
caseCost = parseFloat(caseCost) + parseFloat(caseUpdateCost)
})
// Set the values in the case
accountRecord.values.TotalTime = caseTime
accountRecord.values.TotalCost = caseCost
// Save the case
return Compose.saveRecord(accountRecord).then(mySavedAccount => {
console.log('Record saved, ID', mySavedAccount.recordID)
}).catch(err => {
// solve the problem
console.error(err)
})
}).catch(err => {
// solve the problem
console.error(err)
})
}).catch(err => {
// solve the problem
console.error(err)
})
}
// Add the totals for the related product
}).then(mySavedCase => {
// After saving the case, update the total for the account
// Find the related case
if (caseRecord.values.ProductId) {
Compose.findRecordByID(caseRecord.values.ProductId, 'Product').then(productRecord => {
// Find all updates in the case
return Compose.findRecords(`ProductId = ${productRecord.recordID}`, 'Case')
.then(({ set, filter }) => {
// Start the time and cost with the values of the current update, because the update
// is not saved until after the complete script has run
caseTime = 0
caseCost = 0
// Loop through the updates of the case, to sum the totals
set.forEach(r => {
// Get the time
let caseUpdateTime = r.values.TotalTime
if (typeof caseUpdateTime == "undefined" || caseUpdateTime === '' || isNaN(caseUpdateTime)) {
caseUpdateTime = 0
}
caseTime = parseFloat(caseTime) + parseFloat(caseUpdateTime)
// Get the cost
let caseUpdateCost = r.values.TotalCost
if (typeof caseUpdateCost == "undefined" || caseUpdateCost === '' || isNaN(caseUpdateCost)) {
caseUpdateCost = 0
}
caseCost = parseFloat(caseCost) + parseFloat(caseUpdateCost)
})
// Set the values in the case
productRecord.values.TotalTime = caseTime
productRecord.values.TotalCost = caseCost
// Save the case
return Compose.saveRecord(productRecord).then(mySavedProduct => {
console.log('Record saved, ID', mySavedProduct.recordID)
}).catch(err => {
// solve the problem
console.error(err)
})
}).catch(err => {
// solve the problem
console.error(err)
})
}).catch(err => {
// solve the problem
console.error(err)
})
}
// Add the totals for the department
}).then(mySavedCase => {
// If there is an department, update the total for that department
if ($record.values.Department) {
Compose.findRecordByID($record.values.Department, 'Department').then(departmentRecord => {
// Find all updates of the department (to run through them and update the totals)
return Compose.findRecords(`Department = ${$record.values.Department}`, 'Update')
.then(({ set, filter }) => {
let departmentTime = 0
let departmentCost = 0
// Loop through the updates of the department, to sum the totals
set.forEach(r => {
// Get the time
let departmentUpdateTime = r.values.TimeSpend
if (typeof departmentUpdateTime == "undefined" || departmentUpdateTime === '' || isNaN(departmentUpdateTime)) {
departmentUpdateTime = 0
}
departmentTime = parseFloat(departmentTime) + parseFloat(departmentUpdateTime)
// Get the cost
let departmentUpdateCost = r.values.Cost
if (typeof departmentUpdateCost == "undefined" || departmentUpdateCost === '' || isNaN(departmentUpdateCost)) {
departmentUpdateCost = 0
}
departmentCost = parseFloat(departmentCost) + parseFloat(departmentUpdateCost)
})
// Set the values in the department
departmentRecord.values.TotalTime = departmentTime
departmentRecord.values.TotalCost = departmentCost
// Save the department
return Compose.saveRecord(departmentRecord).then(mySavedDepartment => {
console.log('Record saved, ID', mySavedDepartment.recordID)
}).catch(err => {
// solve the problem
console.error(err)
})
}).catch(err => {
// solve the problem
console.error(err)
})
}).catch(err => {
// solve the problem
console.error(err)
})
}
}).catch(err => {
// solve the problem
console.error(err)
})
}).catch(err => {
// solve the problem
console.error(err)
})
}).catch(err => {
// solve the problem
console.error(err)
})
async: false
runInUA: false
critical: true
enabled: true
timeout: 0
triggers:
- event: afterCreate
module: Update
resource: compose:record
- event: afterUpdate
module: Update
resource: compose:record

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -3,20 +3,34 @@
cd "$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
function download {
SRC="https://raw.githubusercontent.com/cortezaproject/corteza-configs/master/${1}"
SRC="https://raw.githubusercontent.com/cortezaproject/corteza-configs/${1}"
DST=${2}
echo -ne "\033[32m${DST}\033[39m (${SRC}) ..."
curl -s $SRC > ${DST}
echo "done"
}
# ------ ------ ------ ------ ------ ------ ------ ------ ------ ------ ------ ------ ------ ------ ------ ------ ------
function getCrmConfig {
NAMES="1000_namespace 1100_modules 1200_charts 1300_scripts 1400_pages 1500_record_settings"
for NAME in $NAMES; do
download "crm/${NAME}.yaml" "./compose/src/${NAME}.yaml"
download "master/crm/${NAME}.yaml" "./compose/src/${NAME}_crm.yaml"
done
}
getCrmConfig
# ------ ------ ------ ------ ------ ------ ------ ------ ------ ------ ------ ------ ------ ------ ------ ------ ------
function getServiceCloudConfig {
NAMES="1000_namespace 1100_modules 1200_charts 1300_scripts 1400_pages 1500_record_settings"
for NAME in $NAMES; do
download "master/service-cloud/${NAME}.yaml" "./compose/src/${NAME}_service_cloud.yaml"
done
}
getServiceCloudConfig