escalation_examples.rb 42 KB

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