| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308 |
- """OA:审批人为发起人时自动通过"""
- import json
- import unittest
- from datetime import datetime
- from unittest.mock import patch
- from sqlalchemy import create_engine
- from sqlalchemy.orm import sessionmaker
- class TestAutoPassInitiator(unittest.TestCase):
- def setUp(self):
- from app.models.models import OaAppVersion, OaInstance, OaTask
- self.engine = create_engine("sqlite:///:memory:")
- OaAppVersion.__table__.create(self.engine)
- OaInstance.__table__.create(self.engine)
- OaTask.__table__.create(self.engine)
- Session = sessionmaker(bind=self.engine, autoflush=False, autocommit=False)
- self.db = Session()
- self.OaAppVersion = OaAppVersion
- self.OaInstance = OaInstance
- self.OaTask = OaTask
- self.now = datetime.now()
- def tearDown(self):
- self.db.close()
- self.engine.dispose()
- def _seed(self, *, flow, advanced, initiator="u0", tasks=None):
- self.db.add(
- self.OaAppVersion(
- id="v1",
- app_id="app1",
- version_no=1,
- status="published",
- is_latest_published="1",
- form_schema_json="{}",
- flow_tree_json=json.dumps(flow),
- advanced_settings_json=json.dumps(advanced),
- tenant_no="zkxw",
- create_dept_id="",
- create_time=self.now,
- update_time=self.now,
- del_flag=0,
- )
- )
- self.db.add(
- self.OaInstance(
- id="i1",
- app_id="app1",
- app_version_id="v1",
- title="t",
- initiator_user_id=initiator,
- initiator_dept_id="d1",
- form_data_json="{}",
- status="running",
- tenant_no="zkxw",
- create_dept_id="",
- create_time=self.now,
- update_time=self.now,
- del_flag=0,
- )
- )
- for t in tasks or []:
- self.db.add(t)
- self.db.commit()
- def test_or_sign_sole_initiator_auto_passes_to_end(self):
- """开关开:或签唯一审批人=发起人 → 提交推进后自动通过到结束。"""
- from app.services.oa_engine import advance_from
- flow = {
- "id": "s",
- "type": "start",
- "child": {
- "id": "a1",
- "type": "approval",
- "name": "审批人",
- "approverConfig": {
- "assigneeType": "users",
- "userIds": ["u0"],
- "signMode": "or",
- },
- "child": {"id": "e1", "type": "end"},
- },
- }
- self._seed(
- flow=flow,
- advanced={"autoPassWhenApproverIsInitiator": True},
- )
- inst = self.db.query(self.OaInstance).filter_by(id="i1").first()
- ver = self.db.query(self.OaAppVersion).filter_by(id="v1").first()
- with patch(
- "app.services.oa_engine.resolve_assignees",
- return_value=(["u0"], {"resolve_source": "users"}),
- ), patch(
- "app.services.oa_engine._next_task_order_num",
- return_value=1,
- ):
- advance_from(
- self.db, inst=inst, ver=ver, from_node=None, user_id="u0"
- )
- # Session autoflush=False:未 flush 时 query 看不到刚 add 的任务
- self.db.flush()
- tasks = self.db.query(self.OaTask).filter_by(instance_id="i1").all()
- self.assertEqual(len(tasks), 1)
- self.assertEqual(tasks[0].status, "approved")
- self.assertEqual(tasks[0].comment_text, "系统自动通过")
- self.assertEqual(inst.status, "completed")
- def test_switch_off_keeps_pending(self):
- from app.services.oa_engine import advance_from
- flow = {
- "id": "s",
- "type": "start",
- "child": {
- "id": "a1",
- "type": "approval",
- "name": "审批人",
- "approverConfig": {
- "assigneeType": "users",
- "userIds": ["u0"],
- "signMode": "or",
- },
- "child": {"id": "e1", "type": "end"},
- },
- }
- self._seed(flow=flow, advanced={"autoPassWhenApproverIsInitiator": False})
- inst = self.db.query(self.OaInstance).filter_by(id="i1").first()
- ver = self.db.query(self.OaAppVersion).filter_by(id="v1").first()
- with patch(
- "app.services.oa_engine.resolve_assignees",
- return_value=(["u0"], {"resolve_source": "users"}),
- ), patch(
- "app.services.oa_engine._next_task_order_num", return_value=1
- ):
- advance_from(self.db, inst=inst, ver=ver, from_node=None, user_id="u0")
- self.db.flush()
- t = self.db.query(self.OaTask).filter_by(instance_id="i1").one()
- self.assertEqual(t.status, "pending")
- self.assertEqual(inst.status, "running")
- def test_or_sign_multi_cancels_siblings(self):
- from app.services.oa_engine import advance_from
- flow = {
- "id": "s",
- "type": "start",
- "child": {
- "id": "a1",
- "type": "approval",
- "name": "审批人",
- "approverConfig": {
- "assigneeType": "users",
- "userIds": ["u0", "u2"],
- "signMode": "or",
- },
- "child": {"id": "e1", "type": "end"},
- },
- }
- self._seed(flow=flow, advanced={"autoPassWhenApproverIsInitiator": True})
- inst = self.db.query(self.OaInstance).filter_by(id="i1").first()
- ver = self.db.query(self.OaAppVersion).filter_by(id="v1").first()
- with patch(
- "app.services.oa_engine.resolve_assignees",
- return_value=(["u0", "u2"], {"resolve_source": "users"}),
- ), patch(
- "app.services.oa_engine._next_task_order_num", return_value=1
- ):
- advance_from(self.db, inst=inst, ver=ver, from_node=None, user_id="u0")
- self.db.flush()
- by_user = {
- t.assignee_user_id: t
- for t in self.db.query(self.OaTask).filter_by(instance_id="i1").all()
- }
- self.assertEqual(by_user["u0"].status, "approved")
- self.assertEqual(by_user["u0"].comment_text, "系统自动通过")
- self.assertEqual(by_user["u2"].status, "done")
- self.assertEqual(inst.status, "completed")
- def test_and_sign_only_completes_self(self):
- from app.services.oa_engine import advance_from
- flow = {
- "id": "s",
- "type": "start",
- "child": {
- "id": "a1",
- "type": "approval",
- "name": "审批人",
- "approverConfig": {
- "assigneeType": "users",
- "userIds": ["u0", "u2"],
- "signMode": "and",
- },
- "child": {"id": "e1", "type": "end"},
- },
- }
- self._seed(flow=flow, advanced={"autoPassWhenApproverIsInitiator": True})
- inst = self.db.query(self.OaInstance).filter_by(id="i1").first()
- ver = self.db.query(self.OaAppVersion).filter_by(id="v1").first()
- with patch(
- "app.services.oa_engine.resolve_assignees",
- return_value=(["u0", "u2"], {"resolve_source": "users"}),
- ), patch(
- "app.services.oa_engine._next_task_order_num", return_value=1
- ):
- advance_from(self.db, inst=inst, ver=ver, from_node=None, user_id="u0")
- self.db.flush()
- by_user = {
- t.assignee_user_id: t
- for t in self.db.query(self.OaTask).filter_by(instance_id="i1").all()
- }
- self.assertEqual(by_user["u0"].status, "approved")
- self.assertEqual(by_user["u2"].status, "pending")
- self.assertEqual(inst.status, "running")
- def test_consecutive_nodes_both_auto_pass(self):
- from app.services.oa_engine import advance_from
- flow = {
- "id": "s",
- "type": "start",
- "child": {
- "id": "a1",
- "type": "approval",
- "name": "一审",
- "approverConfig": {
- "assigneeType": "users",
- "userIds": ["u0"],
- "signMode": "or",
- },
- "child": {
- "id": "a2",
- "type": "approval",
- "name": "二审",
- "approverConfig": {
- "assigneeType": "users",
- "userIds": ["u0"],
- "signMode": "or",
- },
- "child": {"id": "e1", "type": "end"},
- },
- },
- }
- self._seed(flow=flow, advanced={"autoPassWhenApproverIsInitiator": True})
- inst = self.db.query(self.OaInstance).filter_by(id="i1").first()
- ver = self.db.query(self.OaAppVersion).filter_by(id="v1").first()
- with patch(
- "app.services.oa_engine.resolve_assignees",
- return_value=(["u0"], {"resolve_source": "users"}),
- ), patch(
- "app.services.oa_engine._next_task_order_num", return_value=1
- ):
- advance_from(self.db, inst=inst, ver=ver, from_node=None, user_id="u0")
- self.db.flush()
- tasks = self.db.query(self.OaTask).filter_by(instance_id="i1").all()
- self.assertEqual(len(tasks), 2)
- self.assertTrue(all(t.status == "approved" for t in tasks))
- self.assertTrue(all(t.comment_text == "系统自动通过" for t in tasks))
- self.assertEqual(inst.status, "completed")
- def test_comment_required_does_not_block_auto_pass(self):
- from app.services.oa_engine import advance_from
- flow = {
- "id": "s",
- "type": "start",
- "child": {
- "id": "a1",
- "type": "approval",
- "name": "审批人",
- "approverConfig": {
- "assigneeType": "users",
- "userIds": ["u0"],
- "signMode": "or",
- },
- "child": {"id": "e1", "type": "end"},
- },
- }
- self._seed(
- flow=flow,
- advanced={
- "autoPassWhenApproverIsInitiator": True,
- "commentRequired": True,
- },
- )
- inst = self.db.query(self.OaInstance).filter_by(id="i1").first()
- ver = self.db.query(self.OaAppVersion).filter_by(id="v1").first()
- with patch(
- "app.services.oa_engine.resolve_assignees",
- return_value=(["u0"], {"resolve_source": "users"}),
- ), patch(
- "app.services.oa_engine._next_task_order_num", return_value=1
- ):
- advance_from(self.db, inst=inst, ver=ver, from_node=None, user_id="u0")
- self.db.flush()
- t = self.db.query(self.OaTask).filter_by(instance_id="i1").one()
- self.assertEqual(t.status, "approved")
- self.assertEqual(inst.status, "completed")
- if __name__ == "__main__":
- unittest.main()
|