feat: 收款账户选项只返回当前登记人并带上所属人姓名

发起校验能识别已删除、他租户和他人账户,编辑账户不会改掉 create_by。

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
zlwuandCursor committed 2026-10-21 18:45:43 +08:00
1 parent bd669ea77e
commit 7aa685840f
3 files changed
+87 -9

No files matched your search

+9 -1
View File
@@ -84,7 +84,15 @@ async def list_receive_account_options(
db: Session = Depends(get_db), db: Session = Depends(get_db),
): ):
tenant_no = _get_tenant_no(db, user) tenant_no = _get_tenant_no(db, user)
return success_response({"list": ora_crud.list_options(db, tenant_no=tenant_no)}) return success_response(
{
"list": ora_crud.list_options(
db,
tenant_no=tenant_no,
user_id=user.get("user_id") or "",
)
}
)
@router.post("/receive-accounts/batch-delete") @router.post("/receive-accounts/batch-delete")
+32 -8
View File
@@ -8,7 +8,7 @@ from sqlalchemy import func, or_
from sqlalchemy.orm import Session from sqlalchemy.orm import Session
from app.core.utils import generate_uuid from app.core.utils import generate_uuid
from app.models.models import OaReceiveAccount from app.models.models import OaReceiveAccount, SysUser
def row_to_dict(r: OaReceiveAccount) -> Dict[str, Any]: def row_to_dict(r: OaReceiveAccount) -> Dict[str, Any]:
@@ -26,9 +26,26 @@ def row_to_dict(r: OaReceiveAccount) -> Dict[str, Any]:
"remark": r.remark or "", "remark": r.remark or "",
"createTime": r.create_time.strftime("%Y-%m-%d %H:%M:%S") if r.create_time else "", "createTime": r.create_time.strftime("%Y-%m-%d %H:%M:%S") if r.create_time else "",
"updateTime": r.update_time.strftime("%Y-%m-%d %H:%M:%S") if r.update_time else "", "updateTime": r.update_time.strftime("%Y-%m-%d %H:%M:%S") if r.update_time else "",
"ownerUserId": (r.create_by or "").strip(),
} }
def _owner_name_map(db: Session, user_ids: List[str]) -> Dict[str, str]:
ids = [item for item in {uid.strip() for uid in user_ids if uid and uid.strip()}]
if not ids:
return {}
rows = db.query(SysUser.id, SysUser.nick_name).filter(SysUser.id.in_(ids)).all()
return {row.id: (row.nick_name or "").strip() for row in rows}
def _attach_owner_names(db: Session, items: List[Dict[str, Any]]) -> List[Dict[str, Any]]:
names = _owner_name_map(db, [item.get("ownerUserId") or "" for item in items])
for item in items:
uid = item.get("ownerUserId") or ""
item["ownerName"] = names.get(uid) or "—"
return items
def _filtered_query( def _filtered_query(
db: Session, db: Session,
*, *,
@@ -74,17 +91,24 @@ def list_accounts(
.limit(page_size) .limit(page_size)
.all() .all()
) )
return [row_to_dict(x) for x in rows], int(total) return _attach_owner_names(db, [row_to_dict(x) for x in rows]), int(total)
def list_options(db: Session, *, tenant_no: str) -> List[Dict[str, Any]]: def list_options(db: Session, *, tenant_no: str, user_id: str) -> List[Dict[str, Any]]:
owner_id = (user_id or "").strip()
if not owner_id:
return []
rows = ( rows = (
db.query(OaReceiveAccount) db.query(OaReceiveAccount)
.filter(OaReceiveAccount.tenant_no == tenant_no, OaReceiveAccount.del_flag == 0) .filter(
OaReceiveAccount.tenant_no == tenant_no,
OaReceiveAccount.del_flag == 0,
func.trim(OaReceiveAccount.create_by) == owner_id,
)
.order_by(OaReceiveAccount.create_time.desc()) .order_by(OaReceiveAccount.create_time.desc())
.all() .all()
) )
return [row_to_dict(x) for x in rows] return _attach_owner_names(db, [row_to_dict(x) for x in rows])
def get_account(db: Session, account_id: str, tenant_no: str) -> Optional[Dict[str, Any]]: def get_account(db: Session, account_id: str, tenant_no: str) -> Optional[Dict[str, Any]]:
@@ -97,7 +121,7 @@ def get_account(db: Session, account_id: str, tenant_no: str) -> Optional[Dict[s
) )
.first() .first()
) )
return row_to_dict(row) if row else None return _attach_owner_names(db, [row_to_dict(row)])[0] if row else None
def create_account( def create_account(
@@ -131,7 +155,7 @@ def create_account(
db.add(obj) db.add(obj)
db.commit() db.commit()
db.refresh(obj) db.refresh(obj)
return row_to_dict(obj) return _attach_owner_names(db, [row_to_dict(obj)])[0]
def update_account( def update_account(
@@ -168,7 +192,7 @@ def update_account(
db.add(obj) db.add(obj)
db.commit() db.commit()
db.refresh(obj) db.refresh(obj)
return row_to_dict(obj) return _attach_owner_names(db, [row_to_dict(obj)])[0]
def soft_delete_account( def soft_delete_account(
@@ -3,6 +3,10 @@ from __future__ import annotations
from typing import Any, Dict, List, Optional, Tuple from typing import Any, Dict, List, Optional, Tuple
from sqlalchemy.orm import Session
from app.models.models import OaReceiveAccount
ACCOUNT_TYPES = frozenset({"alipay", "personal", "corporate"}) ACCOUNT_TYPES = frozenset({"alipay", "personal", "corporate"})
_BANK_FIELD_ALIASES = { _BANK_FIELD_ALIASES = {
@@ -199,3 +203,45 @@ def validate_receive_account_form_values(
continue continue
errors.extend(_validate_receive_account_rule(rule, data)) errors.extend(_validate_receive_account_rule(rule, data))
return errors return errors
def validate_receive_account_ownership(
db: Session,
schema: Any,
form_data: Optional[Dict[str, Any]],
*,
tenant_no: str,
initiator_user_id: str,
) -> List[str]:
"""校验收款账户快照 id 属于发起人。调用前须已通过格式校验。"""
data = form_data or {}
owner_id = (initiator_user_id or "").strip()
for rule in _schema_rules(schema):
if str(rule.get("type") or "") != "receiveAccount":
continue
field = str(rule.get("field") or "").strip()
if not field:
continue
value = data.get(field)
if not isinstance(value, list):
continue
label = _field_label(rule)
for item in value:
if not isinstance(item, dict):
continue
item_id = str(item.get("id") or "").strip()
if not item_id:
continue
row = (
db.query(OaReceiveAccount)
.filter(
OaReceiveAccount.id == item_id,
OaReceiveAccount.tenant_no == tenant_no,
)
.first()
)
if row is None or int(row.del_flag or 0) == 1:
return [f"「{label}」不存在或已删除"]
if (row.create_by or "").strip() != owner_id:
return [f"「{label}」不属于当前用户"]
return []