test_oa_instance_history.py 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207
  1. """OA list_instance_history:按 appId + 全员权限收窄。"""
  2. from __future__ import annotations
  3. import unittest
  4. from datetime import datetime
  5. from sqlalchemy import create_engine
  6. from sqlalchemy.orm import sessionmaker
  7. from app.models.base import Base
  8. from app.models.models import OaApp, OaAppVersion, OaInstance, SysUser
  9. from app.services import oa_engine
  10. class TestOaInstanceHistory(unittest.TestCase):
  11. def setUp(self):
  12. self.engine = create_engine("sqlite:///:memory:")
  13. Base.metadata.create_all(
  14. self.engine,
  15. tables=[
  16. OaApp.__table__,
  17. OaAppVersion.__table__,
  18. SysUser.__table__,
  19. OaInstance.__table__,
  20. ],
  21. )
  22. Session = sessionmaker(bind=self.engine, autoflush=False, autocommit=False)
  23. self.db = Session()
  24. t1 = datetime(2026, 8, 10, 9, 0, 0)
  25. t2 = datetime(2026, 8, 20, 15, 30, 0)
  26. t3 = datetime(2026, 8, 25, 11, 0, 0)
  27. self.db.add_all(
  28. [
  29. OaApp(
  30. id="app-leave",
  31. app_name="请假申请",
  32. initiator_scope="all",
  33. admin_scope="all_oa_admin",
  34. status="1",
  35. tenant_no="zkxw",
  36. create_dept_id="",
  37. create_time=t1,
  38. update_time=t1,
  39. del_flag=0,
  40. ),
  41. OaAppVersion(
  42. id="v-leave",
  43. app_id="app-leave",
  44. version_no=1,
  45. status="published",
  46. is_latest_published="1",
  47. form_schema_json='{"rule":[{"type":"input","field":"leaveType","title":"请假类型"},{"type":"input","field":"days","title":"天数"}]}',
  48. flow_tree_json="{}",
  49. advanced_settings_json="{}",
  50. tenant_no="zkxw",
  51. create_dept_id="",
  52. create_time=t1,
  53. update_time=t1,
  54. del_flag=0,
  55. ),
  56. SysUser(
  57. id="u-a",
  58. user_no="a",
  59. nick_name="张三",
  60. password="x",
  61. tenant_no="zkxw",
  62. create_dept_id="",
  63. create_time=t1,
  64. update_time=t1,
  65. del_flag=0,
  66. ),
  67. SysUser(
  68. id="u-b",
  69. user_no="b",
  70. nick_name="李四",
  71. password="x",
  72. tenant_no="zkxw",
  73. create_dept_id="",
  74. create_time=t1,
  75. update_time=t1,
  76. del_flag=0,
  77. ),
  78. OaInstance(
  79. id="inst-alice-done",
  80. app_id="app-leave",
  81. app_version_id="v-leave",
  82. title="请假-张三",
  83. initiator_user_id="u-a",
  84. form_data_json='{"leaveType":"年假","days":"2"}',
  85. status="completed",
  86. tenant_no="zkxw",
  87. create_dept_id="",
  88. create_time=t1,
  89. update_time=t2,
  90. del_flag=0,
  91. ),
  92. OaInstance(
  93. id="inst-bob-run",
  94. app_id="app-leave",
  95. app_version_id="v-leave",
  96. title="请假-李四",
  97. initiator_user_id="u-b",
  98. form_data_json='{"leaveType":"事假","days":"1"}',
  99. status="running",
  100. tenant_no="zkxw",
  101. create_dept_id="",
  102. create_time=t3,
  103. update_time=t3,
  104. del_flag=0,
  105. ),
  106. ]
  107. )
  108. self.db.commit()
  109. def tearDown(self):
  110. self.db.close()
  111. self.engine.dispose()
  112. def test_requires_app_id(self):
  113. with self.assertRaises(oa_engine.OaEngineError):
  114. oa_engine.list_instance_history(
  115. self.db,
  116. tenant_no="zkxw",
  117. user_id="u-a",
  118. can_view_all=False,
  119. app_id="",
  120. )
  121. def test_self_scope_hides_others(self):
  122. data = oa_engine.list_instance_history(
  123. self.db,
  124. tenant_no="zkxw",
  125. user_id="u-a",
  126. can_view_all=False,
  127. app_id="app-leave",
  128. )
  129. self.assertEqual(data["total"], 1)
  130. self.assertFalse(data["canViewAll"])
  131. self.assertEqual(data["list"][0]["id"], "inst-alice-done")
  132. def test_all_scope_returns_both(self):
  133. data = oa_engine.list_instance_history(
  134. self.db,
  135. tenant_no="zkxw",
  136. user_id="u-a",
  137. can_view_all=True,
  138. app_id="app-leave",
  139. )
  140. self.assertEqual(data["total"], 2)
  141. self.assertTrue(data["canViewAll"])
  142. ids = {r["id"] for r in data["list"]}
  143. self.assertEqual(ids, {"inst-alice-done", "inst-bob-run"})
  144. def test_initiator_name_ignored_without_all(self):
  145. data = oa_engine.list_instance_history(
  146. self.db,
  147. tenant_no="zkxw",
  148. user_id="u-a",
  149. can_view_all=False,
  150. app_id="app-leave",
  151. initiator_name="李四",
  152. )
  153. self.assertEqual(data["total"], 1)
  154. self.assertEqual(data["list"][0]["id"], "inst-alice-done")
  155. def test_finish_time_only_on_terminal(self):
  156. data = oa_engine.list_instance_history(
  157. self.db,
  158. tenant_no="zkxw",
  159. user_id="u-a",
  160. can_view_all=True,
  161. app_id="app-leave",
  162. )
  163. by_id = {r["id"]: r for r in data["list"]}
  164. self.assertTrue(by_id["inst-alice-done"].get("finishTime"))
  165. self.assertFalse(by_id["inst-bob-run"].get("finishTime"))
  166. def test_finish_time_filter(self):
  167. data = oa_engine.list_instance_history(
  168. self.db,
  169. tenant_no="zkxw",
  170. user_id="u-a",
  171. can_view_all=True,
  172. app_id="app-leave",
  173. finish_time_from="2026-08-20",
  174. finish_time_to="2026-08-20",
  175. )
  176. self.assertEqual(data["total"], 1)
  177. self.assertEqual(data["list"][0]["id"], "inst-alice-done")
  178. def test_preview_fields_limit_six(self):
  179. data = oa_engine.list_instance_history(
  180. self.db,
  181. tenant_no="zkxw",
  182. user_id="u-a",
  183. can_view_all=False,
  184. app_id="app-leave",
  185. )
  186. pf = data["list"][0].get("previewFields") or []
  187. self.assertIsInstance(pf, list)
  188. self.assertLessEqual(len(pf), 6)
  189. if pf:
  190. self.assertGreaterEqual(len(pf), 1)
  191. if __name__ == "__main__":
  192. unittest.main()