escalation_examples.rb 43 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147
  1. RSpec.shared_examples 'Ticket::Escalation' do
  2. describe '#update_escalation_information callback' do
  3. context 'with standard incoming email with active SLA' do
  4. subject(:ticket) { create(:ticket, created_at: '2013-03-21 09:30:00 UTC', updated_at: '2013-03-21 09:30:00 UTC') }
  5. let(:calendar) do
  6. create(:calendar,
  7. business_hours: {
  8. mon: {
  9. active: true,
  10. timeframes: [ ['08:00', '18:00'] ]
  11. },
  12. tue: {
  13. active: true,
  14. timeframes: [ ['08:00', '18:00'] ]
  15. },
  16. wed: {
  17. active: true,
  18. timeframes: [ ['08:00', '18:00'] ]
  19. },
  20. thu: {
  21. active: true,
  22. timeframes: [ ['08:00', '18:00'] ]
  23. },
  24. fri: {
  25. active: true,
  26. timeframes: [ ['08:00', '18:00'] ]
  27. },
  28. sat: {
  29. active: false,
  30. timeframes: [ ['08:00', '17:00'] ]
  31. },
  32. sun: {
  33. active: false,
  34. timeframes: [ ['08:00', '17:00'] ]
  35. },
  36. })
  37. end
  38. let(:sla) { create(:sla, calendar: calendar, first_response_time: 60, update_time: 120, solution_time: 180) }
  39. let(:article) { create(:'ticket/article', :inbound_email, ticket: ticket, created_at: '2013-03-21 09:30:00 UTC', updated_at: '2013-03-21 09:30:00 UTC') }
  40. before do
  41. sla
  42. ticket
  43. article
  44. ticket.reload
  45. end
  46. it 'calculates escalation_at attributes' do
  47. expect(ticket.escalation_at.gmtime.to_s).to eq('2013-03-21 10:30:00 UTC')
  48. expect(ticket.first_response_escalation_at.gmtime.to_s).to eq('2013-03-21 10:30:00 UTC')
  49. expect(ticket.first_response_at).to be_nil
  50. expect(ticket.first_response_in_min).to be_nil
  51. expect(ticket.first_response_diff_in_min).to be_nil
  52. expect(ticket.update_escalation_at.gmtime.to_s).to eq('2013-03-21 11:30:00 UTC')
  53. expect(ticket.update_in_min).to be_nil
  54. expect(ticket.update_diff_in_min).to be_nil
  55. expect(ticket.close_escalation_at.gmtime.to_s).to eq('2013-03-21 12:30:00 UTC')
  56. expect(ticket.close_in_min).to be_nil
  57. expect(ticket.close_diff_in_min).to be_nil
  58. end
  59. context 'with first response time resolved by answer + state pending reminder' do
  60. before do
  61. ticket.update(state: Ticket::State.find_by(name: 'pending reminder'))
  62. create(:'ticket/article', :outbound_email, ticket: ticket, created_at: '2013-03-21 09:45:00 UTC', updated_at: '2013-03-21 09:45:00 UTC')
  63. end
  64. it 'does set first_response_diff_in_min' do
  65. expect(ticket.reload.first_response_diff_in_min).to eq(45)
  66. end
  67. end
  68. context 'with first response in time' do
  69. before do
  70. ticket.update!(
  71. first_response_at: '2013-03-21 10:00:00 UTC',
  72. )
  73. ticket.reload
  74. end
  75. it 'calculates escalation_at attributes' do
  76. expect(ticket.escalation_at.gmtime.to_s).to eq('2013-03-21 11:30:00 UTC')
  77. expect(ticket.first_response_escalation_at).to be_nil
  78. expect(ticket.first_response_at.gmtime.to_s).to eq('2013-03-21 10:00:00 UTC')
  79. expect(ticket.first_response_in_min).to eq(30)
  80. expect(ticket.first_response_diff_in_min).to eq(30)
  81. expect(ticket.update_escalation_at.gmtime.to_s).to eq('2013-03-21 11:30:00 UTC')
  82. expect(ticket.update_in_min).to be_nil
  83. expect(ticket.update_diff_in_min).to be_nil
  84. expect(ticket.close_escalation_at.gmtime.to_s).to eq('2013-03-21 12:30:00 UTC')
  85. expect(ticket.close_in_min).to be_nil
  86. expect(ticket.close_diff_in_min).to be_nil
  87. end
  88. end
  89. context 'with first response over time' do
  90. before do
  91. ticket.update!(
  92. first_response_at: '2013-03-21 14:00:00 UTC',
  93. )
  94. ticket.reload
  95. end
  96. it 'calculates escalation_at attributes' do
  97. expect(ticket.escalation_at.gmtime.to_s).to eq('2013-03-21 11:30:00 UTC')
  98. expect(ticket.first_response_escalation_at).to be_nil
  99. expect(ticket.first_response_at.gmtime.to_s).to eq('2013-03-21 14:00:00 UTC')
  100. expect(ticket.first_response_in_min).to eq(270)
  101. expect(ticket.first_response_diff_in_min).to eq(-210)
  102. expect(ticket.update_escalation_at.gmtime.to_s).to eq('2013-03-21 11:30:00 UTC')
  103. expect(ticket.update_in_min).to be_nil
  104. expect(ticket.update_diff_in_min).to be_nil
  105. expect(ticket.close_escalation_at.gmtime.to_s).to eq('2013-03-21 12:30:00 UTC')
  106. expect(ticket.close_in_min).to be_nil
  107. expect(ticket.close_diff_in_min).to be_nil
  108. end
  109. end
  110. context 'with first response over time and update time in time' do
  111. before do
  112. # set first response over time
  113. ticket.update!(
  114. first_response_at: '2013-03-21 14:00:00 UTC',
  115. )
  116. ticket.reload
  117. # set update time in time
  118. ticket.update!(
  119. last_contact_agent_at: '2013-03-21 11:00:00 UTC',
  120. )
  121. ticket.reload
  122. end
  123. it 'calculates escalation_at attributes' do
  124. expect(ticket.escalation_at.gmtime.to_s).to eq('2013-03-21 12:30:00 UTC')
  125. expect(ticket.first_response_escalation_at).to be_nil
  126. expect(ticket.first_response_at.gmtime.to_s).to eq('2013-03-21 14:00:00 UTC')
  127. expect(ticket.first_response_in_min).to eq(270)
  128. expect(ticket.first_response_diff_in_min).to eq(-210)
  129. expect(ticket.update_escalation_at).to be_nil
  130. expect(ticket.update_in_min).to eq(90)
  131. expect(ticket.update_diff_in_min).to eq(30)
  132. expect(ticket.close_escalation_at.gmtime.to_s).to eq('2013-03-21 12:30:00 UTC')
  133. expect(ticket.close_in_min).to be_nil
  134. expect(ticket.close_diff_in_min).to be_nil
  135. end
  136. end
  137. context 'with first response over time and update time over time' do
  138. before do
  139. # set first response over time
  140. ticket.update!(
  141. first_response_at: '2013-03-21 14:00:00 UTC',
  142. )
  143. ticket.reload
  144. # set update time over time
  145. ticket.update!(
  146. last_contact_agent_at: '2013-03-21 12:00:00 UTC',
  147. )
  148. ticket.reload
  149. end
  150. it 'calculates escalation_at attributes' do
  151. expect(ticket.escalation_at.gmtime.to_s).to eq('2013-03-21 12:30:00 UTC')
  152. expect(ticket.first_response_escalation_at).to be_nil
  153. expect(ticket.first_response_at.gmtime.to_s).to eq('2013-03-21 14:00:00 UTC')
  154. expect(ticket.first_response_in_min).to eq(270)
  155. expect(ticket.first_response_diff_in_min).to eq(-210)
  156. expect(ticket.update_escalation_at).to be_nil
  157. expect(ticket.update_in_min).to eq(150)
  158. expect(ticket.update_diff_in_min).to eq(-30)
  159. expect(ticket.close_escalation_at.gmtime.to_s).to eq('2013-03-21 12:30:00 UTC')
  160. expect(ticket.close_in_min).to be_nil
  161. expect(ticket.close_diff_in_min).to be_nil
  162. end
  163. end
  164. context 'with first response over time and update time over time and customer reply' do
  165. before do
  166. # set first response over time
  167. ticket.update!(
  168. first_response_at: '2013-03-21 14:00:00 UTC',
  169. )
  170. ticket.reload
  171. # set update time over time
  172. ticket.update!(
  173. last_contact_agent_at: '2013-03-21 12:00:00 UTC',
  174. )
  175. ticket.reload
  176. # set update time over time
  177. ticket.update!(
  178. last_contact_customer_at: '2013-03-21 12:05:00 UTC',
  179. )
  180. ticket.reload
  181. end
  182. it 'calculates escalation_at attributes' do
  183. expect(ticket.escalation_at.gmtime.to_s).to eq('2013-03-21 12:30:00 UTC')
  184. expect(ticket.first_response_escalation_at).to be_nil
  185. expect(ticket.first_response_at.gmtime.to_s).to eq('2013-03-21 14:00:00 UTC')
  186. expect(ticket.first_response_in_min).to eq(270)
  187. expect(ticket.first_response_diff_in_min).to eq(-210)
  188. expect(ticket.update_escalation_at.gmtime.to_s).to eq('2013-03-21 14:05:00 UTC')
  189. expect(ticket.update_in_min).to eq(150)
  190. expect(ticket.update_diff_in_min).to eq(-30)
  191. expect(ticket.close_escalation_at.gmtime.to_s).to eq('2013-03-21 12:30:00 UTC')
  192. expect(ticket.close_in_min).to be_nil
  193. expect(ticket.close_diff_in_min).to be_nil
  194. end
  195. end
  196. context 'with first response over time and update time over time and customer reply with agent response' do
  197. before do
  198. # set first response over time
  199. ticket.update!(
  200. first_response_at: '2013-03-21 14:00:00 UTC',
  201. )
  202. ticket.reload
  203. # set update time over time
  204. ticket.update!(
  205. last_contact_agent_at: '2013-03-21 12:00:00 UTC',
  206. )
  207. ticket.reload
  208. # set update time over time
  209. ticket.update!(
  210. last_contact_customer_at: '2013-03-21 12:05:00 UTC',
  211. )
  212. ticket.reload
  213. # set update time over time
  214. ticket.update!(
  215. last_contact_agent_at: '2013-03-21 12:10:00 UTC',
  216. )
  217. ticket.reload
  218. end
  219. it 'calculates escalation_at attributes' do
  220. expect(ticket.escalation_at.gmtime.to_s).to eq('2013-03-21 12:30:00 UTC')
  221. expect(ticket.first_response_escalation_at).to be_nil
  222. expect(ticket.first_response_at.gmtime.to_s).to eq('2013-03-21 14:00:00 UTC')
  223. expect(ticket.first_response_in_min).to eq(270)
  224. expect(ticket.first_response_diff_in_min).to eq(-210)
  225. expect(ticket.update_escalation_at).to be_nil
  226. expect(ticket.update_in_min).to eq(150)
  227. expect(ticket.update_diff_in_min).to eq(-30)
  228. expect(ticket.close_escalation_at.gmtime.to_s).to eq('2013-03-21 12:30:00 UTC')
  229. expect(ticket.close_in_min).to be_nil
  230. expect(ticket.close_diff_in_min).to be_nil
  231. end
  232. end
  233. context 'with first response over time and update time over time and customer reply with agent response and closed in time' do
  234. before do
  235. # set first response over time
  236. ticket.update!(
  237. first_response_at: '2013-03-21 14:00:00 UTC',
  238. )
  239. ticket.reload
  240. # set update time over time
  241. ticket.update!(
  242. last_contact_agent_at: '2013-03-21 12:00:00 UTC',
  243. )
  244. ticket.reload
  245. # set update time over time
  246. ticket.update!(
  247. last_contact_customer_at: '2013-03-21 12:05:00 UTC',
  248. )
  249. ticket.reload
  250. # set update time over time
  251. ticket.update!(
  252. last_contact_agent_at: '2013-03-21 12:10:00 UTC',
  253. )
  254. ticket.reload
  255. # set close time in time
  256. ticket.update!(
  257. close_at: '2013-03-21 11:30:00 UTC',
  258. )
  259. ticket.reload
  260. end
  261. it 'calculates escalation_at attributes' do
  262. # straight escalation after closing
  263. expect(ticket.escalation_at).to be_nil
  264. expect(ticket.first_response_escalation_at).to be_nil
  265. expect(ticket.first_response_at.gmtime.to_s).to eq('2013-03-21 14:00:00 UTC')
  266. expect(ticket.first_response_in_min).to eq(270)
  267. expect(ticket.first_response_diff_in_min).to eq(-210)
  268. expect(ticket.update_escalation_at).to be_nil
  269. expect(ticket.update_in_min).to eq(150)
  270. expect(ticket.update_diff_in_min).to eq(-30)
  271. expect(ticket.close_escalation_at).to be_nil
  272. expect(ticket.close_in_min).to eq(120)
  273. expect(ticket.close_diff_in_min).to eq(60)
  274. end
  275. end
  276. context 'with first response over time and update time over time and customer reply with agent response and closed over time' do
  277. before do
  278. # set first response over time
  279. ticket.update!(
  280. first_response_at: '2013-03-21 14:00:00 UTC',
  281. )
  282. ticket.reload
  283. # set update time over time
  284. ticket.update!(
  285. last_contact_agent_at: '2013-03-21 12:00:00 UTC',
  286. )
  287. ticket.reload
  288. # set update time over time
  289. ticket.update!(
  290. last_contact_customer_at: '2013-03-21 12:05:00 UTC',
  291. )
  292. ticket.reload
  293. # set update time over time
  294. ticket.update!(
  295. last_contact_agent_at: '2013-03-21 12:10:00 UTC',
  296. )
  297. ticket.reload
  298. # set close time over time
  299. ticket.update!(
  300. close_at: '2013-03-21 13:00:00 UTC',
  301. )
  302. ticket.reload
  303. end
  304. it 'calculates escalation_at attributes' do
  305. expect(ticket.escalation_at).to be_nil
  306. expect(ticket.first_response_escalation_at).to be_nil
  307. expect(ticket.first_response_at.gmtime.to_s).to eq('2013-03-21 14:00:00 UTC')
  308. expect(ticket.first_response_in_min).to eq(270)
  309. expect(ticket.first_response_diff_in_min).to eq(-210)
  310. expect(ticket.update_escalation_at).to be_nil
  311. expect(ticket.update_in_min).to eq(150)
  312. expect(ticket.update_diff_in_min).to eq(-30)
  313. expect(ticket.close_escalation_at).to be_nil
  314. expect(ticket.close_in_min).to eq(210)
  315. expect(ticket.close_diff_in_min).to eq(-30)
  316. end
  317. end
  318. end
  319. context 'when SLA no longer matches' do
  320. subject(:ticket) { create(:ticket, priority: priorty_matching, created_at: '2013-03-21 09:30:00 UTC', updated_at: '2013-03-21 09:30:00 UTC') }
  321. let(:priorty_matching) { create(:'ticket/priority') }
  322. let(:priorty_not_matching) { create(:'ticket/priority') }
  323. let(:calendar) do
  324. create(:calendar,
  325. business_hours: {
  326. mon: {
  327. active: true,
  328. timeframes: [ ['09:00', '17:00'] ]
  329. },
  330. tue: {
  331. active: true,
  332. timeframes: [ ['09:00', '17:00'] ]
  333. },
  334. wed: {
  335. active: true,
  336. timeframes: [ ['09:00', '17:00'] ]
  337. },
  338. thu: {
  339. active: true,
  340. timeframes: [ ['09:00', '17:00'] ]
  341. },
  342. fri: {
  343. active: true,
  344. timeframes: [ ['09:00', '17:00'] ]
  345. },
  346. sat: {
  347. active: false,
  348. timeframes: [ ['08:00', '17:00'] ]
  349. },
  350. sun: {
  351. active: false,
  352. timeframes: [ ['08:00', '17:00'] ]
  353. },
  354. })
  355. end
  356. let(:sla) do
  357. create(:sla,
  358. calendar: calendar,
  359. condition: {
  360. 'ticket.priority_id' => {
  361. operator: 'is',
  362. value: priorty_matching.id.to_s,
  363. },
  364. },
  365. first_response_time: 60,
  366. update_time: 180,
  367. solution_time: 240)
  368. end
  369. it 'removes/resets the escalation attributes' do
  370. sla
  371. ticket.reload # read as: ticket; ticket.reload
  372. expect(ticket.escalation_at.gmtime.to_s).to eq('2013-03-21 10:30:00 UTC')
  373. expect(ticket.first_response_escalation_at.gmtime.to_s).to eq('2013-03-21 10:30:00 UTC')
  374. expect(ticket.first_response_at).to be_nil
  375. expect(ticket.first_response_in_min).to be_nil
  376. expect(ticket.first_response_diff_in_min).to be_nil
  377. expect(ticket.update_escalation_at).to be_nil
  378. expect(ticket.update_in_min).to be_nil
  379. expect(ticket.update_diff_in_min).to be_nil
  380. expect(ticket.close_escalation_at.gmtime.to_s).to eq('2013-03-21 13:30:00 UTC')
  381. expect(ticket.close_in_min).to be_nil
  382. expect(ticket.close_diff_in_min).to be_nil
  383. ticket.update!(priority: priorty_not_matching)
  384. ticket.reload
  385. expect(ticket.escalation_at).to be_nil
  386. expect(ticket.first_response_escalation_at).to be_nil
  387. expect(ticket.first_response_at).to be_nil
  388. expect(ticket.first_response_in_min).to be_nil
  389. expect(ticket.first_response_diff_in_min).to be_nil
  390. expect(ticket.update_escalation_at).to be_nil
  391. expect(ticket.update_in_min).to be_nil
  392. expect(ticket.update_diff_in_min).to be_nil
  393. expect(ticket.close_escalation_at).to be_nil
  394. expect(ticket.close_in_min).to be_nil
  395. expect(ticket.close_diff_in_min).to be_nil
  396. end
  397. end
  398. context 'when Ticket state changes (escalation suspense)' do
  399. let(:calendar) do
  400. create(:calendar,
  401. business_hours: {
  402. mon: {
  403. active: true,
  404. timeframes: [ ['09:00', '18:00'] ]
  405. },
  406. tue: {
  407. active: true,
  408. timeframes: [ ['09:00', '18:00'] ]
  409. },
  410. wed: {
  411. active: true,
  412. timeframes: [ ['09:00', '18:00'] ]
  413. },
  414. thu: {
  415. active: true,
  416. timeframes: [ ['09:00', '18:00'] ]
  417. },
  418. fri: {
  419. active: true,
  420. timeframes: [ ['09:00', '18:00'] ]
  421. },
  422. sat: {
  423. active: true,
  424. timeframes: [ ['09:00', '18:00'] ]
  425. },
  426. sun: {
  427. active: true,
  428. timeframes: [ ['09:00', '18:00'] ]
  429. },
  430. })
  431. end
  432. let(:sla) { create(:sla, calendar: calendar, first_response_time: 120, update_time: 180, solution_time: 250) }
  433. context 'when Ticket is reopened' do
  434. subject(:ticket) { create(:ticket, created_at: '2013-06-04 09:00:00 UTC', updated_at: '2013-06-04 09:00:00 UTC') }
  435. before do
  436. # set ticket at 09:30 to pending
  437. create(:history,
  438. history_type: 'updated',
  439. history_attribute: 'state',
  440. o: ticket,
  441. id_from: Ticket::State.lookup(name: 'open').id,
  442. id_to: Ticket::State.lookup(name: 'pending reminder').id,
  443. value_from: 'open',
  444. value_to: 'pending reminder',
  445. created_at: '2013-06-04 09:30:00 UTC',
  446. updated_at: '2013-06-04 09:30:00 UTC',)
  447. # set ticket at 09:45 to open
  448. create(:history,
  449. history_type: 'updated',
  450. history_attribute: 'state',
  451. o: ticket,
  452. id_from: Ticket::State.lookup(name: 'pending reminder').id,
  453. id_to: Ticket::State.lookup(name: 'open').id,
  454. value_from: 'pending reminder',
  455. value_to: 'open',
  456. created_at: '2013-06-04 09:45:00 UTC',
  457. updated_at: '2013-06-04 09:45:00 UTC',)
  458. # set ticket at 10:00 to closed
  459. create(:history,
  460. history_type: 'updated',
  461. history_attribute: 'state',
  462. o: ticket,
  463. id_from: Ticket::State.lookup(name: 'open').id,
  464. id_to: Ticket::State.lookup(name: 'closed').id,
  465. value_from: 'open',
  466. value_to: 'closed',
  467. created_at: '2013-06-04 10:00:00 UTC',
  468. updated_at: '2013-06-04 10:00:00 UTC',)
  469. # set ticket at 10:30 to open
  470. create(:history,
  471. history_type: 'updated',
  472. history_attribute: 'state',
  473. o: ticket,
  474. id_from: Ticket::State.lookup(name: 'closed').id,
  475. id_to: Ticket::State.lookup(name: 'open').id,
  476. value_from: 'closed',
  477. value_to: 'open',
  478. created_at: '2013-06-04 10:30:00 UTC',
  479. updated_at: '2013-06-04 10:30:00 UTC',)
  480. sla
  481. ticket.escalation_calculation
  482. ticket.reload
  483. end
  484. it 'calculates escalation_at attributes' do
  485. expect(ticket.escalation_at.gmtime.to_s).to eq('2013-06-04 11:45:00 UTC')
  486. expect(ticket.first_response_escalation_at.gmtime.to_s).to eq('2013-06-04 11:45:00 UTC')
  487. expect(ticket.first_response_in_min).to be_nil
  488. expect(ticket.first_response_diff_in_min).to be_nil
  489. end
  490. end
  491. context 'when Ticket transitions from pending to open' do
  492. subject(:ticket) { create(:ticket, created_at: '2013-06-04 09:00:00 UTC', updated_at: '2013-06-04 09:00:00 UTC') }
  493. before do
  494. sla
  495. # set ticket at 10:00 to pending
  496. create(:history,
  497. history_type: 'updated',
  498. history_attribute: 'state',
  499. o_id: ticket.id,
  500. id_from: Ticket::State.lookup(name: 'open').id,
  501. id_to: Ticket::State.lookup(name: 'pending reminder').id,
  502. value_from: 'open',
  503. value_to: 'pending reminder',
  504. created_at: '2013-06-04 10:00:00 UTC',
  505. updated_at: '2013-06-04 10:00:00 UTC',)
  506. # set ticket at 15:00 to open
  507. create(:history,
  508. history_type: 'updated',
  509. history_attribute: 'state',
  510. o_id: ticket.id,
  511. id_from: Ticket::State.lookup(name: 'pending reminder').id,
  512. id_to: Ticket::State.lookup(name: 'open').id,
  513. value_from: 'pending reminder',
  514. value_to: 'open',
  515. created_at: '2013-06-04 15:00:00 UTC',
  516. updated_at: '2013-06-04 15:00:00 UTC',)
  517. ticket.escalation_calculation
  518. ticket.reload
  519. end
  520. it 'calculates escalation_at attributes' do
  521. expect(ticket.escalation_at.gmtime.to_s).to eq('2013-06-05 07:00:00 UTC')
  522. expect(ticket.first_response_escalation_at.gmtime.to_s).to eq('2013-06-05 07:00:00 UTC')
  523. expect(ticket.first_response_in_min).to be_nil
  524. expect(ticket.first_response_diff_in_min).to be_nil
  525. end
  526. end
  527. context 'when Ticket transitions from open to pending to open, response and close' do
  528. subject(:ticket) { create(:ticket, created_at: '2013-06-04 09:00:00 UTC', updated_at: '2013-06-04 09:00:00 UTC') }
  529. # set sla's for timezone "Europe/Berlin" summertime (+2), so UTC times are 7:00-16:00
  530. let(:calendar) do
  531. create(:calendar,
  532. business_hours: {
  533. mon: {
  534. active: true,
  535. timeframes: [ ['09:00', '18:00'] ]
  536. },
  537. tue: {
  538. active: true,
  539. timeframes: [ ['09:00', '18:00'] ]
  540. },
  541. wed: {
  542. active: true,
  543. timeframes: [ ['09:00', '18:00'] ]
  544. },
  545. thu: {
  546. active: true,
  547. timeframes: [ ['09:00', '18:00'] ]
  548. },
  549. fri: {
  550. active: true,
  551. timeframes: [ ['09:00', '18:00'] ]
  552. },
  553. sat: {
  554. active: true,
  555. timeframes: [ ['09:00', '18:00'] ]
  556. },
  557. sun: {
  558. active: true,
  559. timeframes: [ ['09:00', '18:00'] ]
  560. },
  561. })
  562. end
  563. let(:sla) { create(:sla, condition: {}, calendar: calendar, first_response_time: 120, update_time: 180, solution_time: 250) }
  564. before do
  565. sla
  566. # set ticket at 10:00 to pending
  567. create(:history,
  568. history_type: 'updated',
  569. history_attribute: 'state',
  570. o_id: ticket.id,
  571. id_to: 3,
  572. id_from: 2,
  573. value_from: 'open',
  574. value_to: 'pending reminder',
  575. created_at: '2013-06-04 10:00:00 UTC',
  576. updated_at: '2013-06-04 10:00:00 UTC',)
  577. # set ticket at 10:30 to open
  578. create(:history,
  579. history_type: 'updated',
  580. history_attribute: 'state',
  581. o_id: ticket.id,
  582. id_to: 2,
  583. id_from: 3,
  584. value_from: 'pending reminder',
  585. value_to: 'open',
  586. created_at: '2013-06-04 10:30:00 UTC',
  587. updated_at: '2013-06-04 10:30:00 UTC')
  588. # set update time
  589. ticket.update!(
  590. last_contact_agent_at: '2013-06-04 10:15:00 UTC',
  591. )
  592. # set first response time
  593. ticket.update!(
  594. first_response_at: '2013-06-04 10:45:00 UTC',
  595. )
  596. # set ticket from 11:30 to closed
  597. create(:history,
  598. history_type: 'updated',
  599. history_attribute: 'state',
  600. o_id: ticket.id,
  601. id_to: 3,
  602. id_from: 2,
  603. value_from: 'open',
  604. value_to: 'closed',
  605. created_at: '2013-06-04 12:00:00 UTC',
  606. updated_at: '2013-06-04 12:00:00 UTC')
  607. ticket.update!(
  608. close_at: '2013-06-04 12:00:00 UTC',
  609. )
  610. ticket.escalation_calculation
  611. ticket.reload
  612. end
  613. it 'calculates escalation_at attributes' do
  614. expect(ticket.escalation_at).to be_nil
  615. expect(ticket.first_response_escalation_at).to be_nil
  616. expect(ticket.first_response_in_min).to eq(75)
  617. expect(ticket.first_response_diff_in_min).to eq(45)
  618. expect(ticket.update_escalation_at).to be_nil
  619. expect(ticket.close_escalation_at).to be_nil
  620. expect(ticket.close_in_min).to eq(150)
  621. expect(ticket.close_diff_in_min).to eq(100)
  622. end
  623. end
  624. context 'when Ticket is created in state pending and closed without reopen or state change' do
  625. subject(:ticket) { create(:ticket, state: Ticket::State.lookup(name: 'pending reminder'), created_at: '2013-06-04 09:00:00 UTC', updated_at: '2013-06-04 09:00:00 UTC') }
  626. # set sla's for timezone "Europe/Berlin" summertime (+2), so UTC times are 7:00-16:00
  627. let(:calendar) do
  628. create(:calendar,
  629. business_hours: {
  630. mon: {
  631. active: true,
  632. timeframes: [ ['09:00', '18:00'] ]
  633. },
  634. tue: {
  635. active: true,
  636. timeframes: [ ['09:00', '18:00'] ]
  637. },
  638. wed: {
  639. active: true,
  640. timeframes: [ ['09:00', '18:00'] ]
  641. },
  642. thu: {
  643. active: true,
  644. timeframes: [ ['09:00', '18:00'] ]
  645. },
  646. fri: {
  647. active: true,
  648. timeframes: [ ['09:00', '18:00'] ]
  649. },
  650. sat: {
  651. active: true,
  652. timeframes: [ ['09:00', '18:00'] ]
  653. },
  654. sun: {
  655. active: true,
  656. timeframes: [ ['09:00', '18:00'] ]
  657. },
  658. })
  659. end
  660. let(:sla) { create(:sla, condition: {}, calendar: calendar, first_response_time: 120, update_time: 180, solution_time: 240) }
  661. before do
  662. sla
  663. # set ticket from 11:30 to closed
  664. create(:history,
  665. history_type: 'updated',
  666. history_attribute: 'state',
  667. o_id: ticket.id,
  668. id_to: 4,
  669. id_from: 3,
  670. value_from: 'pending reminder',
  671. value_to: 'closed',
  672. created_at: '2013-06-04 12:00:00 UTC',
  673. updated_at: '2013-06-04 12:00:00 UTC',)
  674. ticket.update!(
  675. close_at: '2013-06-04 12:00:00 UTC',
  676. )
  677. ticket.escalation_calculation
  678. ticket.reload
  679. end
  680. it 'calculates escalation_at attributes' do
  681. expect(ticket.escalation_at).to be_nil
  682. expect(ticket.first_response_escalation_at).to be_nil
  683. expect(ticket.first_response_in_min).to be_nil
  684. expect(ticket.first_response_diff_in_min).to be_nil
  685. expect(ticket.update_escalation_at).to be_nil
  686. expect(ticket.close_escalation_at).to be_nil
  687. expect(ticket.close_in_min).to eq(0)
  688. expect(ticket.close_diff_in_min).to eq(240)
  689. end
  690. end
  691. context 'when Ticket created in state pending, changed state to openen, back to pending and closed' do
  692. subject(:ticket) { create(:ticket, state: Ticket::State.lookup(name: 'pending reminder'), created_at: '2013-06-04 09:00:00 UTC', updated_at: '2013-06-04 09:00:00 UTC') }
  693. # set sla's for timezone "Europe/Berlin" summertime (+2), so UTC times are 7:00-16:00
  694. let(:calendar) do
  695. create(:calendar,
  696. business_hours: {
  697. mon: {
  698. active: true,
  699. timeframes: [ ['09:00', '18:00'] ]
  700. },
  701. tue: {
  702. active: true,
  703. timeframes: [ ['09:00', '18:00'] ]
  704. },
  705. wed: {
  706. active: true,
  707. timeframes: [ ['09:00', '18:00'] ]
  708. },
  709. thu: {
  710. active: true,
  711. timeframes: [ ['09:00', '18:00'] ]
  712. },
  713. fri: {
  714. active: true,
  715. timeframes: [ ['09:00', '18:00'] ]
  716. },
  717. sat: {
  718. active: true,
  719. timeframes: [ ['09:00', '18:00'] ]
  720. },
  721. sun: {
  722. active: true,
  723. timeframes: [ ['09:00', '18:00'] ]
  724. },
  725. })
  726. end
  727. let(:sla) { create(:sla, condition: {}, calendar: calendar, first_response_time: 120, update_time: 180, solution_time: 240) }
  728. before do
  729. sla
  730. # state change to open 10:30
  731. create(:history,
  732. history_type: 'updated',
  733. history_attribute: 'state',
  734. o_id: ticket.id,
  735. id_to: 2,
  736. id_from: 3,
  737. value_from: 'pending reminder',
  738. value_to: 'open',
  739. created_at: '2013-06-04 10:30:00 UTC',
  740. updated_at: '2013-06-04 10:30:00 UTC',)
  741. # state change to pending 11:00
  742. create(:history,
  743. history_type: 'updated',
  744. history_attribute: 'state',
  745. o_id: ticket.id,
  746. id_to: 3,
  747. id_from: 2,
  748. value_from: 'open',
  749. value_to: 'pending reminder',
  750. created_at: '2013-06-04 11:00:00 UTC',
  751. updated_at: '2013-06-04 11:00:00 UTC',)
  752. # set ticket from 12:00 to closed
  753. create(:history,
  754. history_type: 'updated',
  755. history_attribute: 'state',
  756. o_id: ticket.id,
  757. id_to: 4,
  758. id_from: 3,
  759. value_from: 'pending reminder',
  760. value_to: 'closed',
  761. created_at: '2013-06-04 12:00:00 UTC',
  762. updated_at: '2013-06-04 12:00:00 UTC',)
  763. ticket.update!(
  764. close_at: '2013-06-04 12:00:00 UTC',
  765. )
  766. ticket.escalation_calculation
  767. ticket.reload
  768. end
  769. it 'calculates escalation_at attributes' do
  770. expect(ticket.escalation_at).to be_nil
  771. expect(ticket.first_response_escalation_at).to be_nil
  772. expect(ticket.first_response_in_min).to be_nil
  773. expect(ticket.first_response_diff_in_min).to be_nil
  774. expect(ticket.update_escalation_at).to be_nil
  775. expect(ticket.close_escalation_at).to be_nil
  776. expect(ticket.close_in_min).to eq(30)
  777. expect(ticket.close_diff_in_min).to eq(210)
  778. end
  779. end
  780. context 'when Test Ticket created in state pending, changed state to openen, back to pending and back to open then - close ticket' do
  781. subject(:ticket) { create(:ticket, state: Ticket::State.lookup(name: 'pending reminder'), created_at: '2013-06-04 09:00:00 UTC', updated_at: '2013-06-04 09:00:00 UTC') }
  782. # set sla's for timezone "Europe/Berlin" summertime (+2), so UTC times are 7:00-16:00
  783. let(:calendar) do
  784. create(:calendar,
  785. business_hours: {
  786. mon: {
  787. active: true,
  788. timeframes: [ ['09:00', '18:00'] ]
  789. },
  790. tue: {
  791. active: true,
  792. timeframes: [ ['09:00', '18:00'] ]
  793. },
  794. wed: {
  795. active: true,
  796. timeframes: [ ['09:00', '18:00'] ]
  797. },
  798. thu: {
  799. active: true,
  800. timeframes: [ ['09:00', '18:00'] ]
  801. },
  802. fri: {
  803. active: true,
  804. timeframes: [ ['09:00', '18:00'] ]
  805. },
  806. sat: {
  807. active: true,
  808. timeframes: [ ['09:00', '18:00'] ]
  809. },
  810. sun: {
  811. active: true,
  812. timeframes: [ ['09:00', '18:00'] ]
  813. },
  814. })
  815. end
  816. let(:sla) { create(:sla, condition: {}, calendar: calendar, first_response_time: 120, update_time: 180, solution_time: 240) }
  817. before do
  818. sla
  819. # state change to open from pending
  820. create(:history,
  821. history_type: 'updated',
  822. history_attribute: 'state',
  823. o_id: ticket.id,
  824. id_to: 2,
  825. id_from: 3,
  826. value_from: 'pending reminder',
  827. value_to: 'open',
  828. created_at: '2013-06-04 10:30:00 UTC',
  829. updated_at: '2013-06-04 10:30:00 UTC',)
  830. # state change to pending from open 11:00
  831. create(:history,
  832. history_type: 'updated',
  833. history_attribute: 'state',
  834. o_id: ticket.id,
  835. id_to: 3,
  836. id_from: 2,
  837. value_from: 'open',
  838. value_to: 'pending reminder',
  839. created_at: '2013-06-04 11:00:00 UTC',
  840. updated_at: '2013-06-04 11:00:00 UTC',)
  841. # state change to open 11:30
  842. create(:history,
  843. history_type: 'updated',
  844. history_attribute: 'state',
  845. o_id: ticket.id,
  846. id_to: 2,
  847. id_from: 3,
  848. value_from: 'pending reminder',
  849. value_to: 'open',
  850. created_at: '2013-06-04 11:30:00 UTC',
  851. updated_at: '2013-06-04 11:30:00 UTC',)
  852. # set ticket from open to closed 12:00
  853. create(:history,
  854. history_type: 'updated',
  855. history_attribute: 'state',
  856. o_id: ticket.id,
  857. id_to: 4,
  858. id_from: 3,
  859. value_from: 'open',
  860. value_to: 'closed',
  861. created_at: '2013-06-04 12:00:00 UTC',
  862. updated_at: '2013-06-04 12:00:00 UTC',)
  863. ticket.update!(
  864. close_at: '2013-06-04 12:00:00 UTC',
  865. )
  866. ticket.escalation_calculation
  867. ticket.reload
  868. end
  869. it 'calculates escalation_at attributes' do
  870. expect(ticket.escalation_at).to be_nil
  871. expect(ticket.first_response_escalation_at).to be_nil
  872. expect(ticket.first_response_in_min).to be_nil
  873. expect(ticket.first_response_diff_in_min).to be_nil
  874. expect(ticket.update_escalation_at).to be_nil
  875. expect(ticket.close_escalation_at).to be_nil
  876. expect(ticket.close_in_min).to eq(60)
  877. expect(ticket.close_diff_in_min).to eq(180)
  878. end
  879. end
  880. end
  881. context 'when SLA has Calendar with holidays' do
  882. subject(:ticket) { create(:ticket, created_at: '2016-11-01 13:56:21 UTC', updated_at: '2016-11-01 13:56:21 UTC') }
  883. # set sla's for timezone "Europe/Berlin" wintertime (+1), so UTC times are 7:00-18:00
  884. let(:calendar) do
  885. create(:calendar,
  886. business_hours: {
  887. mon: {
  888. active: true,
  889. timeframes: [ ['08:00', '20:00'] ]
  890. },
  891. tue: {
  892. active: true,
  893. timeframes: [ ['08:00', '20:00'] ]
  894. },
  895. wed: {
  896. active: true,
  897. timeframes: [ ['08:00', '20:00'] ]
  898. },
  899. thu: {
  900. active: true,
  901. timeframes: [ ['08:00', '20:00'] ]
  902. },
  903. fri: {
  904. active: true,
  905. timeframes: [ ['08:00', '20:00'] ]
  906. },
  907. sat: {
  908. active: false,
  909. timeframes: [ ['08:00', '17:00'] ]
  910. },
  911. sun: {
  912. active: false,
  913. timeframes: [ ['08:00', '17:00'] ]
  914. },
  915. },
  916. public_holidays: {
  917. '2016-11-01' => {
  918. 'active' => true,
  919. 'summary' => 'test 1',
  920. },
  921. })
  922. end
  923. let(:sla) { create(:sla, condition: {}, calendar: calendar, first_response_time: 120, update_time: 1200, solution_time: nil) }
  924. before do
  925. sla
  926. ticket
  927. end
  928. it 'calculates escalation_at attributes' do
  929. create(:'ticket/article', :inbound_web, ticket: ticket, created_at: '2016-11-01 13:56:21 UTC', updated_at: '2016-11-01 13:56:21 UTC')
  930. ticket.reload
  931. expect(ticket.escalation_at.gmtime.to_s).to eq('2016-11-02 09:00:00 UTC')
  932. expect(ticket.first_response_escalation_at.gmtime.to_s).to eq('2016-11-02 09:00:00 UTC')
  933. expect(ticket.update_escalation_at.gmtime.to_s).to eq('2016-11-03 15:00:00 UTC')
  934. expect(ticket.close_escalation_at).to be_nil
  935. ticket.update!(
  936. state: Ticket::State.lookup(name: 'pending reminder'),
  937. pending_time: '2016-11-10 07:00:00 UTC',
  938. updated_at: '2016-11-01 15:25:40 UTC',
  939. )
  940. create(:'ticket/article', :outbound_email, ticket: ticket, created_at: '2016-11-01 15:25:40 UTC', updated_at: '2016-11-01 15:25:40 UTC')
  941. ticket.reload
  942. expect(ticket.escalation_at).to be_nil
  943. expect(ticket.first_response_escalation_at).to be_nil
  944. expect(ticket.update_escalation_at).to be_nil
  945. expect(ticket.close_escalation_at).to be_nil
  946. ticket.update!(
  947. state: Ticket::State.lookup(name: 'open'),
  948. updated_at: '2016-11-01 15:59:14 UTC',
  949. )
  950. create(:'ticket/article', :inbound_email, ticket: ticket, created_at: '2016-11-01 15:59:14 UTC', updated_at: '2016-11-01 15:59:14 UTC')
  951. ticket.reload
  952. expect(ticket.escalation_at.gmtime.to_s).to eq('2016-11-03 15:00:00 UTC')
  953. expect(ticket.first_response_escalation_at).to be_nil
  954. expect(ticket.update_escalation_at.gmtime.to_s).to eq('2016-11-03 15:00:00 UTC')
  955. expect(ticket.close_escalation_at).to be_nil
  956. ticket.update!(
  957. state: Ticket::State.lookup(name: 'pending reminder'),
  958. pending_time: '2016-11-18 07:00:00 UTC',
  959. updated_at: '2016-11-01 15:59:58 UTC',
  960. )
  961. ticket.reload
  962. expect(ticket.escalation_at).to be_nil
  963. expect(ticket.first_response_escalation_at).to be_nil
  964. expect(ticket.update_escalation_at).to be_nil
  965. expect(ticket.close_escalation_at).to be_nil
  966. ticket.update!(
  967. state: Ticket::State.lookup(name: 'open'),
  968. updated_at: '2016-11-07 13:26:36 UTC',
  969. )
  970. create(:'ticket/article', :inbound_email, ticket: ticket, created_at: '2016-11-07 13:26:36 UTC', updated_at: '2016-11-07 13:26:36 UTC')
  971. ticket.reload
  972. expect(ticket.escalation_at.gmtime.to_s).to eq('2016-11-09 09:26:00 UTC')
  973. expect(ticket.first_response_escalation_at).to be_nil
  974. expect(ticket.update_escalation_at.gmtime.to_s).to eq('2016-11-09 09:26:00 UTC')
  975. expect(ticket.close_escalation_at).to be_nil
  976. create(:'ticket/article', :inbound_email, ticket: ticket, created_at: '2016-11-07 14:26:36 UTC', updated_at: '2016-11-07 14:26:36 UTC')
  977. ticket.reload
  978. expect(ticket.escalation_at.gmtime.to_s).to eq('2016-11-09 09:26:00 UTC')
  979. expect(ticket.first_response_escalation_at).to be_nil
  980. expect(ticket.update_escalation_at.gmtime.to_s).to eq('2016-11-09 09:26:00 UTC')
  981. expect(ticket.close_escalation_at).to be_nil
  982. end
  983. end
  984. end
  985. end