|
|
@@ -23,6 +23,7 @@ from app.schemas.bx.reimburse import ReimburseApplyOut, ReimburseDetailOut
|
|
|
from app.services.bx.approval_cycle import filter_current_cycle_approvals
|
|
|
from app.services.bx.attachment import AttachmentService
|
|
|
from app.services.bx.base import BxCrudService
|
|
|
+from app.services.bx_data_scope import apply_bx_scope
|
|
|
from app.utils.bx_codegen import (
|
|
|
allocate_reimburse_title_seq,
|
|
|
generate_apply_code,
|
|
|
@@ -42,8 +43,17 @@ class ReimburseService:
|
|
|
return get_tenant_no(db, user.to_tenant_user_dict())
|
|
|
|
|
|
@staticmethod
|
|
|
- def get_by_id(db: Session, reimburse_id: str, tenant_no: str) -> Optional[BxReimburseApply]:
|
|
|
- return BxCrudService.get_by_id(BxReimburseApply, db, reimburse_id, tenant_no)
|
|
|
+ def get_by_id(
|
|
|
+ db: Session,
|
|
|
+ reimburse_id: str,
|
|
|
+ tenant_no: str,
|
|
|
+ *,
|
|
|
+ user: Optional[BxUserContext] = None,
|
|
|
+ skip_scope: bool = False,
|
|
|
+ ) -> Optional[BxReimburseApply]:
|
|
|
+ return BxCrudService.get_by_id(
|
|
|
+ BxReimburseApply, db, reimburse_id, tenant_no, user=user, skip_scope=skip_scope
|
|
|
+ )
|
|
|
|
|
|
@staticmethod
|
|
|
def get_paged(
|
|
|
@@ -52,14 +62,18 @@ class ReimburseService:
|
|
|
page: int,
|
|
|
page_size: int,
|
|
|
filters: Optional[List[Any]] = None,
|
|
|
+ *,
|
|
|
+ user: Optional[BxUserContext] = None,
|
|
|
) -> Tuple[Sequence[BxReimburseApply], int]:
|
|
|
- return BxCrudService.get_paged(BxReimburseApply, db, tenant_no, page, page_size, filters)
|
|
|
+ return BxCrudService.get_paged(
|
|
|
+ BxReimburseApply, db, tenant_no, page, page_size, filters, user=user
|
|
|
+ )
|
|
|
|
|
|
@staticmethod
|
|
|
def soft_delete(db: Session, reimburse_id: str, *, user: BxUserContext) -> bool:
|
|
|
tenant_no = ReimburseService._tenant_no(db, user)
|
|
|
return BxCrudService.soft_delete(
|
|
|
- BxReimburseApply, db, reimburse_id, tenant_no, user_id=user.id
|
|
|
+ BxReimburseApply, db, reimburse_id, tenant_no, user_id=user.id, user=user
|
|
|
)
|
|
|
|
|
|
@staticmethod
|
|
|
@@ -170,6 +184,7 @@ class ReimburseService:
|
|
|
if bounds:
|
|
|
d0, d1 = bounds
|
|
|
query = query.filter(BxReimburseApply.create_time >= d0, BxReimburseApply.create_time < d1)
|
|
|
+ query = apply_bx_scope(query, BxReimburseApply, user, db, tenant_no)
|
|
|
total = query.count()
|
|
|
rows = (
|
|
|
query.order_by(BxReimburseApply.create_time.desc())
|
|
|
@@ -182,7 +197,7 @@ class ReimburseService:
|
|
|
@staticmethod
|
|
|
def submit(db: Session, apply_id: str, user: BxUserContext) -> Optional[BxReimburseApply]:
|
|
|
tenant_no = ReimburseService._tenant_no(db, user)
|
|
|
- apply_obj = ReimburseService.get_by_id(db, apply_id, tenant_no)
|
|
|
+ apply_obj = ReimburseService.get_by_id(db, apply_id, tenant_no, user=user)
|
|
|
if not apply_obj:
|
|
|
return None
|
|
|
apply_obj.status = "pending"
|
|
|
@@ -201,7 +216,7 @@ class ReimburseService:
|
|
|
db: Session, apply_id: str, approver: BxUserContext, opinion: str
|
|
|
) -> Optional[BxReimburseApply]:
|
|
|
tenant_no = ReimburseService._tenant_no(db, approver)
|
|
|
- apply_obj = ReimburseService.get_by_id(db, apply_id, tenant_no)
|
|
|
+ apply_obj = ReimburseService.get_by_id(db, apply_id, tenant_no, skip_scope=True)
|
|
|
if not apply_obj or not apply_obj.wf_id:
|
|
|
return None
|
|
|
nodes = ReimburseService._workflow_nodes(db, apply_obj.wf_id, tenant_no)
|
|
|
@@ -246,7 +261,7 @@ class ReimburseService:
|
|
|
db: Session, apply_id: str, approver: BxUserContext, opinion: str
|
|
|
) -> Optional[BxReimburseApply]:
|
|
|
tenant_no = ReimburseService._tenant_no(db, approver)
|
|
|
- apply_obj = ReimburseService.get_by_id(db, apply_id, tenant_no)
|
|
|
+ apply_obj = ReimburseService.get_by_id(db, apply_id, tenant_no, skip_scope=True)
|
|
|
if not apply_obj or not apply_obj.wf_id:
|
|
|
return None
|
|
|
nodes = ReimburseService._workflow_nodes(db, apply_obj.wf_id, tenant_no)
|
|
|
@@ -321,8 +336,10 @@ class ReimburseService:
|
|
|
)
|
|
|
|
|
|
@staticmethod
|
|
|
- def get_approvals(db: Session, apply_id: str, tenant_no: str) -> List[Dict[str, Any]]:
|
|
|
- apply_obj = ReimburseService.get_by_id(db, apply_id, tenant_no)
|
|
|
+ def get_approvals(
|
|
|
+ db: Session, apply_id: str, tenant_no: str, *, user: Optional[BxUserContext] = None
|
|
|
+ ) -> List[Dict[str, Any]]:
|
|
|
+ apply_obj = ReimburseService.get_by_id(db, apply_id, tenant_no, user=user)
|
|
|
if not apply_obj or not apply_obj.wf_id:
|
|
|
return []
|
|
|
wf = BxCrudService.get_by_id(BxWorkflowDef, db, apply_obj.wf_id, tenant_no)
|
|
|
@@ -355,9 +372,11 @@ class ReimburseService:
|
|
|
return result
|
|
|
|
|
|
@staticmethod
|
|
|
- def get_approval_history(db: Session, apply_id: str, tenant_no: str) -> List[Dict[str, Any]]:
|
|
|
+ def get_approval_history(
|
|
|
+ db: Session, apply_id: str, tenant_no: str, *, user: Optional[BxUserContext] = None
|
|
|
+ ) -> List[Dict[str, Any]]:
|
|
|
"""返回全部审批动作,按时间正序排列,用于展示完整审批历史。"""
|
|
|
- if not ReimburseService.get_by_id(db, apply_id, tenant_no):
|
|
|
+ if not ReimburseService.get_by_id(db, apply_id, tenant_no, user=user):
|
|
|
return []
|
|
|
approvals = (
|
|
|
db.query(BxReimburseApproval)
|
|
|
@@ -445,7 +464,7 @@ class ReimburseService:
|
|
|
user: BxUserContext,
|
|
|
) -> Optional[BxReimburseApply]:
|
|
|
tenant_no = ReimburseService._tenant_no(db, user)
|
|
|
- apply_obj = ReimburseService.get_by_id(db, apply_id, tenant_no)
|
|
|
+ apply_obj = ReimburseService.get_by_id(db, apply_id, tenant_no, user=user)
|
|
|
if not apply_obj:
|
|
|
return None
|
|
|
|
|
|
@@ -560,26 +579,33 @@ class ReimburseService:
|
|
|
return out
|
|
|
|
|
|
@staticmethod
|
|
|
- def global_status_counts(db: Session, tenant_no: str) -> Dict[str, int]:
|
|
|
- rows = (
|
|
|
- db.query(BxReimburseApply.status, func.count())
|
|
|
- .filter(BxReimburseApply.del_flag == 0, BxReimburseApply.tenant_no == tenant_no)
|
|
|
- .group_by(BxReimburseApply.status)
|
|
|
- .all()
|
|
|
+ def global_status_counts(db: Session, tenant_no: str, *, user: BxUserContext) -> Dict[str, int]:
|
|
|
+ query = db.query(BxReimburseApply.status, func.count()).filter(
|
|
|
+ BxReimburseApply.del_flag == 0, BxReimburseApply.tenant_no == tenant_no
|
|
|
)
|
|
|
+ query = apply_bx_scope(query, BxReimburseApply, user, db, tenant_no)
|
|
|
+ rows = query.group_by(BxReimburseApply.status).all()
|
|
|
return {str(s or ""): int(c) for s, c in rows}
|
|
|
|
|
|
@staticmethod
|
|
|
- def my_apply_stats(db: Session, user_id: str, tenant_no: str) -> dict:
|
|
|
- base = and_(
|
|
|
+ def _my_apply_base(db: Session, user: BxUserContext, tenant_no: str):
|
|
|
+ query = db.query(BxReimburseApply).filter(
|
|
|
BxReimburseApply.del_flag == 0,
|
|
|
BxReimburseApply.tenant_no == tenant_no,
|
|
|
or_(
|
|
|
- BxReimburseApply.applicant_id == user_id,
|
|
|
- BxReimburseApply.create_by == user_id,
|
|
|
+ BxReimburseApply.applicant_id == user.id,
|
|
|
+ BxReimburseApply.create_by == user.id,
|
|
|
),
|
|
|
)
|
|
|
- total_count = db.query(func.count()).select_from(BxReimburseApply).filter(base).scalar() or 0
|
|
|
+ return apply_bx_scope(query, BxReimburseApply, user, db, tenant_no)
|
|
|
+
|
|
|
+ @staticmethod
|
|
|
+ def my_apply_stats(db: Session, user: BxUserContext, tenant_no: str) -> dict:
|
|
|
+ base_q = ReimburseService._my_apply_base(db, user, tenant_no).subquery()
|
|
|
+ base = BxReimburseApply.id.in_(db.query(base_q.c.id))
|
|
|
+ total_count = (
|
|
|
+ db.query(func.count()).select_from(BxReimburseApply).filter(base).scalar() or 0
|
|
|
+ )
|
|
|
pending = (
|
|
|
db.query(func.count())
|
|
|
.select_from(BxReimburseApply)
|
|
|
@@ -671,7 +697,7 @@ class ReimburseService:
|
|
|
actual_amount: Optional[float] = None,
|
|
|
) -> Optional[BxReimburseApply]:
|
|
|
tenant_no = ReimburseService._tenant_no(db, user)
|
|
|
- apply_obj = ReimburseService.get_by_id(db, apply_id, tenant_no)
|
|
|
+ apply_obj = ReimburseService.get_by_id(db, apply_id, tenant_no, user=user)
|
|
|
if not apply_obj:
|
|
|
return None
|
|
|
apply_obj.status = "processed"
|
|
|
@@ -695,7 +721,7 @@ class ReimburseService:
|
|
|
remark: str = "",
|
|
|
) -> Optional[BxReimburseApply]:
|
|
|
tenant_no = ReimburseService._tenant_no(db, user)
|
|
|
- apply_obj = ReimburseService.get_by_id(db, apply_id, tenant_no)
|
|
|
+ apply_obj = ReimburseService.get_by_id(db, apply_id, tenant_no, user=user)
|
|
|
if not apply_obj:
|
|
|
return None
|
|
|
apply_obj.status = "offset"
|
|
|
@@ -726,7 +752,7 @@ class ReimburseService:
|
|
|
remark: str = "",
|
|
|
) -> Optional[BxReimburseApply]:
|
|
|
tenant_no = ReimburseService._tenant_no(db, user)
|
|
|
- apply_obj = ReimburseService.get_by_id(db, apply_id, tenant_no)
|
|
|
+ apply_obj = ReimburseService.get_by_id(db, apply_id, tenant_no, user=user)
|
|
|
if not apply_obj:
|
|
|
return None
|
|
|
|
|
|
@@ -772,8 +798,13 @@ class ReimburseService:
|
|
|
return apply_obj
|
|
|
|
|
|
@staticmethod
|
|
|
- def finance_payment_stats(db: Session, tenant_no: str) -> dict:
|
|
|
- base = and_(BxReimburseApply.del_flag == 0, BxReimburseApply.tenant_no == tenant_no)
|
|
|
+ def finance_payment_stats(db: Session, tenant_no: str, *, user: BxUserContext) -> dict:
|
|
|
+ base_q = (
|
|
|
+ db.query(BxReimburseApply)
|
|
|
+ .filter(BxReimburseApply.del_flag == 0, BxReimburseApply.tenant_no == tenant_no)
|
|
|
+ )
|
|
|
+ base_q = apply_bx_scope(base_q, BxReimburseApply, user, db, tenant_no).subquery()
|
|
|
+ base = BxReimburseApply.id.in_(db.query(base_q.c.id))
|
|
|
pending = (
|
|
|
db.query(func.count())
|
|
|
.select_from(BxReimburseApply)
|