test_oa_overtime_hours.py 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147
  1. """oa_overtime_hours unit tests"""
  2. from app.services.oa_overtime_hours import (
  3. MANUAL_PREFIX,
  4. DEFAULT_OVERTIME_WINDOWS,
  5. apply_overtime_kit_hours,
  6. calc_overtime_hours,
  7. validate_overtime_kit_form_values,
  8. )
  9. REST = {
  10. "2026-08-07": False,
  11. "2026-08-08": True,
  12. "2026-08-09": True,
  13. }
  14. def is_rest(ymd: str) -> bool:
  15. if ymd in REST:
  16. return REST[ymd]
  17. from datetime import datetime
  18. return datetime.strptime(ymd, "%Y-%m-%d").weekday() >= 5
  19. def test_weekday_evening():
  20. assert (
  21. calc_overtime_hours("2026-08-07 18:00", "2026-08-07 20:00", DEFAULT_OVERTIME_WINDOWS, is_rest)
  22. == 2.0
  23. )
  24. def test_weekday_partial_window():
  25. assert (
  26. calc_overtime_hours("2026-08-07 14:00", "2026-08-07 18:00", DEFAULT_OVERTIME_WINDOWS, is_rest)
  27. == 0.5
  28. )
  29. def test_full_weekday_window():
  30. assert (
  31. calc_overtime_hours("2026-08-07 17:30", "2026-08-08 08:30", DEFAULT_OVERTIME_WINDOWS, is_rest)
  32. == 15.0
  33. )
  34. def test_saturday_with_break():
  35. assert (
  36. calc_overtime_hours("2026-08-08 09:00", "2026-08-08 15:00", DEFAULT_OVERTIME_WINDOWS, is_rest)
  37. == 4.0
  38. )
  39. def test_fri_to_sat():
  40. assert (
  41. calc_overtime_hours("2026-08-07 18:00", "2026-08-08 12:00", DEFAULT_OVERTIME_WINDOWS, is_rest)
  42. == 17.5
  43. )
  44. def test_invalid():
  45. assert (
  46. calc_overtime_hours("2026-08-07 20:00", "2026-08-07 18:00", DEFAULT_OVERTIME_WINDOWS, is_rest)
  47. is None
  48. )
  49. def test_apply_overwrites_when_not_manual():
  50. schema = {
  51. "rule": [
  52. {
  53. "type": "overtimeKit",
  54. "props": {
  55. "startField": "overtimeStart",
  56. "endField": "overtimeEnd",
  57. "durationField": "overtimeDuration",
  58. },
  59. "children": [
  60. {"type": "person", "field": "overtimePerson"},
  61. {
  62. "type": "datePicker",
  63. "field": "overtimeStart",
  64. "props": {"_fc_kit_field": "overtimeStart"},
  65. },
  66. {
  67. "type": "datePicker",
  68. "field": "overtimeEnd",
  69. "props": {"_fc_kit_field": "overtimeEnd"},
  70. },
  71. {
  72. "type": "inputNumber",
  73. "field": "overtimeDuration",
  74. "props": {"_fc_kit_field": "overtimeDuration"},
  75. },
  76. ],
  77. }
  78. ]
  79. }
  80. data = {
  81. "overtimeStart": "2026-08-07 18:00",
  82. "overtimeEnd": "2026-08-07 20:00",
  83. "overtimeDuration": 1,
  84. }
  85. out = apply_overtime_kit_hours(schema, data, is_rest)
  86. assert out["overtimeDuration"] == 2.0
  87. def test_apply_respects_manual():
  88. schema = {
  89. "rule": [
  90. {
  91. "type": "overtimeKit",
  92. "props": {},
  93. "children": [
  94. {"type": "datePicker", "field": "overtimeStart"},
  95. {"type": "datePicker", "field": "overtimeEnd"},
  96. {"type": "inputNumber", "field": "overtimeDuration"},
  97. ],
  98. }
  99. ]
  100. }
  101. data = {
  102. "overtimeStart": "2026-08-07 18:00",
  103. "overtimeEnd": "2026-08-07 20:00",
  104. "overtimeDuration": 8,
  105. f"{MANUAL_PREFIX}overtimeDuration": True,
  106. }
  107. out = apply_overtime_kit_hours(schema, data, is_rest)
  108. assert out["overtimeDuration"] == 8.0
  109. def test_validate_end_before_start():
  110. schema = {
  111. "rule": [
  112. {
  113. "type": "overtimeKit",
  114. "children": [
  115. {"type": "datePicker", "field": "s"},
  116. {"type": "datePicker", "field": "e"},
  117. {"type": "inputNumber", "field": "d"},
  118. ],
  119. }
  120. ]
  121. }
  122. errs = validate_overtime_kit_form_values(
  123. schema, {"s": "2026-08-07 20:00", "e": "2026-08-07 18:00", "d": 1}
  124. )
  125. assert any("结束" in e for e in errs)