escalation_examples.rb 43 KB

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