feat: Auto resolve conversations after n days of inactivity (#1308)
fixes: #418
This commit is contained in:
parent
65ed4c78a4
commit
074084b258
79 changed files with 358 additions and 22 deletions
|
@ -33,7 +33,7 @@ class Api::V1::AccountsController < Api::BaseController
|
||||||
end
|
end
|
||||||
|
|
||||||
def update
|
def update
|
||||||
@account.update!(account_params.slice(:name, :locale, :domain, :support_email))
|
@account.update!(account_params.slice(:name, :locale, :domain, :support_email, :auto_resolve_duration))
|
||||||
end
|
end
|
||||||
|
|
||||||
def update_active_at
|
def update_active_at
|
||||||
|
@ -54,7 +54,7 @@ class Api::V1::AccountsController < Api::BaseController
|
||||||
end
|
end
|
||||||
|
|
||||||
def account_params
|
def account_params
|
||||||
params.permit(:account_name, :email, :name, :locale, :domain, :support_email)
|
params.permit(:account_name, :email, :name, :locale, :domain, :support_email, :auto_resolve_duration)
|
||||||
end
|
end
|
||||||
|
|
||||||
def check_signup_enabled
|
def check_signup_enabled
|
||||||
|
|
|
@ -33,6 +33,11 @@
|
||||||
"PLACEHOLDER": "عنوان البريد الإلكتروني الخاص باستقبال رسائل الدعم الفني",
|
"PLACEHOLDER": "عنوان البريد الإلكتروني الخاص باستقبال رسائل الدعم الفني",
|
||||||
"ERROR": ""
|
"ERROR": ""
|
||||||
},
|
},
|
||||||
|
"AUTO_RESOLVE_DURATION": {
|
||||||
|
"LABEL": "Number of days after a ticket should auto resolve if there is no activity",
|
||||||
|
"PLACEHOLDER": "30",
|
||||||
|
"ERROR": "Please enter a valid auto resolve duration (minimum 1 day)"
|
||||||
|
},
|
||||||
"FEATURES": {
|
"FEATURES": {
|
||||||
"INBOUND_EMAIL_ENABLED": "الاستمرار في المحادثة عبر رسائل البريد الإلكتروني مفعّل لحسابك.",
|
"INBOUND_EMAIL_ENABLED": "الاستمرار في المحادثة عبر رسائل البريد الإلكتروني مفعّل لحسابك.",
|
||||||
"CUSTOM_EMAIL_DOMAIN_ENABLED": "يمكنك تلقي رسائل البريد الإلكتروني في النطاق المخصص الخاص بك الآن."
|
"CUSTOM_EMAIL_DOMAIN_ENABLED": "يمكنك تلقي رسائل البريد الإلكتروني في النطاق المخصص الخاص بك الآن."
|
||||||
|
|
|
@ -33,6 +33,11 @@
|
||||||
"PLACEHOLDER": "Your company's support email",
|
"PLACEHOLDER": "Your company's support email",
|
||||||
"ERROR": ""
|
"ERROR": ""
|
||||||
},
|
},
|
||||||
|
"AUTO_RESOLVE_DURATION": {
|
||||||
|
"LABEL": "Number of days after a ticket should auto resolve if there is no activity",
|
||||||
|
"PLACEHOLDER": "30",
|
||||||
|
"ERROR": "Please enter a valid auto resolve duration (minimum 1 day)"
|
||||||
|
},
|
||||||
"FEATURES": {
|
"FEATURES": {
|
||||||
"INBOUND_EMAIL_ENABLED": "Conversation continuity with emails is enabled for your account.",
|
"INBOUND_EMAIL_ENABLED": "Conversation continuity with emails is enabled for your account.",
|
||||||
"CUSTOM_EMAIL_DOMAIN_ENABLED": "You can receive emails in your custom domain now."
|
"CUSTOM_EMAIL_DOMAIN_ENABLED": "You can receive emails in your custom domain now."
|
||||||
|
|
|
@ -33,6 +33,11 @@
|
||||||
"PLACEHOLDER": "Your company's support email",
|
"PLACEHOLDER": "Your company's support email",
|
||||||
"ERROR": ""
|
"ERROR": ""
|
||||||
},
|
},
|
||||||
|
"AUTO_RESOLVE_DURATION": {
|
||||||
|
"LABEL": "Number of days after a ticket should auto resolve if there is no activity",
|
||||||
|
"PLACEHOLDER": "30",
|
||||||
|
"ERROR": "Please enter a valid auto resolve duration (minimum 1 day)"
|
||||||
|
},
|
||||||
"FEATURES": {
|
"FEATURES": {
|
||||||
"INBOUND_EMAIL_ENABLED": "Conversation continuity with emails is enabled for your account.",
|
"INBOUND_EMAIL_ENABLED": "Conversation continuity with emails is enabled for your account.",
|
||||||
"CUSTOM_EMAIL_DOMAIN_ENABLED": "You can receive emails in your custom domain now."
|
"CUSTOM_EMAIL_DOMAIN_ENABLED": "You can receive emails in your custom domain now."
|
||||||
|
|
|
@ -33,6 +33,11 @@
|
||||||
"PLACEHOLDER": "Your company's support email",
|
"PLACEHOLDER": "Your company's support email",
|
||||||
"ERROR": ""
|
"ERROR": ""
|
||||||
},
|
},
|
||||||
|
"AUTO_RESOLVE_DURATION": {
|
||||||
|
"LABEL": "Number of days after a ticket should auto resolve if there is no activity",
|
||||||
|
"PLACEHOLDER": "30",
|
||||||
|
"ERROR": "Please enter a valid auto resolve duration (minimum 1 day)"
|
||||||
|
},
|
||||||
"FEATURES": {
|
"FEATURES": {
|
||||||
"INBOUND_EMAIL_ENABLED": "Conversation continuity with emails is enabled for your account.",
|
"INBOUND_EMAIL_ENABLED": "Conversation continuity with emails is enabled for your account.",
|
||||||
"CUSTOM_EMAIL_DOMAIN_ENABLED": "You can receive emails in your custom domain now."
|
"CUSTOM_EMAIL_DOMAIN_ENABLED": "You can receive emails in your custom domain now."
|
||||||
|
|
|
@ -33,6 +33,11 @@
|
||||||
"PLACEHOLDER": "Your company's support email",
|
"PLACEHOLDER": "Your company's support email",
|
||||||
"ERROR": ""
|
"ERROR": ""
|
||||||
},
|
},
|
||||||
|
"AUTO_RESOLVE_DURATION": {
|
||||||
|
"LABEL": "Number of days after a ticket should auto resolve if there is no activity",
|
||||||
|
"PLACEHOLDER": "30",
|
||||||
|
"ERROR": "Please enter a valid auto resolve duration (minimum 1 day)"
|
||||||
|
},
|
||||||
"FEATURES": {
|
"FEATURES": {
|
||||||
"INBOUND_EMAIL_ENABLED": "Conversation continuity with emails is enabled for your account.",
|
"INBOUND_EMAIL_ENABLED": "Conversation continuity with emails is enabled for your account.",
|
||||||
"CUSTOM_EMAIL_DOMAIN_ENABLED": "You can receive emails in your custom domain now."
|
"CUSTOM_EMAIL_DOMAIN_ENABLED": "You can receive emails in your custom domain now."
|
||||||
|
|
|
@ -33,6 +33,11 @@
|
||||||
"PLACEHOLDER": "To email υποστήριξης της εταιρίας σας",
|
"PLACEHOLDER": "To email υποστήριξης της εταιρίας σας",
|
||||||
"ERROR": ""
|
"ERROR": ""
|
||||||
},
|
},
|
||||||
|
"AUTO_RESOLVE_DURATION": {
|
||||||
|
"LABEL": "Number of days after a ticket should auto resolve if there is no activity",
|
||||||
|
"PLACEHOLDER": "30",
|
||||||
|
"ERROR": "Please enter a valid auto resolve duration (minimum 1 day)"
|
||||||
|
},
|
||||||
"FEATURES": {
|
"FEATURES": {
|
||||||
"INBOUND_EMAIL_ENABLED": "Η συνέχεια της συνομιλίας με emails έχει ενεργοποιηθεί για τον λογαριασμό.",
|
"INBOUND_EMAIL_ENABLED": "Η συνέχεια της συνομιλίας με emails έχει ενεργοποιηθεί για τον λογαριασμό.",
|
||||||
"CUSTOM_EMAIL_DOMAIN_ENABLED": "Τώρα μπορείτε να λαμβάνετε emails στον τομέα (domain) σας."
|
"CUSTOM_EMAIL_DOMAIN_ENABLED": "Τώρα μπορείτε να λαμβάνετε emails στον τομέα (domain) σας."
|
||||||
|
|
|
@ -33,6 +33,11 @@
|
||||||
"PLACEHOLDER": "Your company's support email",
|
"PLACEHOLDER": "Your company's support email",
|
||||||
"ERROR": ""
|
"ERROR": ""
|
||||||
},
|
},
|
||||||
|
"AUTO_RESOLVE_DURATION": {
|
||||||
|
"LABEL": "Number of days after a ticket should auto resolve if there is no activity",
|
||||||
|
"PLACEHOLDER": "30",
|
||||||
|
"ERROR": "Please enter a valid auto resolve duration (minimum 1 day)"
|
||||||
|
},
|
||||||
"FEATURES": {
|
"FEATURES": {
|
||||||
"INBOUND_EMAIL_ENABLED": "Conversation continuity with emails is enabled for your account.",
|
"INBOUND_EMAIL_ENABLED": "Conversation continuity with emails is enabled for your account.",
|
||||||
"CUSTOM_EMAIL_DOMAIN_ENABLED": "You can receive emails in your custom domain now."
|
"CUSTOM_EMAIL_DOMAIN_ENABLED": "You can receive emails in your custom domain now."
|
||||||
|
|
|
@ -33,6 +33,11 @@
|
||||||
"PLACEHOLDER": "Email de soporte de su empresa",
|
"PLACEHOLDER": "Email de soporte de su empresa",
|
||||||
"ERROR": ""
|
"ERROR": ""
|
||||||
},
|
},
|
||||||
|
"AUTO_RESOLVE_DURATION": {
|
||||||
|
"LABEL": "Number of days after a ticket should auto resolve if there is no activity",
|
||||||
|
"PLACEHOLDER": "30",
|
||||||
|
"ERROR": "Please enter a valid auto resolve duration (minimum 1 day)"
|
||||||
|
},
|
||||||
"FEATURES": {
|
"FEATURES": {
|
||||||
"INBOUND_EMAIL_ENABLED": "Continuidad de la conversación con emails está habilitada para su cuenta.",
|
"INBOUND_EMAIL_ENABLED": "Continuidad de la conversación con emails está habilitada para su cuenta.",
|
||||||
"CUSTOM_EMAIL_DOMAIN_ENABLED": "Ahora puede recibir emails en su dominio personalizado."
|
"CUSTOM_EMAIL_DOMAIN_ENABLED": "Ahora puede recibir emails en su dominio personalizado."
|
||||||
|
|
|
@ -33,6 +33,11 @@
|
||||||
"PLACEHOLDER": "ایمیل پشتیبانی شرکت شما",
|
"PLACEHOLDER": "ایمیل پشتیبانی شرکت شما",
|
||||||
"ERROR": ""
|
"ERROR": ""
|
||||||
},
|
},
|
||||||
|
"AUTO_RESOLVE_DURATION": {
|
||||||
|
"LABEL": "Number of days after a ticket should auto resolve if there is no activity",
|
||||||
|
"PLACEHOLDER": "30",
|
||||||
|
"ERROR": "Please enter a valid auto resolve duration (minimum 1 day)"
|
||||||
|
},
|
||||||
"FEATURES": {
|
"FEATURES": {
|
||||||
"INBOUND_EMAIL_ENABLED": "Conversation continuity with emails is enabled for your account.",
|
"INBOUND_EMAIL_ENABLED": "Conversation continuity with emails is enabled for your account.",
|
||||||
"CUSTOM_EMAIL_DOMAIN_ENABLED": "You can receive emails in your custom domain now."
|
"CUSTOM_EMAIL_DOMAIN_ENABLED": "You can receive emails in your custom domain now."
|
||||||
|
|
|
@ -33,6 +33,11 @@
|
||||||
"PLACEHOLDER": "Your company's support email",
|
"PLACEHOLDER": "Your company's support email",
|
||||||
"ERROR": ""
|
"ERROR": ""
|
||||||
},
|
},
|
||||||
|
"AUTO_RESOLVE_DURATION": {
|
||||||
|
"LABEL": "Number of days after a ticket should auto resolve if there is no activity",
|
||||||
|
"PLACEHOLDER": "30",
|
||||||
|
"ERROR": "Please enter a valid auto resolve duration (minimum 1 day)"
|
||||||
|
},
|
||||||
"FEATURES": {
|
"FEATURES": {
|
||||||
"INBOUND_EMAIL_ENABLED": "Conversation continuity with emails is enabled for your account.",
|
"INBOUND_EMAIL_ENABLED": "Conversation continuity with emails is enabled for your account.",
|
||||||
"CUSTOM_EMAIL_DOMAIN_ENABLED": "You can receive emails in your custom domain now."
|
"CUSTOM_EMAIL_DOMAIN_ENABLED": "You can receive emails in your custom domain now."
|
||||||
|
|
|
@ -33,6 +33,11 @@
|
||||||
"PLACEHOLDER": "L'adresse de courriel de support de votre entreprise",
|
"PLACEHOLDER": "L'adresse de courriel de support de votre entreprise",
|
||||||
"ERROR": ""
|
"ERROR": ""
|
||||||
},
|
},
|
||||||
|
"AUTO_RESOLVE_DURATION": {
|
||||||
|
"LABEL": "Number of days after a ticket should auto resolve if there is no activity",
|
||||||
|
"PLACEHOLDER": "30",
|
||||||
|
"ERROR": "Please enter a valid auto resolve duration (minimum 1 day)"
|
||||||
|
},
|
||||||
"FEATURES": {
|
"FEATURES": {
|
||||||
"INBOUND_EMAIL_ENABLED": "La continuité des conversations avec les courriels est activée pour votre compte.",
|
"INBOUND_EMAIL_ENABLED": "La continuité des conversations avec les courriels est activée pour votre compte.",
|
||||||
"CUSTOM_EMAIL_DOMAIN_ENABLED": "Vous pouvez maintenant recevoir des courriels dans votre domaine personnalisé."
|
"CUSTOM_EMAIL_DOMAIN_ENABLED": "Vous pouvez maintenant recevoir des courriels dans votre domaine personnalisé."
|
||||||
|
|
|
@ -33,6 +33,11 @@
|
||||||
"PLACEHOLDER": "Your company's support email",
|
"PLACEHOLDER": "Your company's support email",
|
||||||
"ERROR": ""
|
"ERROR": ""
|
||||||
},
|
},
|
||||||
|
"AUTO_RESOLVE_DURATION": {
|
||||||
|
"LABEL": "Number of days after a ticket should auto resolve if there is no activity",
|
||||||
|
"PLACEHOLDER": "30",
|
||||||
|
"ERROR": "Please enter a valid auto resolve duration (minimum 1 day)"
|
||||||
|
},
|
||||||
"FEATURES": {
|
"FEATURES": {
|
||||||
"INBOUND_EMAIL_ENABLED": "Conversation continuity with emails is enabled for your account.",
|
"INBOUND_EMAIL_ENABLED": "Conversation continuity with emails is enabled for your account.",
|
||||||
"CUSTOM_EMAIL_DOMAIN_ENABLED": "You can receive emails in your custom domain now."
|
"CUSTOM_EMAIL_DOMAIN_ENABLED": "You can receive emails in your custom domain now."
|
||||||
|
|
|
@ -33,6 +33,11 @@
|
||||||
"PLACEHOLDER": "Your company's support email",
|
"PLACEHOLDER": "Your company's support email",
|
||||||
"ERROR": ""
|
"ERROR": ""
|
||||||
},
|
},
|
||||||
|
"AUTO_RESOLVE_DURATION": {
|
||||||
|
"LABEL": "Number of days after a ticket should auto resolve if there is no activity",
|
||||||
|
"PLACEHOLDER": "30",
|
||||||
|
"ERROR": "Please enter a valid auto resolve duration (minimum 1 day)"
|
||||||
|
},
|
||||||
"FEATURES": {
|
"FEATURES": {
|
||||||
"INBOUND_EMAIL_ENABLED": "Conversation continuity with emails is enabled for your account.",
|
"INBOUND_EMAIL_ENABLED": "Conversation continuity with emails is enabled for your account.",
|
||||||
"CUSTOM_EMAIL_DOMAIN_ENABLED": "You can receive emails in your custom domain now."
|
"CUSTOM_EMAIL_DOMAIN_ENABLED": "You can receive emails in your custom domain now."
|
||||||
|
|
|
@ -33,6 +33,11 @@
|
||||||
"PLACEHOLDER": "E-mail di supporto della tua azienda",
|
"PLACEHOLDER": "E-mail di supporto della tua azienda",
|
||||||
"ERROR": ""
|
"ERROR": ""
|
||||||
},
|
},
|
||||||
|
"AUTO_RESOLVE_DURATION": {
|
||||||
|
"LABEL": "Number of days after a ticket should auto resolve if there is no activity",
|
||||||
|
"PLACEHOLDER": "30",
|
||||||
|
"ERROR": "Please enter a valid auto resolve duration (minimum 1 day)"
|
||||||
|
},
|
||||||
"FEATURES": {
|
"FEATURES": {
|
||||||
"INBOUND_EMAIL_ENABLED": "Conversation continuity with emails is enabled for your account.",
|
"INBOUND_EMAIL_ENABLED": "Conversation continuity with emails is enabled for your account.",
|
||||||
"CUSTOM_EMAIL_DOMAIN_ENABLED": "You can receive emails in your custom domain now."
|
"CUSTOM_EMAIL_DOMAIN_ENABLED": "You can receive emails in your custom domain now."
|
||||||
|
|
|
@ -33,6 +33,11 @@
|
||||||
"PLACEHOLDER": "Your company's support email",
|
"PLACEHOLDER": "Your company's support email",
|
||||||
"ERROR": ""
|
"ERROR": ""
|
||||||
},
|
},
|
||||||
|
"AUTO_RESOLVE_DURATION": {
|
||||||
|
"LABEL": "Number of days after a ticket should auto resolve if there is no activity",
|
||||||
|
"PLACEHOLDER": "30",
|
||||||
|
"ERROR": "Please enter a valid auto resolve duration (minimum 1 day)"
|
||||||
|
},
|
||||||
"FEATURES": {
|
"FEATURES": {
|
||||||
"INBOUND_EMAIL_ENABLED": "Conversation continuity with emails is enabled for your account.",
|
"INBOUND_EMAIL_ENABLED": "Conversation continuity with emails is enabled for your account.",
|
||||||
"CUSTOM_EMAIL_DOMAIN_ENABLED": "You can receive emails in your custom domain now."
|
"CUSTOM_EMAIL_DOMAIN_ENABLED": "You can receive emails in your custom domain now."
|
||||||
|
|
|
@ -33,6 +33,11 @@
|
||||||
"PLACEHOLDER": "Your company's support email",
|
"PLACEHOLDER": "Your company's support email",
|
||||||
"ERROR": ""
|
"ERROR": ""
|
||||||
},
|
},
|
||||||
|
"AUTO_RESOLVE_DURATION": {
|
||||||
|
"LABEL": "Number of days after a ticket should auto resolve if there is no activity",
|
||||||
|
"PLACEHOLDER": "30",
|
||||||
|
"ERROR": "Please enter a valid auto resolve duration (minimum 1 day)"
|
||||||
|
},
|
||||||
"FEATURES": {
|
"FEATURES": {
|
||||||
"INBOUND_EMAIL_ENABLED": "Conversation continuity with emails is enabled for your account.",
|
"INBOUND_EMAIL_ENABLED": "Conversation continuity with emails is enabled for your account.",
|
||||||
"CUSTOM_EMAIL_DOMAIN_ENABLED": "You can receive emails in your custom domain now."
|
"CUSTOM_EMAIL_DOMAIN_ENABLED": "You can receive emails in your custom domain now."
|
||||||
|
|
|
@ -33,6 +33,11 @@
|
||||||
"PLACEHOLDER": "നിങ്ങളുടെ കമ്പനിയുടെ പിന്തുണാ ഇമെയിൽ",
|
"PLACEHOLDER": "നിങ്ങളുടെ കമ്പനിയുടെ പിന്തുണാ ഇമെയിൽ",
|
||||||
"ERROR": ""
|
"ERROR": ""
|
||||||
},
|
},
|
||||||
|
"AUTO_RESOLVE_DURATION": {
|
||||||
|
"LABEL": "Number of days after a ticket should auto resolve if there is no activity",
|
||||||
|
"PLACEHOLDER": "30",
|
||||||
|
"ERROR": "Please enter a valid auto resolve duration (minimum 1 day)"
|
||||||
|
},
|
||||||
"FEATURES": {
|
"FEATURES": {
|
||||||
"INBOUND_EMAIL_ENABLED": "നിങ്ങളുടെ അക്കൗണ്ടിനായി ഇമെയിലുകളുമായുള്ള സംഭാഷണ തുടർച്ച പ്രവർത്തനക്ഷമമാക്കി.",
|
"INBOUND_EMAIL_ENABLED": "നിങ്ങളുടെ അക്കൗണ്ടിനായി ഇമെയിലുകളുമായുള്ള സംഭാഷണ തുടർച്ച പ്രവർത്തനക്ഷമമാക്കി.",
|
||||||
"CUSTOM_EMAIL_DOMAIN_ENABLED": "നിങ്ങളുടെ ഇഷ്ടാനുസൃത ഡൊമെയ്നിൽ നിങ്ങൾക്ക് ഇപ്പോൾ ഇമെയിലുകൾ സ്വീകരിക്കാൻ കഴിയും."
|
"CUSTOM_EMAIL_DOMAIN_ENABLED": "നിങ്ങളുടെ ഇഷ്ടാനുസൃത ഡൊമെയ്നിൽ നിങ്ങൾക്ക് ഇപ്പോൾ ഇമെയിലുകൾ സ്വീകരിക്കാൻ കഴിയും."
|
||||||
|
|
|
@ -33,6 +33,11 @@
|
||||||
"PLACEHOLDER": "E-mailadres support van uw bedrijf",
|
"PLACEHOLDER": "E-mailadres support van uw bedrijf",
|
||||||
"ERROR": ""
|
"ERROR": ""
|
||||||
},
|
},
|
||||||
|
"AUTO_RESOLVE_DURATION": {
|
||||||
|
"LABEL": "Number of days after a ticket should auto resolve if there is no activity",
|
||||||
|
"PLACEHOLDER": "30",
|
||||||
|
"ERROR": "Please enter a valid auto resolve duration (minimum 1 day)"
|
||||||
|
},
|
||||||
"FEATURES": {
|
"FEATURES": {
|
||||||
"INBOUND_EMAIL_ENABLED": "Conversation continuity with emails is enabled for your account.",
|
"INBOUND_EMAIL_ENABLED": "Conversation continuity with emails is enabled for your account.",
|
||||||
"CUSTOM_EMAIL_DOMAIN_ENABLED": "You can receive emails in your custom domain now."
|
"CUSTOM_EMAIL_DOMAIN_ENABLED": "You can receive emails in your custom domain now."
|
||||||
|
|
|
@ -33,6 +33,11 @@
|
||||||
"PLACEHOLDER": "Your company's support email",
|
"PLACEHOLDER": "Your company's support email",
|
||||||
"ERROR": ""
|
"ERROR": ""
|
||||||
},
|
},
|
||||||
|
"AUTO_RESOLVE_DURATION": {
|
||||||
|
"LABEL": "Number of days after a ticket should auto resolve if there is no activity",
|
||||||
|
"PLACEHOLDER": "30",
|
||||||
|
"ERROR": "Please enter a valid auto resolve duration (minimum 1 day)"
|
||||||
|
},
|
||||||
"FEATURES": {
|
"FEATURES": {
|
||||||
"INBOUND_EMAIL_ENABLED": "Conversation continuity with emails is enabled for your account.",
|
"INBOUND_EMAIL_ENABLED": "Conversation continuity with emails is enabled for your account.",
|
||||||
"CUSTOM_EMAIL_DOMAIN_ENABLED": "You can receive emails in your custom domain now."
|
"CUSTOM_EMAIL_DOMAIN_ENABLED": "You can receive emails in your custom domain now."
|
||||||
|
|
|
@ -33,6 +33,11 @@
|
||||||
"PLACEHOLDER": "E-mail de suporte da sua empresa",
|
"PLACEHOLDER": "E-mail de suporte da sua empresa",
|
||||||
"ERROR": ""
|
"ERROR": ""
|
||||||
},
|
},
|
||||||
|
"AUTO_RESOLVE_DURATION": {
|
||||||
|
"LABEL": "Number of days after a ticket should auto resolve if there is no activity",
|
||||||
|
"PLACEHOLDER": "30",
|
||||||
|
"ERROR": "Please enter a valid auto resolve duration (minimum 1 day)"
|
||||||
|
},
|
||||||
"FEATURES": {
|
"FEATURES": {
|
||||||
"INBOUND_EMAIL_ENABLED": "Conversation continuity with emails is enabled for your account.",
|
"INBOUND_EMAIL_ENABLED": "Conversation continuity with emails is enabled for your account.",
|
||||||
"CUSTOM_EMAIL_DOMAIN_ENABLED": "You can receive emails in your custom domain now."
|
"CUSTOM_EMAIL_DOMAIN_ENABLED": "You can receive emails in your custom domain now."
|
||||||
|
|
|
@ -33,6 +33,11 @@
|
||||||
"PLACEHOLDER": "E-mail de suporte da sua empresa",
|
"PLACEHOLDER": "E-mail de suporte da sua empresa",
|
||||||
"ERROR": ""
|
"ERROR": ""
|
||||||
},
|
},
|
||||||
|
"AUTO_RESOLVE_DURATION": {
|
||||||
|
"LABEL": "Number of days after a ticket should auto resolve if there is no activity",
|
||||||
|
"PLACEHOLDER": "30",
|
||||||
|
"ERROR": "Please enter a valid auto resolve duration (minimum 1 day)"
|
||||||
|
},
|
||||||
"FEATURES": {
|
"FEATURES": {
|
||||||
"INBOUND_EMAIL_ENABLED": "A continuidade das conversas com e-mails está ativada para sua conta.",
|
"INBOUND_EMAIL_ENABLED": "A continuidade das conversas com e-mails está ativada para sua conta.",
|
||||||
"CUSTOM_EMAIL_DOMAIN_ENABLED": "Você pode receber e-mails em seu domínio personalizado agora."
|
"CUSTOM_EMAIL_DOMAIN_ENABLED": "Você pode receber e-mails em seu domínio personalizado agora."
|
||||||
|
|
|
@ -33,6 +33,11 @@
|
||||||
"PLACEHOLDER": "E-mailul de asistență al companiei dumneavoastră",
|
"PLACEHOLDER": "E-mailul de asistență al companiei dumneavoastră",
|
||||||
"ERROR": ""
|
"ERROR": ""
|
||||||
},
|
},
|
||||||
|
"AUTO_RESOLVE_DURATION": {
|
||||||
|
"LABEL": "Number of days after a ticket should auto resolve if there is no activity",
|
||||||
|
"PLACEHOLDER": "30",
|
||||||
|
"ERROR": "Please enter a valid auto resolve duration (minimum 1 day)"
|
||||||
|
},
|
||||||
"FEATURES": {
|
"FEATURES": {
|
||||||
"INBOUND_EMAIL_ENABLED": "Continuitatea conversației cu e-mailurile este activată pentru contul dvs.",
|
"INBOUND_EMAIL_ENABLED": "Continuitatea conversației cu e-mailurile este activată pentru contul dvs.",
|
||||||
"CUSTOM_EMAIL_DOMAIN_ENABLED": "Puteți primi e-mailuri în domeniul dvs. personalizat acum."
|
"CUSTOM_EMAIL_DOMAIN_ENABLED": "Puteți primi e-mailuri în domeniul dvs. personalizat acum."
|
||||||
|
|
|
@ -33,6 +33,11 @@
|
||||||
"PLACEHOLDER": "Email службы поддержки вашей компании",
|
"PLACEHOLDER": "Email службы поддержки вашей компании",
|
||||||
"ERROR": ""
|
"ERROR": ""
|
||||||
},
|
},
|
||||||
|
"AUTO_RESOLVE_DURATION": {
|
||||||
|
"LABEL": "Number of days after a ticket should auto resolve if there is no activity",
|
||||||
|
"PLACEHOLDER": "30",
|
||||||
|
"ERROR": "Please enter a valid auto resolve duration (minimum 1 day)"
|
||||||
|
},
|
||||||
"FEATURES": {
|
"FEATURES": {
|
||||||
"INBOUND_EMAIL_ENABLED": "Для вашего аккаунта включено продолжение диалогов по электронной почте.",
|
"INBOUND_EMAIL_ENABLED": "Для вашего аккаунта включено продолжение диалогов по электронной почте.",
|
||||||
"CUSTOM_EMAIL_DOMAIN_ENABLED": "Теперь вы можете получать письма на свой домен."
|
"CUSTOM_EMAIL_DOMAIN_ENABLED": "Теперь вы можете получать письма на свой домен."
|
||||||
|
|
|
@ -33,6 +33,11 @@
|
||||||
"PLACEHOLDER": "Your company's support email",
|
"PLACEHOLDER": "Your company's support email",
|
||||||
"ERROR": ""
|
"ERROR": ""
|
||||||
},
|
},
|
||||||
|
"AUTO_RESOLVE_DURATION": {
|
||||||
|
"LABEL": "Number of days after a ticket should auto resolve if there is no activity",
|
||||||
|
"PLACEHOLDER": "30",
|
||||||
|
"ERROR": "Please enter a valid auto resolve duration (minimum 1 day)"
|
||||||
|
},
|
||||||
"FEATURES": {
|
"FEATURES": {
|
||||||
"INBOUND_EMAIL_ENABLED": "Conversation continuity with emails is enabled for your account.",
|
"INBOUND_EMAIL_ENABLED": "Conversation continuity with emails is enabled for your account.",
|
||||||
"CUSTOM_EMAIL_DOMAIN_ENABLED": "You can receive emails in your custom domain now."
|
"CUSTOM_EMAIL_DOMAIN_ENABLED": "You can receive emails in your custom domain now."
|
||||||
|
|
|
@ -33,6 +33,11 @@
|
||||||
"PLACEHOLDER": "Your company's support email",
|
"PLACEHOLDER": "Your company's support email",
|
||||||
"ERROR": ""
|
"ERROR": ""
|
||||||
},
|
},
|
||||||
|
"AUTO_RESOLVE_DURATION": {
|
||||||
|
"LABEL": "Number of days after a ticket should auto resolve if there is no activity",
|
||||||
|
"PLACEHOLDER": "30",
|
||||||
|
"ERROR": "Please enter a valid auto resolve duration (minimum 1 day)"
|
||||||
|
},
|
||||||
"FEATURES": {
|
"FEATURES": {
|
||||||
"INBOUND_EMAIL_ENABLED": "Conversation continuity with emails is enabled for your account.",
|
"INBOUND_EMAIL_ENABLED": "Conversation continuity with emails is enabled for your account.",
|
||||||
"CUSTOM_EMAIL_DOMAIN_ENABLED": "You can receive emails in your custom domain now."
|
"CUSTOM_EMAIL_DOMAIN_ENABLED": "You can receive emails in your custom domain now."
|
||||||
|
|
|
@ -33,6 +33,11 @@
|
||||||
"PLACEHOLDER": "உங்கள் நிறுவனத்தின் சேவைக்கான ஈ-மெயில் முகவரி",
|
"PLACEHOLDER": "உங்கள் நிறுவனத்தின் சேவைக்கான ஈ-மெயில் முகவரி",
|
||||||
"ERROR": ""
|
"ERROR": ""
|
||||||
},
|
},
|
||||||
|
"AUTO_RESOLVE_DURATION": {
|
||||||
|
"LABEL": "Number of days after a ticket should auto resolve if there is no activity",
|
||||||
|
"PLACEHOLDER": "30",
|
||||||
|
"ERROR": "Please enter a valid auto resolve duration (minimum 1 day)"
|
||||||
|
},
|
||||||
"FEATURES": {
|
"FEATURES": {
|
||||||
"INBOUND_EMAIL_ENABLED": "Conversation continuity with emails is enabled for your account.",
|
"INBOUND_EMAIL_ENABLED": "Conversation continuity with emails is enabled for your account.",
|
||||||
"CUSTOM_EMAIL_DOMAIN_ENABLED": "You can receive emails in your custom domain now."
|
"CUSTOM_EMAIL_DOMAIN_ENABLED": "You can receive emails in your custom domain now."
|
||||||
|
|
|
@ -33,6 +33,11 @@
|
||||||
"PLACEHOLDER": "อีเมล์ช่วยเหลือในบริษัทของคุณ",
|
"PLACEHOLDER": "อีเมล์ช่วยเหลือในบริษัทของคุณ",
|
||||||
"ERROR": ""
|
"ERROR": ""
|
||||||
},
|
},
|
||||||
|
"AUTO_RESOLVE_DURATION": {
|
||||||
|
"LABEL": "Number of days after a ticket should auto resolve if there is no activity",
|
||||||
|
"PLACEHOLDER": "30",
|
||||||
|
"ERROR": "Please enter a valid auto resolve duration (minimum 1 day)"
|
||||||
|
},
|
||||||
"FEATURES": {
|
"FEATURES": {
|
||||||
"INBOUND_EMAIL_ENABLED": "การสนทนาด้วยอีเมล์ถูกเปิดสำหรับบัญชีของคุณ",
|
"INBOUND_EMAIL_ENABLED": "การสนทนาด้วยอีเมล์ถูกเปิดสำหรับบัญชีของคุณ",
|
||||||
"CUSTOM_EMAIL_DOMAIN_ENABLED": "คุณสามารถรับอีเมล์ในโดเมนเเบบกำหนดเองได้เเล้ว"
|
"CUSTOM_EMAIL_DOMAIN_ENABLED": "คุณสามารถรับอีเมล์ในโดเมนเเบบกำหนดเองได้เเล้ว"
|
||||||
|
|
|
@ -33,6 +33,11 @@
|
||||||
"PLACEHOLDER": "Your company's support email",
|
"PLACEHOLDER": "Your company's support email",
|
||||||
"ERROR": ""
|
"ERROR": ""
|
||||||
},
|
},
|
||||||
|
"AUTO_RESOLVE_DURATION": {
|
||||||
|
"LABEL": "Number of days after a ticket should auto resolve if there is no activity",
|
||||||
|
"PLACEHOLDER": "30",
|
||||||
|
"ERROR": "Please enter a valid auto resolve duration (minimum 1 day)"
|
||||||
|
},
|
||||||
"FEATURES": {
|
"FEATURES": {
|
||||||
"INBOUND_EMAIL_ENABLED": "Conversation continuity with emails is enabled for your account.",
|
"INBOUND_EMAIL_ENABLED": "Conversation continuity with emails is enabled for your account.",
|
||||||
"CUSTOM_EMAIL_DOMAIN_ENABLED": "You can receive emails in your custom domain now."
|
"CUSTOM_EMAIL_DOMAIN_ENABLED": "You can receive emails in your custom domain now."
|
||||||
|
|
|
@ -33,6 +33,11 @@
|
||||||
"PLACEHOLDER": "Your company's support email",
|
"PLACEHOLDER": "Your company's support email",
|
||||||
"ERROR": ""
|
"ERROR": ""
|
||||||
},
|
},
|
||||||
|
"AUTO_RESOLVE_DURATION": {
|
||||||
|
"LABEL": "Number of days after a ticket should auto resolve if there is no activity",
|
||||||
|
"PLACEHOLDER": "30",
|
||||||
|
"ERROR": "Please enter a valid auto resolve duration (minimum 1 day)"
|
||||||
|
},
|
||||||
"FEATURES": {
|
"FEATURES": {
|
||||||
"INBOUND_EMAIL_ENABLED": "Conversation continuity with emails is enabled for your account.",
|
"INBOUND_EMAIL_ENABLED": "Conversation continuity with emails is enabled for your account.",
|
||||||
"CUSTOM_EMAIL_DOMAIN_ENABLED": "You can receive emails in your custom domain now."
|
"CUSTOM_EMAIL_DOMAIN_ENABLED": "You can receive emails in your custom domain now."
|
||||||
|
|
|
@ -33,6 +33,11 @@
|
||||||
"PLACEHOLDER": "Email hỗ trợ của công ty bạn",
|
"PLACEHOLDER": "Email hỗ trợ của công ty bạn",
|
||||||
"ERROR": ""
|
"ERROR": ""
|
||||||
},
|
},
|
||||||
|
"AUTO_RESOLVE_DURATION": {
|
||||||
|
"LABEL": "Number of days after a ticket should auto resolve if there is no activity",
|
||||||
|
"PLACEHOLDER": "30",
|
||||||
|
"ERROR": "Please enter a valid auto resolve duration (minimum 1 day)"
|
||||||
|
},
|
||||||
"FEATURES": {
|
"FEATURES": {
|
||||||
"INBOUND_EMAIL_ENABLED": "Tính liên tục của cuộc trò chuyện với email được kích hoạt cho tài khoản của bạn.",
|
"INBOUND_EMAIL_ENABLED": "Tính liên tục của cuộc trò chuyện với email được kích hoạt cho tài khoản của bạn.",
|
||||||
"CUSTOM_EMAIL_DOMAIN_ENABLED": "Bạn có thể nhận email trong miền tùy chỉnh của mình ngay bây giờ."
|
"CUSTOM_EMAIL_DOMAIN_ENABLED": "Bạn có thể nhận email trong miền tùy chỉnh của mình ngay bây giờ."
|
||||||
|
|
|
@ -33,6 +33,11 @@
|
||||||
"PLACEHOLDER": "您公司的支持邮件",
|
"PLACEHOLDER": "您公司的支持邮件",
|
||||||
"ERROR": ""
|
"ERROR": ""
|
||||||
},
|
},
|
||||||
|
"AUTO_RESOLVE_DURATION": {
|
||||||
|
"LABEL": "Number of days after a ticket should auto resolve if there is no activity",
|
||||||
|
"PLACEHOLDER": "30",
|
||||||
|
"ERROR": "Please enter a valid auto resolve duration (minimum 1 day)"
|
||||||
|
},
|
||||||
"FEATURES": {
|
"FEATURES": {
|
||||||
"INBOUND_EMAIL_ENABLED": "您的帐户启用了与电子邮件的对话连续性。",
|
"INBOUND_EMAIL_ENABLED": "您的帐户启用了与电子邮件的对话连续性。",
|
||||||
"CUSTOM_EMAIL_DOMAIN_ENABLED": "您现在可以在您的自定义域名的电子邮件中接收消息。"
|
"CUSTOM_EMAIL_DOMAIN_ENABLED": "您现在可以在您的自定义域名的电子邮件中接收消息。"
|
||||||
|
|
|
@ -33,6 +33,11 @@
|
||||||
"PLACEHOLDER": "您公司的支持邮件",
|
"PLACEHOLDER": "您公司的支持邮件",
|
||||||
"ERROR": ""
|
"ERROR": ""
|
||||||
},
|
},
|
||||||
|
"AUTO_RESOLVE_DURATION": {
|
||||||
|
"LABEL": "Number of days after a ticket should auto resolve if there is no activity",
|
||||||
|
"PLACEHOLDER": "30",
|
||||||
|
"ERROR": "Please enter a valid auto resolve duration (minimum 1 day)"
|
||||||
|
},
|
||||||
"FEATURES": {
|
"FEATURES": {
|
||||||
"INBOUND_EMAIL_ENABLED": "您的帐户启用了与电子邮件的对话连续性。",
|
"INBOUND_EMAIL_ENABLED": "您的帐户启用了与电子邮件的对话连续性。",
|
||||||
"CUSTOM_EMAIL_DOMAIN_ENABLED": "您现在可以在您的自定义域名的电子邮件中接收消息。"
|
"CUSTOM_EMAIL_DOMAIN_ENABLED": "您现在可以在您的自定义域名的电子邮件中接收消息。"
|
||||||
|
|
|
@ -33,6 +33,11 @@
|
||||||
"PLACEHOLDER": "您公司的客服信箱",
|
"PLACEHOLDER": "您公司的客服信箱",
|
||||||
"ERROR": ""
|
"ERROR": ""
|
||||||
},
|
},
|
||||||
|
"AUTO_RESOLVE_DURATION": {
|
||||||
|
"LABEL": "Number of days after a ticket should auto resolve if there is no activity",
|
||||||
|
"PLACEHOLDER": "30",
|
||||||
|
"ERROR": "Please enter a valid auto resolve duration (minimum 1 day)"
|
||||||
|
},
|
||||||
"FEATURES": {
|
"FEATURES": {
|
||||||
"INBOUND_EMAIL_ENABLED": "您的帳戶啟用了電子信箱與對話的持續性功能。",
|
"INBOUND_EMAIL_ENABLED": "您的帳戶啟用了電子信箱與對話的持續性功能。",
|
||||||
"CUSTOM_EMAIL_DOMAIN_ENABLED": "您現在可以在您的自定義域名的電子信箱中接收消息。"
|
"CUSTOM_EMAIL_DOMAIN_ENABLED": "您現在可以在您的自定義域名的電子信箱中接收消息。"
|
||||||
|
|
|
@ -62,6 +62,20 @@
|
||||||
"
|
"
|
||||||
/>
|
/>
|
||||||
</label>
|
</label>
|
||||||
|
<label :class="{ error: $v.autoResolveDuration.$error }">
|
||||||
|
{{ $t('GENERAL_SETTINGS.FORM.AUTO_RESOLVE_DURATION.LABEL') }}
|
||||||
|
<input
|
||||||
|
v-model="autoResolveDuration"
|
||||||
|
type="number"
|
||||||
|
:placeholder="
|
||||||
|
$t('GENERAL_SETTINGS.FORM.AUTO_RESOLVE_DURATION.PLACEHOLDER')
|
||||||
|
"
|
||||||
|
@blur="$v.autoResolveDuration.$touch"
|
||||||
|
/>
|
||||||
|
<span v-if="$v.autoResolveDuration.$error" class="message">
|
||||||
|
{{ $t('GENERAL_SETTINGS.FORM.AUTO_RESOLVE_DURATION.ERROR') }}
|
||||||
|
</span>
|
||||||
|
</label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="current-version">
|
<div class="current-version">
|
||||||
|
@ -82,7 +96,7 @@
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import Vue from 'vue';
|
import Vue from 'vue';
|
||||||
import { required } from 'vuelidate/lib/validators';
|
import { required, minValue } from 'vuelidate/lib/validators';
|
||||||
import { mapGetters } from 'vuex';
|
import { mapGetters } from 'vuex';
|
||||||
import alertMixin from 'shared/mixins/alertMixin';
|
import alertMixin from 'shared/mixins/alertMixin';
|
||||||
import configMixin from 'shared/mixins/configMixin';
|
import configMixin from 'shared/mixins/configMixin';
|
||||||
|
@ -98,6 +112,7 @@ export default {
|
||||||
domain: '',
|
domain: '',
|
||||||
supportEmail: '',
|
supportEmail: '',
|
||||||
features: {},
|
features: {},
|
||||||
|
autoResolveDuration: null,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
validations: {
|
validations: {
|
||||||
|
@ -107,6 +122,9 @@ export default {
|
||||||
locale: {
|
locale: {
|
||||||
required,
|
required,
|
||||||
},
|
},
|
||||||
|
autoResolveDuration: {
|
||||||
|
minValue: minValue(1),
|
||||||
|
},
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
...mapGetters({
|
...mapGetters({
|
||||||
|
@ -144,6 +162,7 @@ export default {
|
||||||
support_email,
|
support_email,
|
||||||
custom_email_domain_enabled,
|
custom_email_domain_enabled,
|
||||||
features,
|
features,
|
||||||
|
auto_resolve_duration,
|
||||||
} = this.getAccount(this.accountId);
|
} = this.getAccount(this.accountId);
|
||||||
|
|
||||||
Vue.config.lang = locale;
|
Vue.config.lang = locale;
|
||||||
|
@ -154,6 +173,7 @@ export default {
|
||||||
this.supportEmail = support_email;
|
this.supportEmail = support_email;
|
||||||
this.customEmailDomainEnabled = custom_email_domain_enabled;
|
this.customEmailDomainEnabled = custom_email_domain_enabled;
|
||||||
this.features = features;
|
this.features = features;
|
||||||
|
this.autoResolveDuration = auto_resolve_duration;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
// Ignore error
|
// Ignore error
|
||||||
}
|
}
|
||||||
|
@ -171,6 +191,7 @@ export default {
|
||||||
name: this.name,
|
name: this.name,
|
||||||
domain: this.domain,
|
domain: this.domain,
|
||||||
support_email: this.supportEmail,
|
support_email: this.supportEmail,
|
||||||
|
auto_resolve_duration: this.autoResolveDuration,
|
||||||
});
|
});
|
||||||
Vue.config.lang = this.locale;
|
Vue.config.lang = this.locale;
|
||||||
this.showAlert(this.$t('GENERAL_SETTINGS.UPDATE.SUCCESS'));
|
this.showAlert(this.$t('GENERAL_SETTINGS.UPDATE.SUCCESS'));
|
||||||
|
|
16
app/jobs/auto_resolve_conversations_job.rb
Normal file
16
app/jobs/auto_resolve_conversations_job.rb
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
class AutoResolveConversationsJob < ApplicationJob
|
||||||
|
queue_as :medium
|
||||||
|
|
||||||
|
def perform(conversation_id)
|
||||||
|
conversation = Conversation.find_by(id: conversation_id)
|
||||||
|
return unless conversation&.auto_resolve_duration && conversation&.open?
|
||||||
|
|
||||||
|
time_since_last_activity = Time.zone.now.to_i - conversation.last_activity_at.to_i
|
||||||
|
time_left_to_auto_resolve = conversation.auto_resolve_duration.days.to_i - time_since_last_activity
|
||||||
|
if time_left_to_auto_resolve.positive?
|
||||||
|
AutoResolveConversationsJob.set(wait_until: time_left_to_auto_resolve.seconds.from_now).perform_later(conversation_id)
|
||||||
|
else
|
||||||
|
conversation.toggle_status
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -2,16 +2,17 @@
|
||||||
#
|
#
|
||||||
# Table name: accounts
|
# Table name: accounts
|
||||||
#
|
#
|
||||||
# id :integer not null, primary key
|
# id :integer not null, primary key
|
||||||
# domain :string(100)
|
# auto_resolve_duration :integer
|
||||||
# feature_flags :integer default(0), not null
|
# domain :string(100)
|
||||||
# locale :integer default("en")
|
# feature_flags :integer default(0), not null
|
||||||
# name :string not null
|
# locale :integer default("en")
|
||||||
# settings_flags :integer default(0), not null
|
# name :string not null
|
||||||
# support_email :string(100)
|
# settings_flags :integer default(0), not null
|
||||||
|
# support_email :string(100)
|
||||||
# timezone :string default("UTC")
|
# timezone :string default("UTC")
|
||||||
# created_at :datetime not null
|
# created_at :datetime not null
|
||||||
# updated_at :datetime not null
|
# updated_at :datetime not null
|
||||||
#
|
#
|
||||||
|
|
||||||
class Account < ApplicationRecord
|
class Account < ApplicationRecord
|
||||||
|
@ -29,6 +30,7 @@ class Account < ApplicationRecord
|
||||||
}.freeze
|
}.freeze
|
||||||
|
|
||||||
validates :name, presence: true
|
validates :name, presence: true
|
||||||
|
validates :auto_resolve_duration, numericality: { greater_than_or_equal_to: 1, allow_nil: true }
|
||||||
|
|
||||||
has_many :account_users, dependent: :destroy
|
has_many :account_users, dependent: :destroy
|
||||||
has_many :agent_bot_inboxes, dependent: :destroy
|
has_many :agent_bot_inboxes, dependent: :destroy
|
||||||
|
|
|
@ -54,11 +54,13 @@ class Conversation < ApplicationRecord
|
||||||
# wanted to change this to after_update commit. But it ended up creating a loop
|
# wanted to change this to after_update commit. But it ended up creating a loop
|
||||||
# reinvestigate in future and identity the implications
|
# reinvestigate in future and identity the implications
|
||||||
after_update :notify_status_change, :create_activity
|
after_update :notify_status_change, :create_activity
|
||||||
after_create_commit :notify_conversation_creation
|
after_create_commit :notify_conversation_creation, :queue_conversation_auto_resolution_job
|
||||||
after_save :run_round_robin
|
after_save :run_round_robin
|
||||||
|
|
||||||
acts_as_taggable_on :labels
|
acts_as_taggable_on :labels
|
||||||
|
|
||||||
|
delegate :auto_resolve_duration, to: :account
|
||||||
|
|
||||||
def can_reply?
|
def can_reply?
|
||||||
return true unless inbox&.channel&.has_24_hour_messaging_window?
|
return true unless inbox&.channel&.has_24_hour_messaging_window?
|
||||||
|
|
||||||
|
@ -145,6 +147,12 @@ class Conversation < ApplicationRecord
|
||||||
dispatcher_dispatch(CONVERSATION_CREATED)
|
dispatcher_dispatch(CONVERSATION_CREATED)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def queue_conversation_auto_resolution_job
|
||||||
|
return unless auto_resolve_duration
|
||||||
|
|
||||||
|
AutoResolveConversationsJob.set(wait_until: (last_activity_at || created_at) + auto_resolve_duration.days).perform_later(id)
|
||||||
|
end
|
||||||
|
|
||||||
def self_assign?(assignee_id)
|
def self_assign?(assignee_id)
|
||||||
assignee_id.present? && Current.user&.id == assignee_id
|
assignee_id.present? && Current.user&.id == assignee_id
|
||||||
end
|
end
|
||||||
|
@ -157,15 +165,17 @@ class Conversation < ApplicationRecord
|
||||||
end
|
end
|
||||||
|
|
||||||
def create_activity
|
def create_activity
|
||||||
return unless Current.user
|
user_name = Current.user.name if Current.user.present?
|
||||||
|
status_change_activity(user_name) if saved_change_to_status?
|
||||||
user_name = Current.user.name
|
|
||||||
|
|
||||||
create_status_change_message(user_name) if saved_change_to_status?
|
|
||||||
create_assignee_change(user_name) if saved_change_to_assignee_id?
|
create_assignee_change(user_name) if saved_change_to_assignee_id?
|
||||||
create_label_change(user_name) if saved_change_to_label_list?
|
create_label_change(user_name) if saved_change_to_label_list?
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def status_change_activity(user_name)
|
||||||
|
create_status_change_message(user_name)
|
||||||
|
queue_conversation_auto_resolution_job if open?
|
||||||
|
end
|
||||||
|
|
||||||
def activity_message_params(content)
|
def activity_message_params(content)
|
||||||
{ account_id: account_id, inbox_id: inbox_id, message_type: :activity, content: content }
|
{ account_id: account_id, inbox_id: inbox_id, message_type: :activity, content: content }
|
||||||
end
|
end
|
||||||
|
@ -210,12 +220,18 @@ class Conversation < ApplicationRecord
|
||||||
end
|
end
|
||||||
|
|
||||||
def create_status_change_message(user_name)
|
def create_status_change_message(user_name)
|
||||||
content = I18n.t("conversations.activity.status.#{status}", user_name: user_name)
|
content = if user_name
|
||||||
|
I18n.t("conversations.activity.status.#{status}", user_name: user_name)
|
||||||
|
elsif resolved?
|
||||||
|
I18n.t('conversations.activity.status.auto_resolved', duration: auto_resolve_duration)
|
||||||
|
end
|
||||||
|
|
||||||
messages.create(activity_message_params(content))
|
messages.create(activity_message_params(content)) if content
|
||||||
end
|
end
|
||||||
|
|
||||||
def create_assignee_change(user_name)
|
def create_assignee_change(user_name)
|
||||||
|
return unless user_name
|
||||||
|
|
||||||
params = { assignee_name: assignee.name, user_name: user_name }.compact
|
params = { assignee_name: assignee.name, user_name: user_name }.compact
|
||||||
key = assignee_id ? 'assigned' : 'removed'
|
key = assignee_id ? 'assigned' : 'removed'
|
||||||
key = 'self_assigned' if self_assign? assignee_id
|
key = 'self_assigned' if self_assign? assignee_id
|
||||||
|
@ -225,6 +241,8 @@ class Conversation < ApplicationRecord
|
||||||
end
|
end
|
||||||
|
|
||||||
def create_label_change(user_name)
|
def create_label_change(user_name)
|
||||||
|
return unless user_name
|
||||||
|
|
||||||
previous_labels, current_labels = previous_changes[:label_list]
|
previous_labels, current_labels = previous_changes[:label_list]
|
||||||
return unless (previous_labels.is_a? Array) && (current_labels.is_a? Array)
|
return unless (previous_labels.is_a? Array) && (current_labels.is_a? Array)
|
||||||
|
|
||||||
|
|
|
@ -5,3 +5,4 @@ json.domain @account.domain
|
||||||
json.custom_email_domain_enabled @account.custom_email_domain_enabled
|
json.custom_email_domain_enabled @account.custom_email_domain_enabled
|
||||||
json.support_email @account.support_email
|
json.support_email @account.support_email
|
||||||
json.features @account.all_features
|
json.features @account.all_features
|
||||||
|
json.auto_resolve_duration @account.auto_resolve_duration
|
||||||
|
|
|
@ -32,6 +32,7 @@ ar:
|
||||||
status:
|
status:
|
||||||
resolved: "تم تحديث حالة المحادثة لـ\"مغلقة\" بواسطة %{user_name}"
|
resolved: "تم تحديث حالة المحادثة لـ\"مغلقة\" بواسطة %{user_name}"
|
||||||
open: "تم إعادة فتح المحادثة بواسطة %{user_name}"
|
open: "تم إعادة فتح المحادثة بواسطة %{user_name}"
|
||||||
|
auto_resolved: "Conversation was marked resolved by system due to %{duration} days of inactivity"
|
||||||
assignee:
|
assignee:
|
||||||
assigned: "تم إسنادها إلى %{assignee_name} بواسطة %{user_name}"
|
assigned: "تم إسنادها إلى %{assignee_name} بواسطة %{user_name}"
|
||||||
removed: "المحادثة غير مسندة بواسطة %{user_name}"
|
removed: "المحادثة غير مسندة بواسطة %{user_name}"
|
||||||
|
|
|
@ -32,6 +32,7 @@ ca:
|
||||||
status:
|
status:
|
||||||
resolved: "La conversa va ser marcada com resolta per %{user_name}"
|
resolved: "La conversa va ser marcada com resolta per %{user_name}"
|
||||||
open: "La conversa es va reobrir per %{user_name}"
|
open: "La conversa es va reobrir per %{user_name}"
|
||||||
|
auto_resolved: "Conversation was marked resolved by system due to %{duration} days of inactivity"
|
||||||
assignee:
|
assignee:
|
||||||
assigned: "Assignada a %{assignee_name} per %{user_name}"
|
assigned: "Assignada a %{assignee_name} per %{user_name}"
|
||||||
removed: "%{user_name} ha tret l'assignació de la conversa"
|
removed: "%{user_name} ha tret l'assignació de la conversa"
|
||||||
|
|
|
@ -32,6 +32,7 @@ cs:
|
||||||
status:
|
status:
|
||||||
resolved: "Konverzace byla vyřešena uživatelem %{user_name}"
|
resolved: "Konverzace byla vyřešena uživatelem %{user_name}"
|
||||||
open: "Konverzace byla znovu otevřena uživatelem %{user_name}"
|
open: "Konverzace byla znovu otevřena uživatelem %{user_name}"
|
||||||
|
auto_resolved: "Conversation was marked resolved by system due to %{duration} days of inactivity"
|
||||||
assignee:
|
assignee:
|
||||||
assigned: "Přiřazeno k %{assignee_name} uživatelem %{user_name}"
|
assigned: "Přiřazeno k %{assignee_name} uživatelem %{user_name}"
|
||||||
removed: "Konverzace zrušena uživatelem %{user_name}"
|
removed: "Konverzace zrušena uživatelem %{user_name}"
|
||||||
|
|
|
@ -32,6 +32,7 @@ da:
|
||||||
status:
|
status:
|
||||||
resolved: "Conversation was marked resolved by %{user_name}"
|
resolved: "Conversation was marked resolved by %{user_name}"
|
||||||
open: "Conversation was reopened by %{user_name}"
|
open: "Conversation was reopened by %{user_name}"
|
||||||
|
auto_resolved: "Conversation was marked resolved by system due to %{duration} days of inactivity"
|
||||||
assignee:
|
assignee:
|
||||||
assigned: "Assigned to %{assignee_name} by %{user_name}"
|
assigned: "Assigned to %{assignee_name} by %{user_name}"
|
||||||
removed: "Conversation unassigned by %{user_name}"
|
removed: "Conversation unassigned by %{user_name}"
|
||||||
|
|
|
@ -32,6 +32,7 @@ de:
|
||||||
status:
|
status:
|
||||||
resolved: "Das Gespräch wurde von gelöst gelöst %{user_name}"
|
resolved: "Das Gespräch wurde von gelöst gelöst %{user_name}"
|
||||||
open: "Das Gespräch wurde von wieder eröffnet %{user_name}"
|
open: "Das Gespräch wurde von wieder eröffnet %{user_name}"
|
||||||
|
auto_resolved: "Conversation was marked resolved by system due to %{duration} days of inactivity"
|
||||||
assignee:
|
assignee:
|
||||||
assigned: "%{user_name} von %{assignee_name} zugewiesen"
|
assigned: "%{user_name} von %{assignee_name} zugewiesen"
|
||||||
removed: "Gespräch nicht zugewiesen von %{user_name}"
|
removed: "Gespräch nicht zugewiesen von %{user_name}"
|
||||||
|
|
|
@ -32,6 +32,7 @@ el:
|
||||||
status:
|
status:
|
||||||
resolved: "Η συνομιλία έχει επιλυθεί από τον %{user_name}"
|
resolved: "Η συνομιλία έχει επιλυθεί από τον %{user_name}"
|
||||||
open: "Έγινε επαναφορά της συνομιλίας από τον %{user_name}"
|
open: "Έγινε επαναφορά της συνομιλίας από τον %{user_name}"
|
||||||
|
auto_resolved: "Conversation was marked resolved by system due to %{duration} days of inactivity"
|
||||||
assignee:
|
assignee:
|
||||||
assigned: "Ανατέθηκε στον %{assignee_name} από τον %{user_name}"
|
assigned: "Ανατέθηκε στον %{assignee_name} από τον %{user_name}"
|
||||||
removed: "Η συνομιλία σημάνθηκε ως μη ανατεθειμένη από τον %{user_name}"
|
removed: "Η συνομιλία σημάνθηκε ως μη ανατεθειμένη από τον %{user_name}"
|
||||||
|
|
|
@ -47,6 +47,7 @@ en:
|
||||||
status:
|
status:
|
||||||
resolved: "Conversation was marked resolved by %{user_name}"
|
resolved: "Conversation was marked resolved by %{user_name}"
|
||||||
open: "Conversation was reopened by %{user_name}"
|
open: "Conversation was reopened by %{user_name}"
|
||||||
|
auto_resolved: "Conversation was marked resolved by system due to %{duration} days of inactivity"
|
||||||
assignee:
|
assignee:
|
||||||
self_assigned: "%{user_name} self-assigned this conversation"
|
self_assigned: "%{user_name} self-assigned this conversation"
|
||||||
assigned: "Assigned to %{assignee_name} by %{user_name}"
|
assigned: "Assigned to %{assignee_name} by %{user_name}"
|
||||||
|
|
|
@ -32,6 +32,7 @@ es:
|
||||||
status:
|
status:
|
||||||
resolved: "La conversación fue marcada por %{user_name}"
|
resolved: "La conversación fue marcada por %{user_name}"
|
||||||
open: "La conversación fue reabierta por %{user_name}"
|
open: "La conversación fue reabierta por %{user_name}"
|
||||||
|
auto_resolved: "Conversation was marked resolved by system due to %{duration} days of inactivity"
|
||||||
assignee:
|
assignee:
|
||||||
assigned: "Asignado a %{assignee_name} por %{user_name}"
|
assigned: "Asignado a %{assignee_name} por %{user_name}"
|
||||||
removed: "Conversación no asignada por %{user_name}"
|
removed: "Conversación no asignada por %{user_name}"
|
||||||
|
|
|
@ -32,6 +32,7 @@ fa:
|
||||||
status:
|
status:
|
||||||
resolved: "مکالمه توسط اپراتور %{user_name} حل شده، اعلام شده بود"
|
resolved: "مکالمه توسط اپراتور %{user_name} حل شده، اعلام شده بود"
|
||||||
open: "گفتگو توسط اپراتور %{user_name} مجددا باز شده بود"
|
open: "گفتگو توسط اپراتور %{user_name} مجددا باز شده بود"
|
||||||
|
auto_resolved: "Conversation was marked resolved by system due to %{duration} days of inactivity"
|
||||||
assignee:
|
assignee:
|
||||||
assigned: "%{user_name} گفتگو را به %{assignee_name} اختصاص داد"
|
assigned: "%{user_name} گفتگو را به %{assignee_name} اختصاص داد"
|
||||||
removed: "گفتگو توسط اپراتور %{user_name} به وضعیت اختصاص داده نشده تغییر یافت"
|
removed: "گفتگو توسط اپراتور %{user_name} به وضعیت اختصاص داده نشده تغییر یافت"
|
||||||
|
|
|
@ -32,6 +32,7 @@ fi:
|
||||||
status:
|
status:
|
||||||
resolved: "Conversation was marked resolved by %{user_name}"
|
resolved: "Conversation was marked resolved by %{user_name}"
|
||||||
open: "Conversation was reopened by %{user_name}"
|
open: "Conversation was reopened by %{user_name}"
|
||||||
|
auto_resolved: "Conversation was marked resolved by system due to %{duration} days of inactivity"
|
||||||
assignee:
|
assignee:
|
||||||
assigned: "Assigned to %{assignee_name} by %{user_name}"
|
assigned: "Assigned to %{assignee_name} by %{user_name}"
|
||||||
removed: "Conversation unassigned by %{user_name}"
|
removed: "Conversation unassigned by %{user_name}"
|
||||||
|
|
|
@ -32,6 +32,7 @@ fr:
|
||||||
status:
|
status:
|
||||||
resolved: "La conversation a été marquée résolue par %{user_name}"
|
resolved: "La conversation a été marquée résolue par %{user_name}"
|
||||||
open: "La conversation a été ré-ouverte par %{user_name}"
|
open: "La conversation a été ré-ouverte par %{user_name}"
|
||||||
|
auto_resolved: "Conversation was marked resolved by system due to %{duration} days of inactivity"
|
||||||
assignee:
|
assignee:
|
||||||
assigned: "Assigné à %{assignee_name} par %{user_name}"
|
assigned: "Assigné à %{assignee_name} par %{user_name}"
|
||||||
removed: "Responsable de la conversation supprimé par %{user_name}"
|
removed: "Responsable de la conversation supprimé par %{user_name}"
|
||||||
|
|
|
@ -32,6 +32,7 @@ hi:
|
||||||
status:
|
status:
|
||||||
resolved: "Conversation was marked resolved by %{user_name}"
|
resolved: "Conversation was marked resolved by %{user_name}"
|
||||||
open: "Conversation was reopened by %{user_name}"
|
open: "Conversation was reopened by %{user_name}"
|
||||||
|
auto_resolved: "Conversation was marked resolved by system due to %{duration} days of inactivity"
|
||||||
assignee:
|
assignee:
|
||||||
assigned: "Assigned to %{assignee_name} by %{user_name}"
|
assigned: "Assigned to %{assignee_name} by %{user_name}"
|
||||||
removed: "Conversation unassigned by %{user_name}"
|
removed: "Conversation unassigned by %{user_name}"
|
||||||
|
|
|
@ -32,6 +32,7 @@ hu:
|
||||||
status:
|
status:
|
||||||
resolved: "Conversation was marked resolved by %{user_name}"
|
resolved: "Conversation was marked resolved by %{user_name}"
|
||||||
open: "Conversation was reopened by %{user_name}"
|
open: "Conversation was reopened by %{user_name}"
|
||||||
|
auto_resolved: "Conversation was marked resolved by system due to %{duration} days of inactivity"
|
||||||
assignee:
|
assignee:
|
||||||
assigned: "Assigned to %{assignee_name} by %{user_name}"
|
assigned: "Assigned to %{assignee_name} by %{user_name}"
|
||||||
removed: "Conversation unassigned by %{user_name}"
|
removed: "Conversation unassigned by %{user_name}"
|
||||||
|
|
|
@ -32,6 +32,7 @@ it:
|
||||||
status:
|
status:
|
||||||
resolved: "Conversazione segnata da %{user_name}"
|
resolved: "Conversazione segnata da %{user_name}"
|
||||||
open: "La conversazione è stata riaperta da %{user_name}"
|
open: "La conversazione è stata riaperta da %{user_name}"
|
||||||
|
auto_resolved: "Conversation was marked resolved by system due to %{duration} days of inactivity"
|
||||||
assignee:
|
assignee:
|
||||||
assigned: "Assegnato a %{assignee_name} da %{user_name}"
|
assigned: "Assegnato a %{assignee_name} da %{user_name}"
|
||||||
removed: "Conversazione non assegnata da %{user_name}"
|
removed: "Conversazione non assegnata da %{user_name}"
|
||||||
|
|
|
@ -32,6 +32,7 @@ ja:
|
||||||
status:
|
status:
|
||||||
resolved: "Conversation was marked resolved by %{user_name}"
|
resolved: "Conversation was marked resolved by %{user_name}"
|
||||||
open: "Conversation was reopened by %{user_name}"
|
open: "Conversation was reopened by %{user_name}"
|
||||||
|
auto_resolved: "Conversation was marked resolved by system due to %{duration} days of inactivity"
|
||||||
assignee:
|
assignee:
|
||||||
assigned: "Assigned to %{assignee_name} by %{user_name}"
|
assigned: "Assigned to %{assignee_name} by %{user_name}"
|
||||||
removed: "Conversation unassigned by %{user_name}"
|
removed: "Conversation unassigned by %{user_name}"
|
||||||
|
|
|
@ -32,6 +32,7 @@ ko:
|
||||||
status:
|
status:
|
||||||
resolved: "Conversation was marked resolved by %{user_name}"
|
resolved: "Conversation was marked resolved by %{user_name}"
|
||||||
open: "Conversation was reopened by %{user_name}"
|
open: "Conversation was reopened by %{user_name}"
|
||||||
|
auto_resolved: "Conversation was marked resolved by system due to %{duration} days of inactivity"
|
||||||
assignee:
|
assignee:
|
||||||
assigned: "Assigned to %{assignee_name} by %{user_name}"
|
assigned: "Assigned to %{assignee_name} by %{user_name}"
|
||||||
removed: "Conversation unassigned by %{user_name}"
|
removed: "Conversation unassigned by %{user_name}"
|
||||||
|
|
|
@ -32,6 +32,7 @@ ml:
|
||||||
status:
|
status:
|
||||||
resolved: "സംഭാഷണം %{user_name} പരിഹരിച്ചതായി അടയാളപ്പെടുത്തി"
|
resolved: "സംഭാഷണം %{user_name} പരിഹരിച്ചതായി അടയാളപ്പെടുത്തി"
|
||||||
open: "സംഭാഷണം %{user_name} വീണ്ടും തുറന്നു"
|
open: "സംഭാഷണം %{user_name} വീണ്ടും തുറന്നു"
|
||||||
|
auto_resolved: "Conversation was marked resolved by system due to %{duration} days of inactivity"
|
||||||
assignee:
|
assignee:
|
||||||
assigned: "%{assignee_name} %{user_name}-നെ നിയുക്തനാക്കി "
|
assigned: "%{assignee_name} %{user_name}-നെ നിയുക്തനാക്കി "
|
||||||
removed: "%{user_name} സംഭാഷണം നിയുക്തമല്ലാതാക്കി"
|
removed: "%{user_name} സംഭാഷണം നിയുക്തമല്ലാതാക്കി"
|
||||||
|
|
|
@ -32,6 +32,7 @@ nl:
|
||||||
status:
|
status:
|
||||||
resolved: "Gesprek werd gemarkeerd door %{user_name}"
|
resolved: "Gesprek werd gemarkeerd door %{user_name}"
|
||||||
open: "Gesprek werd heropend door %{user_name}"
|
open: "Gesprek werd heropend door %{user_name}"
|
||||||
|
auto_resolved: "Conversation was marked resolved by system due to %{duration} days of inactivity"
|
||||||
assignee:
|
assignee:
|
||||||
assigned: "Toegewezen aan %{assignee_name} door %{user_name}"
|
assigned: "Toegewezen aan %{assignee_name} door %{user_name}"
|
||||||
removed: "Gesprek niet toegewezen door %{user_name}"
|
removed: "Gesprek niet toegewezen door %{user_name}"
|
||||||
|
|
|
@ -32,6 +32,7 @@ pl:
|
||||||
status:
|
status:
|
||||||
resolved: "Rozmowa została oznaczona przez %{user_name}"
|
resolved: "Rozmowa została oznaczona przez %{user_name}"
|
||||||
open: "Rozmowa została ponownie otwarta przez %{user_name}"
|
open: "Rozmowa została ponownie otwarta przez %{user_name}"
|
||||||
|
auto_resolved: "Conversation was marked resolved by system due to %{duration} days of inactivity"
|
||||||
assignee:
|
assignee:
|
||||||
assigned: "Przypisane do %{assignee_name} przez %{user_name}"
|
assigned: "Przypisane do %{assignee_name} przez %{user_name}"
|
||||||
removed: "Rozmowa nieprzypisana przez %{user_name}"
|
removed: "Rozmowa nieprzypisana przez %{user_name}"
|
||||||
|
|
|
@ -32,6 +32,7 @@ pt:
|
||||||
status:
|
status:
|
||||||
resolved: "Conversa foi marcada como resolvida por %{user_name}"
|
resolved: "Conversa foi marcada como resolvida por %{user_name}"
|
||||||
open: "Conversa foi reaberta por %{user_name}"
|
open: "Conversa foi reaberta por %{user_name}"
|
||||||
|
auto_resolved: "Conversation was marked resolved by system due to %{duration} days of inactivity"
|
||||||
assignee:
|
assignee:
|
||||||
assigned: "Atribuído a %{assignee_name} por %{user_name}"
|
assigned: "Atribuído a %{assignee_name} por %{user_name}"
|
||||||
removed: "Conversa não atribuída por %{user_name}"
|
removed: "Conversa não atribuída por %{user_name}"
|
||||||
|
|
|
@ -32,6 +32,7 @@ pt:
|
||||||
status:
|
status:
|
||||||
resolved: "Conversa foi marcada como resolvida por %{user_name}"
|
resolved: "Conversa foi marcada como resolvida por %{user_name}"
|
||||||
open: "Conversa foi reaberta por %{user_name}"
|
open: "Conversa foi reaberta por %{user_name}"
|
||||||
|
auto_resolved: "Conversation was marked resolved by system due to %{duration} days of inactivity"
|
||||||
assignee:
|
assignee:
|
||||||
assigned: "Atribuído a %{assignee_name} por %{user_name}"
|
assigned: "Atribuído a %{assignee_name} por %{user_name}"
|
||||||
removed: "Conversa não atribuída por %{user_name}"
|
removed: "Conversa não atribuída por %{user_name}"
|
||||||
|
|
|
@ -32,6 +32,7 @@ ro:
|
||||||
status:
|
status:
|
||||||
resolved: "Conversația a fost marcată de %{user_name}"
|
resolved: "Conversația a fost marcată de %{user_name}"
|
||||||
open: "Conversația a fost redeschisă de %{user_name}"
|
open: "Conversația a fost redeschisă de %{user_name}"
|
||||||
|
auto_resolved: "Conversation was marked resolved by system due to %{duration} days of inactivity"
|
||||||
assignee:
|
assignee:
|
||||||
assigned: "Atribuit lui %{assignee_name} de %{user_name}"
|
assigned: "Atribuit lui %{assignee_name} de %{user_name}"
|
||||||
removed: "Conversație neasociată de %{user_name}"
|
removed: "Conversație neasociată de %{user_name}"
|
||||||
|
|
|
@ -32,6 +32,7 @@ ru:
|
||||||
status:
|
status:
|
||||||
resolved: "%{user_name} завершил диалог"
|
resolved: "%{user_name} завершил диалог"
|
||||||
open: "%{user_name} открыл заново диалог"
|
open: "%{user_name} открыл заново диалог"
|
||||||
|
auto_resolved: "Conversation was marked resolved by system due to %{duration} days of inactivity"
|
||||||
assignee:
|
assignee:
|
||||||
assigned: "%{user_name} назначил %{assignee_name} ответственным"
|
assigned: "%{user_name} назначил %{assignee_name} ответственным"
|
||||||
removed: "Ответственный снят %{user_name}"
|
removed: "Ответственный снят %{user_name}"
|
||||||
|
|
|
@ -32,6 +32,7 @@ sk:
|
||||||
status:
|
status:
|
||||||
resolved: "Conversation was marked resolved by %{user_name}"
|
resolved: "Conversation was marked resolved by %{user_name}"
|
||||||
open: "Conversation was reopened by %{user_name}"
|
open: "Conversation was reopened by %{user_name}"
|
||||||
|
auto_resolved: "Conversation was marked resolved by system due to %{duration} days of inactivity"
|
||||||
assignee:
|
assignee:
|
||||||
assigned: "Assigned to %{assignee_name} by %{user_name}"
|
assigned: "Assigned to %{assignee_name} by %{user_name}"
|
||||||
removed: "Conversation unassigned by %{user_name}"
|
removed: "Conversation unassigned by %{user_name}"
|
||||||
|
|
|
@ -32,6 +32,7 @@ sv:
|
||||||
status:
|
status:
|
||||||
resolved: "Konversationen har markerats som löst av %{user_name}"
|
resolved: "Konversationen har markerats som löst av %{user_name}"
|
||||||
open: "Konversationen öppnades igen av %{user_name}"
|
open: "Konversationen öppnades igen av %{user_name}"
|
||||||
|
auto_resolved: "Conversation was marked resolved by system due to %{duration} days of inactivity"
|
||||||
assignee:
|
assignee:
|
||||||
assigned: "Tilldelad till %{assignee_name} av %{user_name}"
|
assigned: "Tilldelad till %{assignee_name} av %{user_name}"
|
||||||
removed: "Konversation otilldelad av %{user_name}"
|
removed: "Konversation otilldelad av %{user_name}"
|
||||||
|
|
|
@ -32,6 +32,7 @@ ta:
|
||||||
status:
|
status:
|
||||||
resolved: "உரையாடலுக்கு %{user_name} தீர்வு வழங்கியுள்ளார்"
|
resolved: "உரையாடலுக்கு %{user_name} தீர்வு வழங்கியுள்ளார்"
|
||||||
open: "உரையாடலை %{user_name} மீண்டும் திறந்துள்ளார்"
|
open: "உரையாடலை %{user_name} மீண்டும் திறந்துள்ளார்"
|
||||||
|
auto_resolved: "Conversation was marked resolved by system due to %{duration} days of inactivity"
|
||||||
assignee:
|
assignee:
|
||||||
assigned: "%{user_name} இதை %{assignee_name}க்கு ஒதுக்கியுள்ளார்"
|
assigned: "%{user_name} இதை %{assignee_name}க்கு ஒதுக்கியுள்ளார்"
|
||||||
removed: "%{user_name} இதை ஒதுக்க படாத உரையாடளாக்கியுள்ளார்"
|
removed: "%{user_name} இதை ஒதுக்க படாத உரையாடளாக்கியுள்ளார்"
|
||||||
|
|
|
@ -32,6 +32,7 @@ th:
|
||||||
status:
|
status:
|
||||||
resolved: "Conversation was marked resolved by %{user_name}"
|
resolved: "Conversation was marked resolved by %{user_name}"
|
||||||
open: "Conversation was reopened by %{user_name}"
|
open: "Conversation was reopened by %{user_name}"
|
||||||
|
auto_resolved: "Conversation was marked resolved by system due to %{duration} days of inactivity"
|
||||||
assignee:
|
assignee:
|
||||||
assigned: "Assigned to %{assignee_name} by %{user_name}"
|
assigned: "Assigned to %{assignee_name} by %{user_name}"
|
||||||
removed: "Conversation unassigned by %{user_name}"
|
removed: "Conversation unassigned by %{user_name}"
|
||||||
|
|
|
@ -32,6 +32,7 @@ tr:
|
||||||
status:
|
status:
|
||||||
resolved: "Conversation was marked resolved by %{user_name}"
|
resolved: "Conversation was marked resolved by %{user_name}"
|
||||||
open: "Conversation was reopened by %{user_name}"
|
open: "Conversation was reopened by %{user_name}"
|
||||||
|
auto_resolved: "Conversation was marked resolved by system due to %{duration} days of inactivity"
|
||||||
assignee:
|
assignee:
|
||||||
assigned: "Assigned to %{assignee_name} by %{user_name}"
|
assigned: "Assigned to %{assignee_name} by %{user_name}"
|
||||||
removed: "Conversation unassigned by %{user_name}"
|
removed: "Conversation unassigned by %{user_name}"
|
||||||
|
|
|
@ -32,6 +32,7 @@ uk:
|
||||||
status:
|
status:
|
||||||
resolved: "Conversation was marked resolved by %{user_name}"
|
resolved: "Conversation was marked resolved by %{user_name}"
|
||||||
open: "Conversation was reopened by %{user_name}"
|
open: "Conversation was reopened by %{user_name}"
|
||||||
|
auto_resolved: "Conversation was marked resolved by system due to %{duration} days of inactivity"
|
||||||
assignee:
|
assignee:
|
||||||
assigned: "Assigned to %{assignee_name} by %{user_name}"
|
assigned: "Assigned to %{assignee_name} by %{user_name}"
|
||||||
removed: "Conversation unassigned by %{user_name}"
|
removed: "Conversation unassigned by %{user_name}"
|
||||||
|
|
|
@ -32,6 +32,7 @@ vi:
|
||||||
status:
|
status:
|
||||||
resolved: "Cuộc trò chuyện được đánh dấu là đã giải quyết bởi %{user_name}"
|
resolved: "Cuộc trò chuyện được đánh dấu là đã giải quyết bởi %{user_name}"
|
||||||
open: "Cuộc trò chuyện đã được mở lại bởi %{user_name}"
|
open: "Cuộc trò chuyện đã được mở lại bởi %{user_name}"
|
||||||
|
auto_resolved: "Conversation was marked resolved by system due to %{duration} days of inactivity"
|
||||||
assignee:
|
assignee:
|
||||||
assigned: "Chỉ định %{assignee_name} bởi %{user_name}"
|
assigned: "Chỉ định %{assignee_name} bởi %{user_name}"
|
||||||
removed: "Cuộc hội thoại chưa được chỉ định bởi %{user_name}"
|
removed: "Cuộc hội thoại chưa được chỉ định bởi %{user_name}"
|
||||||
|
|
|
@ -46,7 +46,8 @@ zh-TW:
|
||||||
activity:
|
activity:
|
||||||
status:
|
status:
|
||||||
resolved: "被%{user_name}標記的對話已解決。"
|
resolved: "被%{user_name}標記的對話已解決。"
|
||||||
open: "被%{user_name}恢復對話。"
|
open: "被%{user_name}恢復對話。"
|
||||||
|
auto_resolved: "Conversation was marked resolved by system due to %{duration} days of inactivity"
|
||||||
assignee:
|
assignee:
|
||||||
assigned: "被%{user_name}分配給%{assignee_name}。"
|
assigned: "被%{user_name}分配給%{assignee_name}。"
|
||||||
removed: "對話被%{user_name}設定成未分配。"
|
removed: "對話被%{user_name}設定成未分配。"
|
||||||
|
|
|
@ -32,6 +32,7 @@ zh-CN:
|
||||||
status:
|
status:
|
||||||
resolved: "对话被标记由 %{user_name} 解决"
|
resolved: "对话被标记由 %{user_name} 解决"
|
||||||
open: "对话被 %{user_name} 重新打开"
|
open: "对话被 %{user_name} 重新打开"
|
||||||
|
auto_resolved: "Conversation was marked resolved by system due to %{duration} days of inactivity"
|
||||||
assignee:
|
assignee:
|
||||||
assigned: "由 %{assignee_name} 分配给 %{user_name}"
|
assigned: "由 %{assignee_name} 分配给 %{user_name}"
|
||||||
removed: "对话未被 %{user_name} 分配"
|
removed: "对话未被 %{user_name} 分配"
|
||||||
|
|
|
@ -32,6 +32,7 @@ zh-CN:
|
||||||
status:
|
status:
|
||||||
resolved: "对话被标记由 %{user_name} 解决"
|
resolved: "对话被标记由 %{user_name} 解决"
|
||||||
open: "对话被 %{user_name} 重新打开"
|
open: "对话被 %{user_name} 重新打开"
|
||||||
|
auto_resolved: "Conversation was marked resolved by system due to %{duration} days of inactivity"
|
||||||
assignee:
|
assignee:
|
||||||
assigned: "由 %{assignee_name} 分配给 %{user_name}"
|
assigned: "由 %{assignee_name} 分配给 %{user_name}"
|
||||||
removed: "对话未被 %{user_name} 分配"
|
removed: "对话未被 %{user_name} 分配"
|
||||||
|
|
|
@ -47,6 +47,7 @@ zh_TW:
|
||||||
status:
|
status:
|
||||||
resolved: "被%{user_name}標記的對話已解決。"
|
resolved: "被%{user_name}標記的對話已解決。"
|
||||||
open: "被%{user_name}恢復對話。"
|
open: "被%{user_name}恢復對話。"
|
||||||
|
auto_resolved: "Conversation was marked resolved by system due to %{duration} days of inactivity"
|
||||||
assignee:
|
assignee:
|
||||||
assigned: "被%{user_name}分配給%{assignee_name}。"
|
assigned: "被%{user_name}分配給%{assignee_name}。"
|
||||||
removed: "對話被%{user_name}設定成未分配。"
|
removed: "對話被%{user_name}設定成未分配。"
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
class AddAutoResolveDurationToAccount < ActiveRecord::Migration[6.0]
|
||||||
|
def change
|
||||||
|
add_column :accounts, :auto_resolve_duration, :integer
|
||||||
|
end
|
||||||
|
end
|
|
@ -49,6 +49,7 @@ ActiveRecord::Schema.define(version: 2020_10_27_135006) do
|
||||||
t.string "support_email", limit: 100
|
t.string "support_email", limit: 100
|
||||||
t.integer "settings_flags", default: 0, null: false
|
t.integer "settings_flags", default: 0, null: false
|
||||||
t.integer "feature_flags", default: 0, null: false
|
t.integer "feature_flags", default: 0, null: false
|
||||||
|
t.integer "auto_resolve_duration"
|
||||||
t.string "timezone", default: "UTC"
|
t.string "timezone", default: "UTC"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -130,6 +130,8 @@ RSpec.describe 'Accounts API', type: :request do
|
||||||
|
|
||||||
context 'when it is an authenticated user' do
|
context 'when it is an authenticated user' do
|
||||||
it 'shows an account' do
|
it 'shows an account' do
|
||||||
|
account.update(auto_resolve_duration: 30)
|
||||||
|
|
||||||
get "/api/v1/accounts/#{account.id}",
|
get "/api/v1/accounts/#{account.id}",
|
||||||
headers: admin.create_new_auth_token,
|
headers: admin.create_new_auth_token,
|
||||||
as: :json
|
as: :json
|
||||||
|
@ -139,6 +141,7 @@ RSpec.describe 'Accounts API', type: :request do
|
||||||
expect(response.body).to include(account.locale)
|
expect(response.body).to include(account.locale)
|
||||||
expect(response.body).to include(account.domain)
|
expect(response.body).to include(account.domain)
|
||||||
expect(response.body).to include(account.support_email)
|
expect(response.body).to include(account.support_email)
|
||||||
|
expect(response.body).to include(account.auto_resolve_duration.to_s)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -169,7 +172,8 @@ RSpec.describe 'Accounts API', type: :request do
|
||||||
name: 'New Name',
|
name: 'New Name',
|
||||||
locale: 'en',
|
locale: 'en',
|
||||||
domain: 'example.com',
|
domain: 'example.com',
|
||||||
support_email: 'care@example.com'
|
support_email: 'care@example.com',
|
||||||
|
auto_resolve_duration: 40
|
||||||
}
|
}
|
||||||
|
|
||||||
it 'modifies an account' do
|
it 'modifies an account' do
|
||||||
|
@ -183,6 +187,7 @@ RSpec.describe 'Accounts API', type: :request do
|
||||||
expect(account.reload.locale).to eq(params[:locale])
|
expect(account.reload.locale).to eq(params[:locale])
|
||||||
expect(account.reload.domain).to eq(params[:domain])
|
expect(account.reload.domain).to eq(params[:domain])
|
||||||
expect(account.reload.support_email).to eq(params[:support_email])
|
expect(account.reload.support_email).to eq(params[:support_email])
|
||||||
|
expect(account.reload.auto_resolve_duration).to eq(params[:auto_resolve_duration])
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
34
spec/jobs/auto_resolve_conversations_job_spec.rb
Normal file
34
spec/jobs/auto_resolve_conversations_job_spec.rb
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
require 'rails_helper'
|
||||||
|
|
||||||
|
RSpec.describe AutoResolveConversationsJob, type: :job do
|
||||||
|
subject(:job) { described_class.perform_later(conversation.id) }
|
||||||
|
|
||||||
|
let!(:account) { create(:account) }
|
||||||
|
let!(:conversation) { create(:conversation, account: account) }
|
||||||
|
|
||||||
|
it 'queues the job' do
|
||||||
|
expect { job }.to have_enqueued_job(described_class)
|
||||||
|
.with(conversation.id)
|
||||||
|
.on_queue('medium')
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'does nothing when there is no auto resolve duration' do
|
||||||
|
described_class.perform_now(conversation.id)
|
||||||
|
expect(conversation.reload.status).to eq('open')
|
||||||
|
end
|
||||||
|
|
||||||
|
it 're-queues the job if there is still time left to allow inactivity' do
|
||||||
|
account.update(auto_resolve_duration: 10)
|
||||||
|
conversation.update(last_activity_at: 3.days.ago)
|
||||||
|
expect { described_class.perform_now(conversation.id) }.to have_enqueued_job(described_class)
|
||||||
|
.with(conversation.id)
|
||||||
|
.on_queue('medium')
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'resolves the issue if time of inactivity is more than the auto resolve duration' do
|
||||||
|
account.update(auto_resolve_duration: 10)
|
||||||
|
conversation.update(last_activity_at: 13.days.ago)
|
||||||
|
described_class.perform_now(conversation.id)
|
||||||
|
expect(conversation.reload.status).to eq('resolved')
|
||||||
|
end
|
||||||
|
end
|
|
@ -4,6 +4,7 @@ require 'rails_helper'
|
||||||
|
|
||||||
RSpec.describe Account do
|
RSpec.describe Account do
|
||||||
it { is_expected.to validate_presence_of(:name) }
|
it { is_expected.to validate_presence_of(:name) }
|
||||||
|
it { is_expected.to validate_numericality_of(:auto_resolve_duration).is_greater_than_or_equal_to(1) }
|
||||||
|
|
||||||
it { is_expected.to have_many(:users).through(:account_users) }
|
it { is_expected.to have_many(:users).through(:account_users) }
|
||||||
it { is_expected.to have_many(:account_users) }
|
it { is_expected.to have_many(:account_users) }
|
||||||
|
|
|
@ -44,6 +44,19 @@ RSpec.describe Conversation, type: :model do
|
||||||
expect(Rails.configuration.dispatcher).to have_received(:dispatch)
|
expect(Rails.configuration.dispatcher).to have_received(:dispatch)
|
||||||
.with(described_class::CONVERSATION_CREATED, kind_of(Time), conversation: conversation)
|
.with(described_class::CONVERSATION_CREATED, kind_of(Time), conversation: conversation)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it 'queues AutoResolveConversationsJob post creation if auto resolve duration present' do
|
||||||
|
account.update(auto_resolve_duration: 30)
|
||||||
|
expect do
|
||||||
|
create(
|
||||||
|
:conversation,
|
||||||
|
account: account,
|
||||||
|
contact: create(:contact, account: account),
|
||||||
|
inbox: inbox,
|
||||||
|
assignee: nil
|
||||||
|
)
|
||||||
|
end.to have_enqueued_job(AutoResolveConversationsJob)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe '.after_update' do
|
describe '.after_update' do
|
||||||
|
@ -94,6 +107,26 @@ RSpec.describe Conversation, type: :model do
|
||||||
expect(conversation.messages.pluck(:content)).to include("Assigned to #{new_assignee.name} by #{old_assignee.name}")
|
expect(conversation.messages.pluck(:content)).to include("Assigned to #{new_assignee.name} by #{old_assignee.name}")
|
||||||
expect(conversation.messages.pluck(:content)).to include("#{old_assignee.name} added #{label.title}")
|
expect(conversation.messages.pluck(:content)).to include("#{old_assignee.name} added #{label.title}")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it 'adds a message for system auto resolution if marked resolved by system' do
|
||||||
|
conversation2 = create(:conversation, status: 'open', account: account, assignee: old_assignee)
|
||||||
|
account.update(auto_resolve_duration: 40)
|
||||||
|
Current.user = nil
|
||||||
|
conversation2.update(status: :resolved)
|
||||||
|
system_resolved_message = "Conversation was marked resolved by system due to #{account.auto_resolve_duration} days of inactivity"
|
||||||
|
expect(conversation2.messages.pluck(:content)).to include(system_resolved_message)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'does not trigger AutoResolutionJob if conversation reopened and account does not have auto resolve duration' do
|
||||||
|
expect { conversation.update(status: :open) }
|
||||||
|
.not_to have_enqueued_job(AutoResolveConversationsJob).with(conversation.id)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'does trigger AutoResolutionJob if conversation reopened and account has auto resolve duration' do
|
||||||
|
account.update(auto_resolve_duration: 40)
|
||||||
|
expect { conversation.update(status: :open) }
|
||||||
|
.to have_enqueued_job(AutoResolveConversationsJob).with(conversation.id)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe '#round robin' do
|
describe '#round robin' do
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue