mattrguerra/meridian-ops-boardmainPrivate on GitHub, published here in full

line-class.test.ts

Language TypeScript5.3 KB118 lines

packages/plinth-client/test/line-class.test.ts

  1. /**
  2. * Which order lines count as work this team owes.
  3. *
  4. * Every order-line count on the board (the queue, `ourMove`, `atVendor`,
  5. * `waitingOnClient`, every person's workload) classifies each line with this
  6. * rule. Classifying on the order status alone makes the queue show a handful of
  7. * lines against a window holding hundreds.
  8. *
  9. * Neither field alone is right, because they go stale in opposite directions,
  10. * and live Plinth data shows both:
  11. *
  12. * - order status stale behind: an order sitting "On Press" with a product
  13. * line still in File Check is somebody's job today, and filtering on the
  14. * order hides it.
  15. * - product status stale ahead: the product row parks at its last value when
  16. * an order ships. Most design-stage product lines in a typical fortnight sit
  17. * on orders already shipped or delivered. Filtering on the product alone
  18. * resurrects them as open artwork, which "makes the team look behind when it
  19. * is not", the failure the board's own footer warns about.
  20. *
  21. * So the rule takes both: ours when the product says ours and the order has not
  22. * moved past Part Dispatched.
  23. */
  24. import { describe, expect, it } from 'vitest'
  25. import { classifyLine, isLineDesignQueue, isOrderPastFulfilment } from '../src/status-taxonomy.js'
  26. const line = (productStatus: string, orderStatus: string) => ({
  27. productStatus,
  28. productStatusId: null,
  29. orderStatus,
  30. orderStatusId: null,
  31. })
  32. describe('the product row says what the work is', () => {
  33. it('counts design work on an order that has already left for the vendor', () => {
  34. // The line an order-only rule hides. "On Press" is at-vendor at the order
  35. // level, so the whole line would vanish, including the artwork nobody had
  36. // done.
  37. expect(classifyLine(line('File Check', 'On Press'))).toBe('ours')
  38. expect(classifyLine(line('File Check', 'Cleared For Print'))).toBe('ours')
  39. })
  40. it('keeps a line waiting on the client out of the team’s column', () => {
  41. expect(classifyLine(line('Waiting On Files', 'On Press'))).toBe('client')
  42. expect(classifyLine(line('Proof With Client', 'Proof Out'))).toBe('client')
  43. })
  44. it('keeps a line at the vendor out of it too', () => {
  45. expect(classifyLine(line('Partner Dispatched', 'On Press'))).toBe('vendor')
  46. })
  47. })
  48. describe('the order says whether the work is still here', () => {
  49. it('drops a stale product row on an order that has shipped', () => {
  50. // The phantom a product-only rule would create: several of these in a
  51. // typical fortnight.
  52. expect(classifyLine(line('File Check', 'Dispatched'))).toBe('terminal')
  53. expect(classifyLine(line('File Check', 'Delivered'))).toBe('terminal')
  54. expect(classifyLine(line('Waiting On Files', 'Awaiting Collection'))).toBe('terminal')
  55. })
  56. it('treats Part Dispatched as still here (Sam’s cutoff, 2026-09-17)', () => {
  57. // The rule is "has not moved PAST Part Dispatched", so this one is in.
  58. expect(isOrderPastFulfilment('Part Dispatched')).toBe(false)
  59. expect(classifyLine(line('File Check', 'Part Dispatched'))).toBe('ours')
  60. // And the next one along is out.
  61. expect(isOrderPastFulfilment('Dispatched')).toBe(true)
  62. })
  63. it('drops cancelled and refunded orders, whatever the product row says', () => {
  64. for (const s of ['Cancelled', 'Refunded', 'Claim Settled']) {
  65. expect(classifyLine(line('File Check', s)), s).toBe('terminal')
  66. }
  67. })
  68. it('keeps a cancellation REQUEST, because that is a decision somebody owes', () => {
  69. // 'Cancel Requested' is classed 'ours' in the order catalog for
  70. // exactly this reason, and it is not past fulfilment.
  71. expect(isOrderPastFulfilment('Cancel Requested')).toBe(false)
  72. })
  73. })
  74. describe('the unknown direction', () => {
  75. it('lets a line through when the order status is one nobody has classified', () => {
  76. // Same direction as classifyProduct's unknown default: a status nobody has
  77. // seen yet should appear on the page and be noticed, not be filtered off it.
  78. expect(isOrderPastFulfilment('Some New Status Ops Added')).toBe(false)
  79. expect(classifyLine(line('File Check', 'Some New Status Ops Added'))).toBe('ours')
  80. })
  81. it('still counts an unknown PRODUCT status as ours, so it gets noticed', () => {
  82. expect(classifyLine(line('Some New Product Status', 'On Press'))).toBe('ours')
  83. })
  84. })
  85. describe('the design queue rides the same gate', () => {
  86. it('counts artwork on a live order and not on a shipped one', () => {
  87. expect(isLineDesignQueue(line('File Check', 'On Press'))).toBe(true)
  88. expect(isLineDesignQueue(line('File Check', 'Dispatched'))).toBe(false)
  89. })
  90. it('does not count a line that is not design work', () => {
  91. expect(isLineDesignQueue(line('Partner Dispatched', 'On Press'))).toBe(false)
  92. })
  93. })
  94. describe('the two catalogs are not interchangeable', () => {
  95. it('reads the product name against the PRODUCT catalog', () => {
  96. // "Proof Out" exists only at order level. Putting it in the product field
  97. // (which the dashboard fixture did until this change) hits the
  98. // unknown-means-ours default and silently turns a client wait into team
  99. // workload. That is how every fixture line read as work for one commit.
  100. expect(classifyLine(line('Proof Out', 'Proof Out'))).toBe('ours')
  101. // Whereas the product catalog's name for the same wait classifies right.
  102. expect(classifyLine(line('Proof With Client', 'Proof Out'))).toBe('client')
  103. })
  104. })