提交
This commit is contained in:
1 parent
f9676f8759
commit
725774ef0c
155 files changed
+50675
-5242
No files matched your search
+1
-1
@@ -1 +1 @@
|
||||
85220
|
||||
35826
|
||||
@@ -6,6 +6,7 @@ from app.api.workflow import router as workflow_router
|
||||
from app.api.leave import router as leave_router
|
||||
from app.api.crm import router as crm_router
|
||||
from app.api.monitor import router as monitor_router
|
||||
from app.api.bx import bx_router
|
||||
|
||||
__all__ = [
|
||||
"public_router",
|
||||
@@ -15,4 +16,5 @@ __all__ = [
|
||||
"leave_router",
|
||||
"crm_router",
|
||||
"monitor_router",
|
||||
"bx_router",
|
||||
]
|
||||
@@ -0,0 +1,19 @@
|
||||
"""报销(bx)API 路由聚合 — REST 风格,协议对齐 bx 原系统。"""
|
||||
from fastapi import APIRouter
|
||||
|
||||
from app.api.bx import advance, attachment, expense_item, payment, reimburse, workflow
|
||||
from app.schemas.bx.common import ApiResponse
|
||||
|
||||
bx_router = APIRouter(tags=["报销管理"])
|
||||
bx_router.include_router(expense_item.router)
|
||||
bx_router.include_router(workflow.router)
|
||||
bx_router.include_router(advance.router)
|
||||
bx_router.include_router(attachment.router)
|
||||
bx_router.include_router(reimburse.router)
|
||||
bx_router.include_router(payment.router)
|
||||
|
||||
|
||||
@bx_router.get("/bx/health", response_model=ApiResponse[dict])
|
||||
def bx_health():
|
||||
"""P0 健康检查:验证 bx 路由已挂载且响应协议为 code=0。"""
|
||||
return ApiResponse(data={"status": "ok", "module": "bx"})
|
||||
@@ -0,0 +1,345 @@
|
||||
from typing import List, Optional
|
||||
|
||||
from fastapi import APIRouter, Depends, HTTPException, status
|
||||
from sqlalchemy import or_
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
from app.core.bx_auth import BxUserContext, get_bx_current_user
|
||||
from app.core.database import get_db
|
||||
from app.core.tenant_context import get_tenant_no
|
||||
from app.models.bx_models import BxAdvanceApply, BxWorkflowDef
|
||||
from app.schemas.bx.advance import (
|
||||
AdvanceApplyCreate,
|
||||
AdvanceApplyOut,
|
||||
AdvanceApplyUpdate,
|
||||
AdvanceApprovalCreate,
|
||||
AdvanceApprovalOut,
|
||||
AdvanceApproverPendingStatsOut,
|
||||
AdvanceMyStatsOut,
|
||||
)
|
||||
from app.schemas.bx.common import ApiResponse, PagedData
|
||||
from app.services.bx.advance import AdvanceService
|
||||
from app.services.bx.expense_item import ExpenseItemService
|
||||
from app.utils.bx_codegen import generate_apply_code
|
||||
from app.utils.bx_date_range import parse_create_time_day_bounds
|
||||
|
||||
router = APIRouter(prefix="/advances", tags=["备用金管理"])
|
||||
|
||||
|
||||
def _tenant(db: Session, user: BxUserContext) -> str:
|
||||
return get_tenant_no(db, user.to_tenant_user_dict())
|
||||
|
||||
|
||||
def _fill_offset_amounts(db: Session, tenant_no: str, rows, out_rows: List[AdvanceApplyOut]) -> None:
|
||||
if not out_rows:
|
||||
return
|
||||
offset_map = AdvanceService.offset_amount_map(db, tenant_no, [r.id for r in rows])
|
||||
for out_row in out_rows:
|
||||
out_row.offset_amount = offset_map.get(out_row.id, 0.0)
|
||||
|
||||
|
||||
@router.get("/", response_model=ApiResponse[PagedData[AdvanceApplyOut]])
|
||||
def list_advances(
|
||||
page: int = 1,
|
||||
pageSize: int = 10,
|
||||
status: Optional[str] = None,
|
||||
keyword: str = "",
|
||||
applicantId: Optional[str] = None,
|
||||
applyDate: Optional[str] = None,
|
||||
db: Session = Depends(get_db),
|
||||
user: BxUserContext = Depends(get_bx_current_user),
|
||||
):
|
||||
tenant_no = _tenant(db, user)
|
||||
filters = []
|
||||
if status:
|
||||
filters.append(BxAdvanceApply.status == status)
|
||||
if keyword:
|
||||
filters.append(
|
||||
or_(
|
||||
BxAdvanceApply.apply_code.contains(keyword),
|
||||
BxAdvanceApply.applicant_name.contains(keyword),
|
||||
)
|
||||
)
|
||||
if applicantId:
|
||||
filters.append(BxAdvanceApply.applicant_id == str(applicantId).strip())
|
||||
bounds = parse_create_time_day_bounds(applyDate)
|
||||
if bounds:
|
||||
d0, d1 = bounds
|
||||
filters.append(BxAdvanceApply.create_time >= d0)
|
||||
filters.append(BxAdvanceApply.create_time < d1)
|
||||
rows, total = AdvanceService.get_paged(db, tenant_no, page=page, page_size=pageSize, filters=filters)
|
||||
out_rows = [AdvanceApplyOut.model_validate(r) for r in rows]
|
||||
_fill_offset_amounts(db, tenant_no, rows, out_rows)
|
||||
return ApiResponse(data=PagedData(rows=out_rows, total=total, page=page, page_size=pageSize))
|
||||
|
||||
|
||||
@router.get("/my", response_model=ApiResponse[PagedData[AdvanceApplyOut]])
|
||||
def my_advances(
|
||||
page: int = 1,
|
||||
pageSize: int = 10,
|
||||
status: Optional[str] = None,
|
||||
keyword: str = "",
|
||||
applyDate: Optional[str] = None,
|
||||
db: Session = Depends(get_db),
|
||||
user: BxUserContext = Depends(get_bx_current_user),
|
||||
):
|
||||
tenant_no = _tenant(db, user)
|
||||
filters = [
|
||||
or_(
|
||||
BxAdvanceApply.applicant_id == user.id,
|
||||
BxAdvanceApply.create_by == user.id,
|
||||
)
|
||||
]
|
||||
if status:
|
||||
filters.append(BxAdvanceApply.status == status)
|
||||
if keyword:
|
||||
filters.append(
|
||||
or_(
|
||||
BxAdvanceApply.apply_code.contains(keyword),
|
||||
BxAdvanceApply.applicant_name.contains(keyword),
|
||||
)
|
||||
)
|
||||
bounds = parse_create_time_day_bounds(applyDate)
|
||||
if bounds:
|
||||
d0, d1 = bounds
|
||||
filters.append(BxAdvanceApply.create_time >= d0)
|
||||
filters.append(BxAdvanceApply.create_time < d1)
|
||||
rows, total = AdvanceService.get_paged(db, tenant_no, page=page, page_size=pageSize, filters=filters)
|
||||
out_rows = [AdvanceApplyOut.model_validate(r) for r in rows]
|
||||
_fill_offset_amounts(db, tenant_no, rows, out_rows)
|
||||
return ApiResponse(data=PagedData(rows=out_rows, total=total, page=page, page_size=pageSize))
|
||||
|
||||
|
||||
@router.get("/my/stats", response_model=ApiResponse[AdvanceMyStatsOut])
|
||||
def my_advance_stats(
|
||||
db: Session = Depends(get_db),
|
||||
user: BxUserContext = Depends(get_bx_current_user),
|
||||
):
|
||||
tenant_no = _tenant(db, user)
|
||||
data = AdvanceService.my_apply_stats(db, user.id, tenant_no)
|
||||
return ApiResponse(data=AdvanceMyStatsOut.model_validate(data))
|
||||
|
||||
|
||||
@router.get("/stats/status-counts", response_model=ApiResponse[dict])
|
||||
def advance_status_counts(
|
||||
db: Session = Depends(get_db),
|
||||
user: BxUserContext = Depends(get_bx_current_user),
|
||||
):
|
||||
tenant_no = _tenant(db, user)
|
||||
return ApiResponse(data=AdvanceService.global_status_counts(db, tenant_no))
|
||||
|
||||
|
||||
@router.get("/pending-approval", response_model=ApiResponse[PagedData[AdvanceApplyOut]])
|
||||
def pending_approval(
|
||||
page: int = 1,
|
||||
pageSize: int = 10,
|
||||
keyword: str = "",
|
||||
applicantId: Optional[str] = None,
|
||||
applyDate: Optional[str] = None,
|
||||
db: Session = Depends(get_db),
|
||||
user: BxUserContext = Depends(get_bx_current_user),
|
||||
):
|
||||
tenant_no = _tenant(db, user)
|
||||
applicant_id = str(applicantId).strip() if applicantId else None
|
||||
rows, total = AdvanceService.pending_approval(
|
||||
db,
|
||||
user,
|
||||
tenant_no,
|
||||
page=page,
|
||||
page_size=pageSize,
|
||||
keyword=keyword,
|
||||
applicant_id=applicant_id,
|
||||
apply_date=applyDate,
|
||||
)
|
||||
out_rows = [AdvanceApplyOut.model_validate(r) for r in rows]
|
||||
return ApiResponse(data=PagedData(rows=out_rows, total=total, page=page, page_size=pageSize))
|
||||
|
||||
|
||||
@router.get("/pending-approval/stats", response_model=ApiResponse[AdvanceApproverPendingStatsOut])
|
||||
def advance_pending_approval_stats(
|
||||
db: Session = Depends(get_db),
|
||||
user: BxUserContext = Depends(get_bx_current_user),
|
||||
):
|
||||
tenant_no = _tenant(db, user)
|
||||
data = AdvanceService.pending_approval_stats(db, user, tenant_no)
|
||||
return ApiResponse(data=AdvanceApproverPendingStatsOut.model_validate(data))
|
||||
|
||||
|
||||
@router.get("/approved-by-me", response_model=ApiResponse[PagedData[AdvanceApplyOut]])
|
||||
def approved_by_me(
|
||||
page: int = 1,
|
||||
pageSize: int = 10,
|
||||
keyword: str = "",
|
||||
applicantId: Optional[str] = None,
|
||||
applyDate: Optional[str] = None,
|
||||
db: Session = Depends(get_db),
|
||||
user: BxUserContext = Depends(get_bx_current_user),
|
||||
):
|
||||
tenant_no = _tenant(db, user)
|
||||
applicant_id = str(applicantId).strip() if applicantId else None
|
||||
rows, total = AdvanceService.approved_by_me(
|
||||
db,
|
||||
user,
|
||||
tenant_no,
|
||||
page=page,
|
||||
page_size=pageSize,
|
||||
keyword=keyword,
|
||||
applicant_id=applicant_id,
|
||||
apply_date=applyDate,
|
||||
)
|
||||
out_rows = [AdvanceApplyOut.model_validate(r) for r in rows]
|
||||
return ApiResponse(data=PagedData(rows=out_rows, total=total, page=page, page_size=pageSize))
|
||||
|
||||
|
||||
@router.get("/{advance_id}", response_model=ApiResponse[AdvanceApplyOut])
|
||||
def get_advance(
|
||||
advance_id: str,
|
||||
db: Session = Depends(get_db),
|
||||
user: BxUserContext = Depends(get_bx_current_user),
|
||||
):
|
||||
tenant_no = _tenant(db, user)
|
||||
advance = AdvanceService.get_by_id(db, advance_id, tenant_no)
|
||||
if not advance:
|
||||
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="备用金申请不存在")
|
||||
out = AdvanceApplyOut.model_validate(advance)
|
||||
offset_map = AdvanceService.offset_amount_map(db, tenant_no, [advance_id])
|
||||
out.offset_amount = offset_map.get(advance_id, 0.0)
|
||||
return ApiResponse(data=out)
|
||||
|
||||
|
||||
@router.get("/{advance_id}/approvals", response_model=ApiResponse[List[AdvanceApprovalOut]])
|
||||
def get_approvals(
|
||||
advance_id: str,
|
||||
db: Session = Depends(get_db),
|
||||
user: BxUserContext = Depends(get_bx_current_user),
|
||||
):
|
||||
tenant_no = _tenant(db, user)
|
||||
if not AdvanceService.get_by_id(db, advance_id, tenant_no):
|
||||
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="备用金申请不存在")
|
||||
approvals = AdvanceService.get_approvals(db, advance_id, tenant_no)
|
||||
return ApiResponse(data=[AdvanceApprovalOut.model_validate(a) for a in approvals])
|
||||
|
||||
|
||||
@router.get("/{advance_id}/approval-history", response_model=ApiResponse[List[AdvanceApprovalOut]])
|
||||
def get_approval_history(
|
||||
advance_id: str,
|
||||
db: Session = Depends(get_db),
|
||||
user: BxUserContext = Depends(get_bx_current_user),
|
||||
):
|
||||
tenant_no = _tenant(db, user)
|
||||
if not AdvanceService.get_by_id(db, advance_id, tenant_no):
|
||||
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="备用金申请不存在")
|
||||
history = AdvanceService.get_approval_history(db, advance_id, tenant_no)
|
||||
return ApiResponse(data=[AdvanceApprovalOut.model_validate(a) for a in history])
|
||||
|
||||
|
||||
@router.post("/", response_model=ApiResponse[AdvanceApplyOut])
|
||||
def create_advance(
|
||||
body: AdvanceApplyCreate,
|
||||
db: Session = Depends(get_db),
|
||||
user: BxUserContext = Depends(get_bx_current_user),
|
||||
):
|
||||
tenant_no = _tenant(db, user)
|
||||
data = body.model_dump(exclude_unset=True)
|
||||
eid = data.get("expense_item_id")
|
||||
if eid:
|
||||
if not ExpenseItemService.get_by_id(db, eid, tenant_no):
|
||||
raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=f"费用项目 {eid} 不存在")
|
||||
data["applicant_id"] = user.id
|
||||
data["applicant_name"] = user.name
|
||||
data["apply_code"] = generate_apply_code(db, "BYJ", tenant_no)
|
||||
data["status"] = "draft"
|
||||
wf = (
|
||||
db.query(BxWorkflowDef)
|
||||
.filter(
|
||||
BxWorkflowDef.biz_type == "advance",
|
||||
BxWorkflowDef.tenant_no == tenant_no,
|
||||
BxWorkflowDef.del_flag == 0,
|
||||
)
|
||||
.first()
|
||||
)
|
||||
if wf:
|
||||
data["wf_id"] = wf.id
|
||||
advance = AdvanceService.create(db, data, user=user)
|
||||
db.commit()
|
||||
db.refresh(advance)
|
||||
return ApiResponse(data=AdvanceApplyOut.model_validate(advance))
|
||||
|
||||
|
||||
@router.put("/{advance_id}", response_model=ApiResponse[AdvanceApplyOut])
|
||||
def update_advance(
|
||||
advance_id: str,
|
||||
body: AdvanceApplyUpdate,
|
||||
db: Session = Depends(get_db),
|
||||
user: BxUserContext = Depends(get_bx_current_user),
|
||||
):
|
||||
tenant_no = _tenant(db, user)
|
||||
data = body.model_dump(exclude_unset=True)
|
||||
if data.get("expense_item_id"):
|
||||
eid = data["expense_item_id"]
|
||||
if not ExpenseItemService.get_by_id(db, eid, tenant_no):
|
||||
raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=f"费用项目 {eid} 不存在")
|
||||
advance = AdvanceService.update(db, advance_id, data, user=user)
|
||||
if not advance:
|
||||
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="备用金申请不存在")
|
||||
db.commit()
|
||||
db.refresh(advance)
|
||||
return ApiResponse(data=AdvanceApplyOut.model_validate(advance))
|
||||
|
||||
|
||||
@router.post("/{advance_id}/submit", response_model=ApiResponse[AdvanceApplyOut])
|
||||
def submit_advance(
|
||||
advance_id: str,
|
||||
db: Session = Depends(get_db),
|
||||
user: BxUserContext = Depends(get_bx_current_user),
|
||||
):
|
||||
advance = AdvanceService.submit(db, advance_id, user)
|
||||
if not advance:
|
||||
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="备用金申请不存在")
|
||||
db.commit()
|
||||
db.refresh(advance)
|
||||
return ApiResponse(data=AdvanceApplyOut.model_validate(advance))
|
||||
|
||||
|
||||
@router.post("/{advance_id}/approve", response_model=ApiResponse[AdvanceApplyOut])
|
||||
def approve_advance(
|
||||
advance_id: str,
|
||||
body: AdvanceApprovalCreate,
|
||||
db: Session = Depends(get_db),
|
||||
user: BxUserContext = Depends(get_bx_current_user),
|
||||
):
|
||||
advance = AdvanceService.approve(db, advance_id, user, body.approval_opinion or "")
|
||||
if not advance:
|
||||
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="备用金申请不存在或无权审批")
|
||||
db.commit()
|
||||
db.refresh(advance)
|
||||
return ApiResponse(data=AdvanceApplyOut.model_validate(advance))
|
||||
|
||||
|
||||
@router.post("/{advance_id}/reject", response_model=ApiResponse[AdvanceApplyOut])
|
||||
def reject_advance(
|
||||
advance_id: str,
|
||||
body: AdvanceApprovalCreate,
|
||||
db: Session = Depends(get_db),
|
||||
user: BxUserContext = Depends(get_bx_current_user),
|
||||
):
|
||||
advance = AdvanceService.reject(db, advance_id, user, body.approval_opinion or "")
|
||||
if not advance:
|
||||
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="备用金申请不存在或无权审批")
|
||||
db.commit()
|
||||
db.refresh(advance)
|
||||
return ApiResponse(data=AdvanceApplyOut.model_validate(advance))
|
||||
|
||||
|
||||
@router.delete("/{advance_id}", response_model=ApiResponse[None])
|
||||
def delete_advance(
|
||||
advance_id: str,
|
||||
db: Session = Depends(get_db),
|
||||
user: BxUserContext = Depends(get_bx_current_user),
|
||||
):
|
||||
tenant_no = _tenant(db, user)
|
||||
if not AdvanceService.get_by_id(db, advance_id, tenant_no):
|
||||
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="备用金申请不存在")
|
||||
AdvanceService.soft_delete(db, advance_id, user=user)
|
||||
db.commit()
|
||||
return ApiResponse(data=None)
|
||||
@@ -0,0 +1,151 @@
|
||||
import mimetypes
|
||||
from typing import List
|
||||
from urllib.parse import quote
|
||||
|
||||
from fastapi import APIRouter, Depends, File, HTTPException, Query, UploadFile, status
|
||||
from fastapi.responses import StreamingResponse
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
from app.core.bx_auth import BxUserContext, get_bx_current_user
|
||||
from app.core.database import get_db
|
||||
from app.core.tenant_context import get_tenant_no
|
||||
from app.schemas.bx.attachment import AttachmentOut
|
||||
from app.schemas.bx.common import ApiResponse
|
||||
from app.services.bx.attachment import AttachmentService
|
||||
from app.services.bx.storage import (
|
||||
download_file_bytes,
|
||||
get_preview_url,
|
||||
upload_bx_file,
|
||||
)
|
||||
|
||||
router = APIRouter(prefix="/attachments", tags=["附件管理"])
|
||||
|
||||
|
||||
def _tenant(db: Session, user: BxUserContext) -> str:
|
||||
return get_tenant_no(db, user.to_tenant_user_dict())
|
||||
|
||||
|
||||
def _parse_id_list(ids: str) -> List[str]:
|
||||
return [x.strip() for x in (ids or "").split(",") if x.strip()]
|
||||
|
||||
|
||||
@router.post("/upload", response_model=ApiResponse[AttachmentOut])
|
||||
async def upload_file(
|
||||
file: UploadFile = File(...),
|
||||
biz_type: str = "",
|
||||
biz_id: str = "0",
|
||||
db: Session = Depends(get_db),
|
||||
user: BxUserContext = Depends(get_bx_current_user),
|
||||
):
|
||||
if not file or not file.filename:
|
||||
raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail="请选择文件")
|
||||
file_data = await file.read()
|
||||
content_type = (
|
||||
file.content_type
|
||||
or mimetypes.guess_type(file.filename or "")[0]
|
||||
or "application/octet-stream"
|
||||
)
|
||||
relative_path, _full_url = upload_bx_file(
|
||||
file_data, file.filename or "unknown", biz_type=biz_type or "attachment"
|
||||
)
|
||||
biz_id_value = str(biz_id).strip() if biz_id else "0"
|
||||
data = {
|
||||
"biz_type": biz_type or "",
|
||||
"biz_id": biz_id_value or "0",
|
||||
"file_name": file.filename or "unknown",
|
||||
"file_path": relative_path,
|
||||
"file_type": content_type,
|
||||
"file_size": len(file_data),
|
||||
}
|
||||
attachment = AttachmentService.create(db, data, user=user)
|
||||
db.commit()
|
||||
db.refresh(attachment)
|
||||
return ApiResponse(data=AttachmentOut.model_validate(attachment))
|
||||
|
||||
|
||||
@router.get("/download/{attachment_id}")
|
||||
def download_file(
|
||||
attachment_id: str,
|
||||
db: Session = Depends(get_db),
|
||||
user: BxUserContext = Depends(get_bx_current_user),
|
||||
):
|
||||
tenant_no = _tenant(db, user)
|
||||
attachment = AttachmentService.get_by_id(db, attachment_id, tenant_no)
|
||||
if not attachment:
|
||||
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="附件不存在")
|
||||
try:
|
||||
file_data = download_file_bytes(attachment.file_path)
|
||||
except FileNotFoundError as exc:
|
||||
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="文件不存在") from exc
|
||||
except Exception as exc:
|
||||
raise HTTPException(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail="文件读取失败") from exc
|
||||
encoded_name = quote(attachment.file_name or "download")
|
||||
headers = {"Content-Disposition": f"attachment; filename*=UTF-8''{encoded_name}"}
|
||||
media_type = attachment.file_type or "application/octet-stream"
|
||||
return StreamingResponse(iter([file_data]), media_type=media_type, headers=headers)
|
||||
|
||||
|
||||
@router.delete("/{attachment_id}", response_model=ApiResponse[bool])
|
||||
def delete_attachment(
|
||||
attachment_id: str,
|
||||
db: Session = Depends(get_db),
|
||||
user: BxUserContext = Depends(get_bx_current_user),
|
||||
):
|
||||
tenant_no = _tenant(db, user)
|
||||
if not AttachmentService.get_by_id(db, attachment_id, tenant_no):
|
||||
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="附件不存在")
|
||||
success = AttachmentService.soft_delete(db, attachment_id, user=user)
|
||||
db.commit()
|
||||
return ApiResponse(data=success)
|
||||
|
||||
|
||||
@router.get("/preview/{attachment_id}", response_model=ApiResponse[dict])
|
||||
def preview_attachment(
|
||||
attachment_id: str,
|
||||
db: Session = Depends(get_db),
|
||||
user: BxUserContext = Depends(get_bx_current_user),
|
||||
):
|
||||
"""返回图片/附件预览 URL(MinIO 预签名或本地公开地址,对齐门户 storage 能力)。"""
|
||||
tenant_no = _tenant(db, user)
|
||||
attachment = AttachmentService.get_by_id(db, attachment_id, tenant_no)
|
||||
if not attachment:
|
||||
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="附件不存在")
|
||||
try:
|
||||
url = get_preview_url(attachment.file_path, expires_seconds=3600)
|
||||
except Exception as exc:
|
||||
raise HTTPException(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail="获取预览地址失败") from exc
|
||||
return ApiResponse(
|
||||
data={
|
||||
"url": url,
|
||||
"file_name": attachment.file_name,
|
||||
"file_type": attachment.file_type,
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
@router.get("/list", response_model=ApiResponse[List[AttachmentOut]])
|
||||
def list_by_biz(
|
||||
biz_type: str = "",
|
||||
biz_id: str = "0",
|
||||
db: Session = Depends(get_db),
|
||||
user: BxUserContext = Depends(get_bx_current_user),
|
||||
):
|
||||
tenant_no = _tenant(db, user)
|
||||
biz_id_value = str(biz_id).strip() if biz_id else "0"
|
||||
attachments = AttachmentService.get_by_biz(db, biz_type=biz_type, biz_id=biz_id_value, tenant_no=tenant_no)
|
||||
return ApiResponse(data=[AttachmentOut.model_validate(a) for a in attachments])
|
||||
|
||||
|
||||
@router.put("/bind-biz", response_model=ApiResponse[int])
|
||||
def bind_biz(
|
||||
ids: str = Query(...),
|
||||
biz_type: str = Query(...),
|
||||
biz_id: str = Query(...),
|
||||
db: Session = Depends(get_db),
|
||||
user: BxUserContext = Depends(get_bx_current_user),
|
||||
):
|
||||
id_list = _parse_id_list(ids)
|
||||
biz_id_value = str(biz_id).strip() or "0"
|
||||
count = AttachmentService.bind_biz(db, id_list, biz_type, biz_id_value, user=user)
|
||||
db.commit()
|
||||
return ApiResponse(data=count)
|
||||
@@ -0,0 +1,88 @@
|
||||
from typing import List
|
||||
|
||||
from fastapi import APIRouter, Depends, HTTPException, status
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
from app.core.bx_auth import BxUserContext, get_bx_current_user
|
||||
from app.core.database import get_db
|
||||
from app.core.tenant_context import get_tenant_no
|
||||
from app.schemas.bx.common import ApiResponse
|
||||
from app.schemas.bx.expense_item import ExpenseItemCreate, ExpenseItemOut, ExpenseItemUpdate
|
||||
from app.services.bx.expense_item import ExpenseItemService
|
||||
|
||||
router = APIRouter(prefix="/expense-items", tags=["费用项目管理"])
|
||||
|
||||
|
||||
@router.get("/tree", response_model=ApiResponse[List[ExpenseItemOut]])
|
||||
def get_expense_item_tree(
|
||||
db: Session = Depends(get_db),
|
||||
user: BxUserContext = Depends(get_bx_current_user),
|
||||
):
|
||||
tenant_no = get_tenant_no(db, user.to_tenant_user_dict())
|
||||
tree = ExpenseItemService.get_item_tree(db, tenant_no)
|
||||
return ApiResponse(data=[ExpenseItemOut.model_validate(i) for i in tree])
|
||||
|
||||
|
||||
@router.get("/{item_id}", response_model=ApiResponse[ExpenseItemOut])
|
||||
def get_expense_item(
|
||||
item_id: str,
|
||||
db: Session = Depends(get_db),
|
||||
user: BxUserContext = Depends(get_bx_current_user),
|
||||
):
|
||||
tenant_no = get_tenant_no(db, user.to_tenant_user_dict())
|
||||
item = ExpenseItemService.get_by_id(db, item_id, tenant_no)
|
||||
if not item:
|
||||
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="费用项目不存在")
|
||||
return ApiResponse(data=ExpenseItemOut.model_validate(item))
|
||||
|
||||
|
||||
@router.post("/", response_model=ApiResponse[ExpenseItemOut])
|
||||
def create_expense_item(
|
||||
body: ExpenseItemCreate,
|
||||
db: Session = Depends(get_db),
|
||||
user: BxUserContext = Depends(get_bx_current_user),
|
||||
):
|
||||
try:
|
||||
item = ExpenseItemService.create(db, body.model_dump(exclude_unset=True), user=user)
|
||||
db.commit()
|
||||
db.refresh(item)
|
||||
except ValueError as exc:
|
||||
db.rollback()
|
||||
raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=str(exc)) from exc
|
||||
return ApiResponse(data=ExpenseItemOut.model_validate(item))
|
||||
|
||||
|
||||
@router.put("/{item_id}", response_model=ApiResponse[ExpenseItemOut])
|
||||
def update_expense_item(
|
||||
item_id: str,
|
||||
body: ExpenseItemUpdate,
|
||||
db: Session = Depends(get_db),
|
||||
user: BxUserContext = Depends(get_bx_current_user),
|
||||
):
|
||||
try:
|
||||
item = ExpenseItemService.update(
|
||||
db, item_id, body.model_dump(exclude_unset=True), user=user
|
||||
)
|
||||
if not item:
|
||||
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="费用项目不存在")
|
||||
db.commit()
|
||||
db.refresh(item)
|
||||
except ValueError as exc:
|
||||
db.rollback()
|
||||
raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=str(exc)) from exc
|
||||
return ApiResponse(data=ExpenseItemOut.model_validate(item))
|
||||
|
||||
|
||||
@router.delete("/{item_id}", response_model=ApiResponse[None])
|
||||
def delete_expense_item(
|
||||
item_id: str,
|
||||
db: Session = Depends(get_db),
|
||||
user: BxUserContext = Depends(get_bx_current_user),
|
||||
):
|
||||
tenant_no = get_tenant_no(db, user.to_tenant_user_dict())
|
||||
item = ExpenseItemService.get_by_id(db, item_id, tenant_no)
|
||||
if not item:
|
||||
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="费用项目不存在")
|
||||
ExpenseItemService.soft_delete(db, item_id, user=user)
|
||||
db.commit()
|
||||
return ApiResponse(data=None)
|
||||
@@ -0,0 +1,414 @@
|
||||
import csv
|
||||
import io
|
||||
from datetime import datetime
|
||||
from typing import Any, List, Optional
|
||||
from urllib.parse import quote
|
||||
|
||||
from fastapi import APIRouter, Depends, HTTPException, status
|
||||
from fastapi.responses import StreamingResponse
|
||||
from sqlalchemy import or_
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
from app.core.bx_auth import BxUserContext, get_bx_current_user
|
||||
from app.core.database import get_db
|
||||
from app.core.tenant_context import get_tenant_no
|
||||
from app.models.bx_models import BxAdvanceApply, BxReimburseApply, BxReimburseOffset
|
||||
from app.schemas.bx.advance import (
|
||||
AdvanceFinanceIssueStatsOut,
|
||||
AdvanceIssueOut,
|
||||
AdvanceIssueRequest,
|
||||
AdvanceOffsetRecordOut,
|
||||
)
|
||||
from app.schemas.bx.common import ApiResponse, PagedData
|
||||
from app.schemas.bx.reimburse import (
|
||||
BatchOffsetRequest,
|
||||
OffsetRequest,
|
||||
PayRequest,
|
||||
PaymentFinanceStatsOut,
|
||||
ReimburseApplyOut,
|
||||
ReimburseOffsetRecordOut,
|
||||
)
|
||||
from app.services.bx.advance import AdvanceService
|
||||
from app.services.bx.attachment import AttachmentService
|
||||
from app.services.bx.reimburse import ReimburseService
|
||||
from app.utils.bx_date_range import parse_create_time_day_bounds
|
||||
|
||||
router = APIRouter(prefix="/payments", tags=["支付处理"])
|
||||
|
||||
|
||||
def _tenant(db: Session, user: BxUserContext) -> str:
|
||||
return get_tenant_no(db, user.to_tenant_user_dict())
|
||||
|
||||
|
||||
def _wrap_reimburse_rows(outs: List[ReimburseApplyOut]) -> List[dict]:
|
||||
return [{"type": "reimburse", "data": o.model_dump(by_alias=True)} for o in outs]
|
||||
|
||||
|
||||
@router.get("/pending", response_model=ApiResponse[PagedData[Any]])
|
||||
def list_pending_payments(
|
||||
page: int = 1,
|
||||
pageSize: int = 10,
|
||||
keyword: str = "",
|
||||
applicantId: Optional[str] = None,
|
||||
applyDate: Optional[str] = None,
|
||||
db: Session = Depends(get_db),
|
||||
user: BxUserContext = Depends(get_bx_current_user),
|
||||
):
|
||||
tenant_no = _tenant(db, user)
|
||||
filters = [BxReimburseApply.status == "approved"]
|
||||
if keyword:
|
||||
filters.append(
|
||||
or_(
|
||||
BxReimburseApply.apply_code.contains(keyword),
|
||||
BxReimburseApply.applicant_name.contains(keyword),
|
||||
)
|
||||
)
|
||||
if applicantId:
|
||||
filters.append(BxReimburseApply.applicant_id == str(applicantId).strip())
|
||||
bounds = parse_create_time_day_bounds(applyDate)
|
||||
if bounds:
|
||||
d0, d1 = bounds
|
||||
filters.append(BxReimburseApply.create_time >= d0)
|
||||
filters.append(BxReimburseApply.create_time < d1)
|
||||
rows, total = ReimburseService.get_paged(db, tenant_no, page=page, page_size=pageSize, filters=filters)
|
||||
outs = ReimburseService.out_rows_with_attachment_counts(db, tenant_no, list(rows))
|
||||
return ApiResponse(
|
||||
data=PagedData(rows=_wrap_reimburse_rows(outs), total=total, page=page, page_size=pageSize)
|
||||
)
|
||||
|
||||
|
||||
@router.get("/stats", response_model=ApiResponse[PaymentFinanceStatsOut])
|
||||
def payment_finance_stats(
|
||||
db: Session = Depends(get_db),
|
||||
user: BxUserContext = Depends(get_bx_current_user),
|
||||
):
|
||||
tenant_no = _tenant(db, user)
|
||||
data = ReimburseService.finance_payment_stats(db, tenant_no)
|
||||
return ApiResponse(data=PaymentFinanceStatsOut.model_validate(data))
|
||||
|
||||
|
||||
@router.get("/processed", response_model=ApiResponse[PagedData[Any]])
|
||||
def list_processed_payments(
|
||||
page: int = 1,
|
||||
pageSize: int = 10,
|
||||
keyword: str = "",
|
||||
applicantId: Optional[str] = None,
|
||||
applyDate: Optional[str] = None,
|
||||
db: Session = Depends(get_db),
|
||||
user: BxUserContext = Depends(get_bx_current_user),
|
||||
):
|
||||
tenant_no = _tenant(db, user)
|
||||
filters = [BxReimburseApply.status.in_(["processed", "paid", "offset"])]
|
||||
if keyword:
|
||||
filters.append(
|
||||
or_(
|
||||
BxReimburseApply.apply_code.contains(keyword),
|
||||
BxReimburseApply.applicant_name.contains(keyword),
|
||||
)
|
||||
)
|
||||
if applicantId:
|
||||
filters.append(BxReimburseApply.applicant_id == str(applicantId).strip())
|
||||
bounds = parse_create_time_day_bounds(applyDate)
|
||||
if bounds:
|
||||
d0, d1 = bounds
|
||||
filters.append(BxReimburseApply.create_time >= d0)
|
||||
filters.append(BxReimburseApply.create_time < d1)
|
||||
rows, total = ReimburseService.get_paged(db, tenant_no, page=page, page_size=pageSize, filters=filters)
|
||||
outs = ReimburseService.out_rows_with_attachment_counts(db, tenant_no, list(rows))
|
||||
return ApiResponse(
|
||||
data=PagedData(rows=_wrap_reimburse_rows(outs), total=total, page=page, page_size=pageSize)
|
||||
)
|
||||
|
||||
|
||||
@router.post("/{payment_id}/pay", response_model=ApiResponse[ReimburseApplyOut])
|
||||
def pay(
|
||||
payment_id: str,
|
||||
body: Optional[PayRequest] = None,
|
||||
db: Session = Depends(get_db),
|
||||
user: BxUserContext = Depends(get_bx_current_user),
|
||||
):
|
||||
tenant_no = _tenant(db, user)
|
||||
pay_remark = body.pay_remark if body else ""
|
||||
actual_amount = body.actual_amount if body else None
|
||||
reimburse = ReimburseService.pay(
|
||||
db, payment_id, user, pay_remark=pay_remark or "", actual_amount=actual_amount
|
||||
)
|
||||
if not reimburse:
|
||||
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="支付记录不存在")
|
||||
db.commit()
|
||||
db.refresh(reimburse)
|
||||
return ApiResponse(data=ReimburseService.out_one_with_attachment_counts(db, tenant_no, reimburse))
|
||||
|
||||
|
||||
@router.post("/{payment_id}/offset", response_model=ApiResponse[ReimburseApplyOut])
|
||||
def offset(
|
||||
payment_id: str,
|
||||
body: OffsetRequest,
|
||||
db: Session = Depends(get_db),
|
||||
user: BxUserContext = Depends(get_bx_current_user),
|
||||
):
|
||||
tenant_no = _tenant(db, user)
|
||||
reimburse = ReimburseService.offset(
|
||||
db,
|
||||
payment_id,
|
||||
body.advance_id,
|
||||
body.offset_amount,
|
||||
user,
|
||||
remark=body.remark or "",
|
||||
)
|
||||
if not reimburse:
|
||||
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="支付记录不存在")
|
||||
db.commit()
|
||||
db.refresh(reimburse)
|
||||
return ApiResponse(data=ReimburseService.out_one_with_attachment_counts(db, tenant_no, reimburse))
|
||||
|
||||
|
||||
@router.post("/{payment_id}/batch-offset", response_model=ApiResponse[ReimburseApplyOut])
|
||||
def batch_offset(
|
||||
payment_id: str,
|
||||
body: BatchOffsetRequest,
|
||||
db: Session = Depends(get_db),
|
||||
user: BxUserContext = Depends(get_bx_current_user),
|
||||
):
|
||||
tenant_no = _tenant(db, user)
|
||||
reimburse = ReimburseService.batch_offset(
|
||||
db,
|
||||
payment_id,
|
||||
[item.model_dump() for item in body.items],
|
||||
body.pay_amount,
|
||||
user,
|
||||
remark=body.remark or "",
|
||||
)
|
||||
if not reimburse:
|
||||
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="支付记录不存在")
|
||||
db.commit()
|
||||
db.refresh(reimburse)
|
||||
return ApiResponse(data=ReimburseService.out_one_with_attachment_counts(db, tenant_no, reimburse))
|
||||
|
||||
|
||||
@router.get("/advance-issues", response_model=ApiResponse[PagedData[AdvanceIssueOut]])
|
||||
def list_advance_issues(
|
||||
page: int = 1,
|
||||
pageSize: int = 10,
|
||||
issue_status: Optional[str] = None,
|
||||
keyword: str = "",
|
||||
applicantId: Optional[str] = None,
|
||||
applyDate: Optional[str] = None,
|
||||
db: Session = Depends(get_db),
|
||||
user: BxUserContext = Depends(get_bx_current_user),
|
||||
):
|
||||
tenant_no = _tenant(db, user)
|
||||
filters = []
|
||||
if issue_status == "pending":
|
||||
filters.append(BxAdvanceApply.status == "approved")
|
||||
filters.append(or_(BxAdvanceApply.issue_status.is_(None), BxAdvanceApply.issue_status != "issued"))
|
||||
elif issue_status == "issued":
|
||||
filters.append(BxAdvanceApply.status == "issued")
|
||||
else:
|
||||
filters.append(or_(BxAdvanceApply.status == "approved", BxAdvanceApply.status == "issued"))
|
||||
if keyword:
|
||||
filters.append(
|
||||
or_(
|
||||
BxAdvanceApply.apply_code.contains(keyword),
|
||||
BxAdvanceApply.applicant_name.contains(keyword),
|
||||
)
|
||||
)
|
||||
if applicantId:
|
||||
filters.append(BxAdvanceApply.applicant_id == str(applicantId).strip())
|
||||
bounds = parse_create_time_day_bounds(applyDate)
|
||||
if bounds:
|
||||
d0, d1 = bounds
|
||||
filters.append(BxAdvanceApply.create_time >= d0)
|
||||
filters.append(BxAdvanceApply.create_time < d1)
|
||||
rows, total = AdvanceService.get_paged(db, tenant_no, page=page, page_size=pageSize, filters=filters)
|
||||
out_rows = [AdvanceIssueOut.model_validate(r) for r in rows]
|
||||
if out_rows:
|
||||
offset_map = AdvanceService.offset_amount_map(db, tenant_no, [r.id for r in rows])
|
||||
for out_row in out_rows:
|
||||
out_row.offset_amount = offset_map.get(out_row.id, 0.0)
|
||||
return ApiResponse(data=PagedData(rows=out_rows, total=total, page=page, page_size=pageSize))
|
||||
|
||||
|
||||
@router.get("/advance-issues/stats", response_model=ApiResponse[AdvanceFinanceIssueStatsOut])
|
||||
def advance_issue_stats(
|
||||
db: Session = Depends(get_db),
|
||||
user: BxUserContext = Depends(get_bx_current_user),
|
||||
):
|
||||
tenant_no = _tenant(db, user)
|
||||
data = AdvanceService.finance_issue_stats(db, tenant_no)
|
||||
return ApiResponse(data=AdvanceFinanceIssueStatsOut.model_validate(data))
|
||||
|
||||
|
||||
@router.get("/advance-issues/export")
|
||||
def export_advance_issues(
|
||||
issue_status: Optional[str] = None,
|
||||
keyword: str = "",
|
||||
applicantId: Optional[str] = None,
|
||||
applyDate: Optional[str] = None,
|
||||
db: Session = Depends(get_db),
|
||||
user: BxUserContext = Depends(get_bx_current_user),
|
||||
):
|
||||
tenant_no = _tenant(db, user)
|
||||
filters = []
|
||||
if issue_status == "pending":
|
||||
filters.append(BxAdvanceApply.status == "approved")
|
||||
filters.append(or_(BxAdvanceApply.issue_status.is_(None), BxAdvanceApply.issue_status != "issued"))
|
||||
elif issue_status == "issued":
|
||||
filters.append(BxAdvanceApply.status == "issued")
|
||||
else:
|
||||
filters.append(or_(BxAdvanceApply.status == "approved", BxAdvanceApply.status == "issued"))
|
||||
if keyword:
|
||||
filters.append(
|
||||
or_(
|
||||
BxAdvanceApply.apply_code.contains(keyword),
|
||||
BxAdvanceApply.applicant_name.contains(keyword),
|
||||
)
|
||||
)
|
||||
if applicantId:
|
||||
filters.append(BxAdvanceApply.applicant_id == str(applicantId).strip())
|
||||
bounds = parse_create_time_day_bounds(applyDate)
|
||||
if bounds:
|
||||
d0, d1 = bounds
|
||||
filters.append(BxAdvanceApply.create_time >= d0)
|
||||
filters.append(BxAdvanceApply.create_time < d1)
|
||||
rows, _ = AdvanceService.get_paged(db, tenant_no, page=1, page_size=99999, filters=filters)
|
||||
out_rows = [AdvanceIssueOut.model_validate(r) for r in rows]
|
||||
|
||||
buf = io.StringIO()
|
||||
writer = csv.writer(buf)
|
||||
writer.writerow(
|
||||
[
|
||||
"申请单号",
|
||||
"申请人",
|
||||
"申请原因",
|
||||
"申请金额",
|
||||
"审批通过时间",
|
||||
"发放状态",
|
||||
"发放时间",
|
||||
"发放操作人",
|
||||
"实际发放金额",
|
||||
"发放备注",
|
||||
]
|
||||
)
|
||||
for row in out_rows:
|
||||
writer.writerow(
|
||||
[
|
||||
row.apply_code,
|
||||
row.applicant_name,
|
||||
row.reason,
|
||||
row.amount,
|
||||
row.approve_time or "",
|
||||
"已发放" if row.issue_status == "issued" else "待发放",
|
||||
row.issue_time or "",
|
||||
row.issue_user_name or "",
|
||||
row.actual_amount or "",
|
||||
row.issue_remark or "",
|
||||
]
|
||||
)
|
||||
buf.seek(0)
|
||||
filename = f"备用金发放列表_{datetime.now().strftime('%Y%m%d_%H%M%S')}.csv"
|
||||
encoded_name = quote(filename)
|
||||
return StreamingResponse(
|
||||
iter([buf.getvalue()]),
|
||||
media_type="text/csv; charset=utf-8",
|
||||
headers={"Content-Disposition": f"attachment; filename*=UTF-8''{encoded_name}"},
|
||||
)
|
||||
|
||||
|
||||
@router.post("/advance/{advance_id}/issue", response_model=ApiResponse[AdvanceIssueOut])
|
||||
def issue_advance(
|
||||
advance_id: str,
|
||||
body: AdvanceIssueRequest,
|
||||
db: Session = Depends(get_db),
|
||||
user: BxUserContext = Depends(get_bx_current_user),
|
||||
):
|
||||
tenant_no = _tenant(db, user)
|
||||
issue_atts = AttachmentService.get_by_biz(db, "advance_issue", advance_id, tenant_no)
|
||||
if not issue_atts:
|
||||
raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail="请至少上传 1 个发放附件")
|
||||
advance = AdvanceService.issue(
|
||||
db, advance_id, user, body.issue_remark or "", body.actual_amount
|
||||
)
|
||||
if not advance:
|
||||
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="备用金申请不存在")
|
||||
db.commit()
|
||||
db.refresh(advance)
|
||||
out = AdvanceIssueOut.model_validate(advance)
|
||||
offset_map = AdvanceService.offset_amount_map(db, tenant_no, [advance_id])
|
||||
out.offset_amount = offset_map.get(advance_id, 0.0)
|
||||
return ApiResponse(data=out)
|
||||
|
||||
|
||||
@router.get("/advance/{advance_id}/offset-records", response_model=ApiResponse[List[AdvanceOffsetRecordOut]])
|
||||
def list_advance_offset_records(
|
||||
advance_id: str,
|
||||
db: Session = Depends(get_db),
|
||||
user: BxUserContext = Depends(get_bx_current_user),
|
||||
):
|
||||
tenant_no = _tenant(db, user)
|
||||
rows = (
|
||||
db.query(BxReimburseOffset, BxReimburseApply)
|
||||
.join(
|
||||
BxReimburseApply,
|
||||
BxReimburseApply.id == BxReimburseOffset.reimburse_id,
|
||||
)
|
||||
.filter(
|
||||
BxReimburseOffset.advance_id == advance_id,
|
||||
BxReimburseOffset.tenant_no == tenant_no,
|
||||
BxReimburseOffset.del_flag == 0,
|
||||
BxReimburseApply.del_flag == 0,
|
||||
BxReimburseApply.tenant_no == tenant_no,
|
||||
)
|
||||
.order_by(BxReimburseOffset.create_time.desc(), BxReimburseOffset.id.desc())
|
||||
.all()
|
||||
)
|
||||
records = [
|
||||
AdvanceOffsetRecordOut(
|
||||
reimburse_id=reimburse.id,
|
||||
reimburse_apply_code=reimburse.apply_code,
|
||||
reimburse_title=reimburse.title,
|
||||
reimburse_applicant_name=reimburse.applicant_name,
|
||||
offset_amount=float(offset.offset_amount or 0),
|
||||
remark=offset.remark,
|
||||
operator=offset.create_by,
|
||||
create_time=offset.create_time,
|
||||
)
|
||||
for offset, reimburse in rows
|
||||
]
|
||||
return ApiResponse(data=records)
|
||||
|
||||
|
||||
@router.get("/{payment_id}/offset-records", response_model=ApiResponse[List[ReimburseOffsetRecordOut]])
|
||||
def list_reimburse_offset_records(
|
||||
payment_id: str,
|
||||
db: Session = Depends(get_db),
|
||||
user: BxUserContext = Depends(get_bx_current_user),
|
||||
):
|
||||
tenant_no = _tenant(db, user)
|
||||
rows = (
|
||||
db.query(BxReimburseOffset, BxAdvanceApply)
|
||||
.join(BxAdvanceApply, BxAdvanceApply.id == BxReimburseOffset.advance_id)
|
||||
.filter(
|
||||
BxReimburseOffset.reimburse_id == payment_id,
|
||||
BxReimburseOffset.tenant_no == tenant_no,
|
||||
BxReimburseOffset.del_flag == 0,
|
||||
BxAdvanceApply.del_flag == 0,
|
||||
BxAdvanceApply.tenant_no == tenant_no,
|
||||
)
|
||||
.order_by(BxReimburseOffset.create_time.desc(), BxReimburseOffset.id.desc())
|
||||
.all()
|
||||
)
|
||||
records = [
|
||||
ReimburseOffsetRecordOut(
|
||||
advance_id=advance.id,
|
||||
advance_apply_code=advance.apply_code,
|
||||
advance_applicant_name=advance.applicant_name,
|
||||
advance_reason=advance.reason,
|
||||
offset_amount=float(offset.offset_amount or 0),
|
||||
remark=offset.remark,
|
||||
operator=offset.create_by,
|
||||
create_time=offset.create_time,
|
||||
)
|
||||
for offset, advance in rows
|
||||
]
|
||||
return ApiResponse(data=records)
|
||||
@@ -0,0 +1,373 @@
|
||||
from typing import List, Optional
|
||||
|
||||
from fastapi import APIRouter, Depends, HTTPException, status
|
||||
from sqlalchemy import or_
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
from app.core.bx_auth import BxUserContext, get_bx_current_user
|
||||
from app.core.database import get_db
|
||||
from app.core.tenant_context import get_tenant_no
|
||||
from app.models.bx_models import BxReimburseApply, BxWorkflowDef
|
||||
from app.schemas.bx.common import ApiResponse, PagedData
|
||||
from app.schemas.bx.reimburse import (
|
||||
ReimburseApplyCreate,
|
||||
ReimburseApplyOut,
|
||||
ReimburseApplyUpdate,
|
||||
ReimburseApprovalCreate,
|
||||
ReimburseApprovalOut,
|
||||
ReimburseApproverPendingStatsOut,
|
||||
ReimburseMyStatsOut,
|
||||
)
|
||||
from app.services.bx.expense_item import ExpenseItemService
|
||||
from app.services.bx.reimburse import ReimburseService
|
||||
from app.utils.bx_codegen import generate_apply_code, generate_title
|
||||
from app.utils.bx_date_range import parse_create_time_day_bounds
|
||||
|
||||
router = APIRouter(prefix="/reimburses", tags=["报销管理"])
|
||||
|
||||
|
||||
def _tenant(db: Session, user: BxUserContext) -> str:
|
||||
return get_tenant_no(db, user.to_tenant_user_dict())
|
||||
|
||||
|
||||
def _build_details_data(db: Session, tenant_no: str, body_details) -> List[dict]:
|
||||
details_data: List[dict] = []
|
||||
for d in body_details:
|
||||
item = ExpenseItemService.get_by_id(db, d.expense_item_id, tenant_no)
|
||||
if not item:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_400_BAD_REQUEST,
|
||||
detail=f"费用项目 {d.expense_item_id} 不存在",
|
||||
)
|
||||
details_data.append(
|
||||
{
|
||||
"expense_id": d.expense_item_id,
|
||||
"expense_name": item.item_name,
|
||||
"amount": d.amount,
|
||||
"remark": d.remark,
|
||||
}
|
||||
)
|
||||
return details_data
|
||||
|
||||
|
||||
@router.get("/generate-title", response_model=ApiResponse[str])
|
||||
def get_generated_title(
|
||||
db: Session = Depends(get_db),
|
||||
user: BxUserContext = Depends(get_bx_current_user),
|
||||
):
|
||||
tenant_no = _tenant(db, user)
|
||||
title = generate_title(db, user.name, tenant_no)
|
||||
return ApiResponse(data=title)
|
||||
|
||||
|
||||
@router.get("/", response_model=ApiResponse[PagedData[ReimburseApplyOut]])
|
||||
def list_reimburses(
|
||||
page: int = 1,
|
||||
pageSize: int = 10,
|
||||
status: Optional[str] = None,
|
||||
keyword: str = "",
|
||||
expense_id: Optional[str] = None,
|
||||
applicantId: Optional[str] = None,
|
||||
applyDate: Optional[str] = None,
|
||||
db: Session = Depends(get_db),
|
||||
user: BxUserContext = Depends(get_bx_current_user),
|
||||
):
|
||||
tenant_no = _tenant(db, user)
|
||||
filters = []
|
||||
if status:
|
||||
filters.append(BxReimburseApply.status == status)
|
||||
if keyword:
|
||||
filters.append(
|
||||
or_(
|
||||
BxReimburseApply.apply_code.contains(keyword),
|
||||
BxReimburseApply.applicant_name.contains(keyword),
|
||||
)
|
||||
)
|
||||
if expense_id:
|
||||
filters.append(BxReimburseApply.expense_id == str(expense_id).strip())
|
||||
if applicantId:
|
||||
filters.append(BxReimburseApply.applicant_id == str(applicantId).strip())
|
||||
bounds = parse_create_time_day_bounds(applyDate)
|
||||
if bounds:
|
||||
d0, d1 = bounds
|
||||
filters.append(BxReimburseApply.create_time >= d0)
|
||||
filters.append(BxReimburseApply.create_time < d1)
|
||||
rows, total = ReimburseService.get_paged(db, tenant_no, page=page, page_size=pageSize, filters=filters)
|
||||
out_rows = ReimburseService.out_rows_with_attachment_counts(db, tenant_no, list(rows))
|
||||
return ApiResponse(data=PagedData(rows=out_rows, total=total, page=page, page_size=pageSize))
|
||||
|
||||
|
||||
@router.get("/my", response_model=ApiResponse[PagedData[ReimburseApplyOut]])
|
||||
def my_reimburses(
|
||||
page: int = 1,
|
||||
pageSize: int = 10,
|
||||
status: Optional[str] = None,
|
||||
keyword: str = "",
|
||||
applyDate: Optional[str] = None,
|
||||
db: Session = Depends(get_db),
|
||||
user: BxUserContext = Depends(get_bx_current_user),
|
||||
):
|
||||
tenant_no = _tenant(db, user)
|
||||
filters = [
|
||||
or_(
|
||||
BxReimburseApply.applicant_id == user.id,
|
||||
BxReimburseApply.create_by == user.id,
|
||||
)
|
||||
]
|
||||
if status:
|
||||
filters.append(BxReimburseApply.status == status)
|
||||
if keyword:
|
||||
filters.append(
|
||||
or_(
|
||||
BxReimburseApply.apply_code.contains(keyword),
|
||||
BxReimburseApply.applicant_name.contains(keyword),
|
||||
)
|
||||
)
|
||||
bounds = parse_create_time_day_bounds(applyDate)
|
||||
if bounds:
|
||||
d0, d1 = bounds
|
||||
filters.append(BxReimburseApply.create_time >= d0)
|
||||
filters.append(BxReimburseApply.create_time < d1)
|
||||
rows, total = ReimburseService.get_paged(db, tenant_no, page=page, page_size=pageSize, filters=filters)
|
||||
out_rows = ReimburseService.out_rows_with_attachment_counts(db, tenant_no, list(rows))
|
||||
return ApiResponse(data=PagedData(rows=out_rows, total=total, page=page, page_size=pageSize))
|
||||
|
||||
|
||||
@router.get("/my/stats", response_model=ApiResponse[ReimburseMyStatsOut])
|
||||
def my_reimburse_stats(
|
||||
db: Session = Depends(get_db),
|
||||
user: BxUserContext = Depends(get_bx_current_user),
|
||||
):
|
||||
tenant_no = _tenant(db, user)
|
||||
data = ReimburseService.my_apply_stats(db, user.id, tenant_no)
|
||||
return ApiResponse(data=ReimburseMyStatsOut.model_validate(data))
|
||||
|
||||
|
||||
@router.get("/stats/status-counts", response_model=ApiResponse[dict])
|
||||
def reimburse_status_counts(
|
||||
db: Session = Depends(get_db),
|
||||
user: BxUserContext = Depends(get_bx_current_user),
|
||||
):
|
||||
tenant_no = _tenant(db, user)
|
||||
return ApiResponse(data=ReimburseService.global_status_counts(db, tenant_no))
|
||||
|
||||
|
||||
@router.get("/pending-approval", response_model=ApiResponse[PagedData[ReimburseApplyOut]])
|
||||
def pending_approval(
|
||||
page: int = 1,
|
||||
pageSize: int = 10,
|
||||
keyword: str = "",
|
||||
applicantId: Optional[str] = None,
|
||||
applyDate: Optional[str] = None,
|
||||
db: Session = Depends(get_db),
|
||||
user: BxUserContext = Depends(get_bx_current_user),
|
||||
):
|
||||
tenant_no = _tenant(db, user)
|
||||
applicant_id = str(applicantId).strip() if applicantId else None
|
||||
rows, total = ReimburseService.pending_approval(
|
||||
db,
|
||||
user,
|
||||
tenant_no,
|
||||
page=page,
|
||||
page_size=pageSize,
|
||||
keyword=keyword,
|
||||
applicant_id=applicant_id,
|
||||
apply_date=applyDate,
|
||||
)
|
||||
out_rows = ReimburseService.out_rows_with_attachment_counts(db, tenant_no, list(rows))
|
||||
return ApiResponse(data=PagedData(rows=out_rows, total=total, page=page, page_size=pageSize))
|
||||
|
||||
|
||||
@router.get("/pending-approval/stats", response_model=ApiResponse[ReimburseApproverPendingStatsOut])
|
||||
def pending_approval_stats(
|
||||
db: Session = Depends(get_db),
|
||||
user: BxUserContext = Depends(get_bx_current_user),
|
||||
):
|
||||
tenant_no = _tenant(db, user)
|
||||
data = ReimburseService.pending_approval_stats(db, user, tenant_no)
|
||||
return ApiResponse(data=ReimburseApproverPendingStatsOut.model_validate(data))
|
||||
|
||||
|
||||
@router.get("/approved-by-me", response_model=ApiResponse[PagedData[ReimburseApplyOut]])
|
||||
def approved_by_me(
|
||||
page: int = 1,
|
||||
pageSize: int = 10,
|
||||
keyword: str = "",
|
||||
applicantId: Optional[str] = None,
|
||||
applyDate: Optional[str] = None,
|
||||
db: Session = Depends(get_db),
|
||||
user: BxUserContext = Depends(get_bx_current_user),
|
||||
):
|
||||
tenant_no = _tenant(db, user)
|
||||
applicant_id = str(applicantId).strip() if applicantId else None
|
||||
rows, total = ReimburseService.approved_by_me(
|
||||
db,
|
||||
user,
|
||||
tenant_no,
|
||||
page=page,
|
||||
page_size=pageSize,
|
||||
keyword=keyword,
|
||||
applicant_id=applicant_id,
|
||||
apply_date=applyDate,
|
||||
)
|
||||
out_rows = ReimburseService.out_rows_with_attachment_counts(db, tenant_no, list(rows))
|
||||
return ApiResponse(data=PagedData(rows=out_rows, total=total, page=page, page_size=pageSize))
|
||||
|
||||
|
||||
@router.get("/{reimburse_id}", response_model=ApiResponse[ReimburseApplyOut])
|
||||
def get_reimburse(
|
||||
reimburse_id: str,
|
||||
db: Session = Depends(get_db),
|
||||
user: BxUserContext = Depends(get_bx_current_user),
|
||||
):
|
||||
tenant_no = _tenant(db, user)
|
||||
reimburse = ReimburseService.get_by_id(db, reimburse_id, tenant_no)
|
||||
if not reimburse:
|
||||
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="报销单不存在")
|
||||
out = ReimburseService.build_apply_out_with_details(db, tenant_no, reimburse)
|
||||
return ApiResponse(data=out)
|
||||
|
||||
|
||||
@router.get("/{reimburse_id}/approvals", response_model=ApiResponse[List[ReimburseApprovalOut]])
|
||||
def get_approvals(
|
||||
reimburse_id: str,
|
||||
db: Session = Depends(get_db),
|
||||
user: BxUserContext = Depends(get_bx_current_user),
|
||||
):
|
||||
tenant_no = _tenant(db, user)
|
||||
if not ReimburseService.get_by_id(db, reimburse_id, tenant_no):
|
||||
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="报销单不存在")
|
||||
approvals = ReimburseService.get_approvals(db, reimburse_id, tenant_no)
|
||||
return ApiResponse(data=[ReimburseApprovalOut.model_validate(a) for a in approvals])
|
||||
|
||||
|
||||
@router.get("/{reimburse_id}/approval-history", response_model=ApiResponse[List[ReimburseApprovalOut]])
|
||||
def get_approval_history(
|
||||
reimburse_id: str,
|
||||
db: Session = Depends(get_db),
|
||||
user: BxUserContext = Depends(get_bx_current_user),
|
||||
):
|
||||
tenant_no = _tenant(db, user)
|
||||
if not ReimburseService.get_by_id(db, reimburse_id, tenant_no):
|
||||
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="报销单不存在")
|
||||
history = ReimburseService.get_approval_history(db, reimburse_id, tenant_no)
|
||||
return ApiResponse(data=[ReimburseApprovalOut.model_validate(a) for a in history])
|
||||
|
||||
|
||||
@router.post("/", response_model=ApiResponse[ReimburseApplyOut])
|
||||
def create_reimburse(
|
||||
body: ReimburseApplyCreate,
|
||||
db: Session = Depends(get_db),
|
||||
user: BxUserContext = Depends(get_bx_current_user),
|
||||
):
|
||||
tenant_no = _tenant(db, user)
|
||||
details_data = _build_details_data(db, tenant_no, body.details)
|
||||
data = {
|
||||
"apply_code": generate_apply_code(db, "BX", tenant_no),
|
||||
"status": "draft",
|
||||
"remark": body.remark,
|
||||
}
|
||||
if body.title:
|
||||
data["title"] = body.title
|
||||
wf = (
|
||||
db.query(BxWorkflowDef)
|
||||
.filter(
|
||||
BxWorkflowDef.biz_type == "reimburse",
|
||||
BxWorkflowDef.tenant_no == tenant_no,
|
||||
BxWorkflowDef.del_flag == 0,
|
||||
)
|
||||
.first()
|
||||
)
|
||||
if wf:
|
||||
data["wf_id"] = wf.id
|
||||
reimburse = ReimburseService.create_with_details(db, data, details_data, user=user)
|
||||
db.commit()
|
||||
db.refresh(reimburse)
|
||||
out = ReimburseService.build_apply_out_with_details(db, tenant_no, reimburse)
|
||||
return ApiResponse(data=out)
|
||||
|
||||
|
||||
@router.put("/{reimburse_id}", response_model=ApiResponse[ReimburseApplyOut])
|
||||
def update_reimburse(
|
||||
reimburse_id: str,
|
||||
body: ReimburseApplyUpdate,
|
||||
db: Session = Depends(get_db),
|
||||
user: BxUserContext = Depends(get_bx_current_user),
|
||||
):
|
||||
tenant_no = _tenant(db, user)
|
||||
details_data = None
|
||||
if body.details is not None:
|
||||
details_data = _build_details_data(db, tenant_no, body.details)
|
||||
main_data = {}
|
||||
if body.remark is not None:
|
||||
main_data["remark"] = body.remark
|
||||
reimburse = ReimburseService.update_with_details(
|
||||
db, reimburse_id, main_data, details_data, user=user
|
||||
)
|
||||
if not reimburse:
|
||||
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="报销单不存在")
|
||||
db.commit()
|
||||
db.refresh(reimburse)
|
||||
out = ReimburseService.build_apply_out_with_details(db, tenant_no, reimburse)
|
||||
return ApiResponse(data=out)
|
||||
|
||||
|
||||
@router.post("/{reimburse_id}/submit", response_model=ApiResponse[ReimburseApplyOut])
|
||||
def submit_reimburse(
|
||||
reimburse_id: str,
|
||||
db: Session = Depends(get_db),
|
||||
user: BxUserContext = Depends(get_bx_current_user),
|
||||
):
|
||||
tenant_no = _tenant(db, user)
|
||||
reimburse = ReimburseService.submit(db, reimburse_id, user)
|
||||
if not reimburse:
|
||||
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="报销单不存在")
|
||||
db.commit()
|
||||
db.refresh(reimburse)
|
||||
return ApiResponse(data=ReimburseService.out_one_with_attachment_counts(db, tenant_no, reimburse))
|
||||
|
||||
|
||||
@router.post("/{reimburse_id}/approve", response_model=ApiResponse[ReimburseApplyOut])
|
||||
def approve_reimburse(
|
||||
reimburse_id: str,
|
||||
body: ReimburseApprovalCreate,
|
||||
db: Session = Depends(get_db),
|
||||
user: BxUserContext = Depends(get_bx_current_user),
|
||||
):
|
||||
tenant_no = _tenant(db, user)
|
||||
reimburse = ReimburseService.approve(db, reimburse_id, user, body.approval_opinion or "")
|
||||
if not reimburse:
|
||||
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="报销单不存在或无权审批")
|
||||
db.commit()
|
||||
db.refresh(reimburse)
|
||||
return ApiResponse(data=ReimburseService.out_one_with_attachment_counts(db, tenant_no, reimburse))
|
||||
|
||||
|
||||
@router.post("/{reimburse_id}/reject", response_model=ApiResponse[ReimburseApplyOut])
|
||||
def reject_reimburse(
|
||||
reimburse_id: str,
|
||||
body: ReimburseApprovalCreate,
|
||||
db: Session = Depends(get_db),
|
||||
user: BxUserContext = Depends(get_bx_current_user),
|
||||
):
|
||||
tenant_no = _tenant(db, user)
|
||||
reimburse = ReimburseService.reject(db, reimburse_id, user, body.approval_opinion or "")
|
||||
if not reimburse:
|
||||
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="报销单不存在或无权审批")
|
||||
db.commit()
|
||||
db.refresh(reimburse)
|
||||
return ApiResponse(data=ReimburseService.out_one_with_attachment_counts(db, tenant_no, reimburse))
|
||||
|
||||
|
||||
@router.delete("/{reimburse_id}", response_model=ApiResponse[None])
|
||||
def delete_reimburse(
|
||||
reimburse_id: str,
|
||||
db: Session = Depends(get_db),
|
||||
user: BxUserContext = Depends(get_bx_current_user),
|
||||
):
|
||||
tenant_no = _tenant(db, user)
|
||||
if not ReimburseService.get_by_id(db, reimburse_id, tenant_no):
|
||||
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="报销单不存在")
|
||||
ReimburseService.soft_delete(db, reimburse_id, user=user)
|
||||
db.commit()
|
||||
return ApiResponse(data=None)
|
||||
@@ -0,0 +1,130 @@
|
||||
from typing import List
|
||||
|
||||
from fastapi import APIRouter, Depends, HTTPException, status
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
from app.core.bx_auth import BxUserContext, get_bx_current_user
|
||||
from app.core.database import get_db
|
||||
from app.core.tenant_context import get_tenant_no
|
||||
from app.schemas.bx.common import ApiResponse, PagedData
|
||||
from app.schemas.bx.workflow import (
|
||||
WorkflowDefCreate,
|
||||
WorkflowDefOut,
|
||||
WorkflowDefUpdate,
|
||||
WorkflowNodeCreate,
|
||||
)
|
||||
from app.services.bx.workflow import WorkflowService
|
||||
|
||||
router = APIRouter(prefix="/workflows", tags=["工作流配置"])
|
||||
|
||||
|
||||
@router.get("/", response_model=ApiResponse[PagedData[WorkflowDefOut]])
|
||||
def list_workflows(
|
||||
page: int = 1,
|
||||
pageSize: int = 10,
|
||||
db: Session = Depends(get_db),
|
||||
user: BxUserContext = Depends(get_bx_current_user),
|
||||
):
|
||||
tenant_no = get_tenant_no(db, user.to_tenant_user_dict())
|
||||
rows, total = WorkflowService.get_paged(db, tenant_no, page=page, page_size=pageSize)
|
||||
out_rows = [WorkflowDefOut.model_validate(r) for r in rows]
|
||||
paged_data = PagedData(rows=out_rows, total=total, page=page, page_size=pageSize)
|
||||
return ApiResponse(data=paged_data)
|
||||
|
||||
|
||||
@router.get("/biz/{biz_type}", response_model=ApiResponse[WorkflowDefOut])
|
||||
def get_workflow_by_biz_type(
|
||||
biz_type: str,
|
||||
db: Session = Depends(get_db),
|
||||
user: BxUserContext = Depends(get_bx_current_user),
|
||||
):
|
||||
workflow = WorkflowService.ensure_by_biz_type(db, biz_type, user=user)
|
||||
if not workflow:
|
||||
return ApiResponse(data=None)
|
||||
return ApiResponse(data=WorkflowDefOut.model_validate(workflow))
|
||||
|
||||
|
||||
@router.get("/{workflow_id}", response_model=ApiResponse[WorkflowDefOut])
|
||||
def get_workflow(
|
||||
workflow_id: str,
|
||||
db: Session = Depends(get_db),
|
||||
user: BxUserContext = Depends(get_bx_current_user),
|
||||
):
|
||||
tenant_no = get_tenant_no(db, user.to_tenant_user_dict())
|
||||
workflow = WorkflowService.get_by_id(db, workflow_id, tenant_no)
|
||||
if not workflow:
|
||||
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="工作流不存在")
|
||||
return ApiResponse(data=WorkflowDefOut.model_validate(workflow))
|
||||
|
||||
|
||||
@router.post("/", response_model=ApiResponse[WorkflowDefOut])
|
||||
def create_workflow(
|
||||
body: WorkflowDefCreate,
|
||||
db: Session = Depends(get_db),
|
||||
user: BxUserContext = Depends(get_bx_current_user),
|
||||
):
|
||||
data = body.model_dump(exclude_unset=True)
|
||||
nodes_data = data.pop("nodes", []) or []
|
||||
workflow = WorkflowService.create(db, data, user=user)
|
||||
if nodes_data:
|
||||
WorkflowService.save_nodes(db, workflow.id, nodes_data, user=user)
|
||||
db.commit()
|
||||
db.refresh(workflow)
|
||||
return ApiResponse(data=WorkflowDefOut.model_validate(workflow))
|
||||
|
||||
|
||||
@router.put("/{workflow_id}", response_model=ApiResponse[WorkflowDefOut])
|
||||
def update_workflow(
|
||||
workflow_id: str,
|
||||
body: WorkflowDefUpdate,
|
||||
db: Session = Depends(get_db),
|
||||
user: BxUserContext = Depends(get_bx_current_user),
|
||||
):
|
||||
tenant_no = get_tenant_no(db, user.to_tenant_user_dict())
|
||||
data = body.model_dump(exclude_unset=True)
|
||||
nodes_data = data.pop("nodes", None)
|
||||
workflow = WorkflowService.update(db, workflow_id, data, user=user)
|
||||
if not workflow:
|
||||
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="工作流不存在")
|
||||
if nodes_data is not None:
|
||||
WorkflowService.save_nodes(db, workflow_id, nodes_data, user=user)
|
||||
db.commit()
|
||||
db.refresh(workflow)
|
||||
return ApiResponse(data=WorkflowDefOut.model_validate(workflow))
|
||||
|
||||
|
||||
@router.put("/{workflow_id}/nodes", response_model=ApiResponse[WorkflowDefOut])
|
||||
def save_workflow_nodes(
|
||||
workflow_id: str,
|
||||
body: List[WorkflowNodeCreate],
|
||||
db: Session = Depends(get_db),
|
||||
user: BxUserContext = Depends(get_bx_current_user),
|
||||
):
|
||||
tenant_no = get_tenant_no(db, user.to_tenant_user_dict())
|
||||
nodes_data = [n.model_dump(exclude_unset=True) for n in body]
|
||||
try:
|
||||
WorkflowService.save_nodes(db, workflow_id, nodes_data, user=user)
|
||||
except ValueError as exc:
|
||||
db.rollback()
|
||||
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=str(exc)) from exc
|
||||
workflow = WorkflowService.get_by_id(db, workflow_id, tenant_no)
|
||||
if not workflow:
|
||||
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="工作流不存在")
|
||||
db.commit()
|
||||
db.refresh(workflow)
|
||||
return ApiResponse(data=WorkflowDefOut.model_validate(workflow))
|
||||
|
||||
|
||||
@router.delete("/{workflow_id}", response_model=ApiResponse[None])
|
||||
def delete_workflow(
|
||||
workflow_id: str,
|
||||
db: Session = Depends(get_db),
|
||||
user: BxUserContext = Depends(get_bx_current_user),
|
||||
):
|
||||
tenant_no = get_tenant_no(db, user.to_tenant_user_dict())
|
||||
workflow = WorkflowService.get_by_id(db, workflow_id, tenant_no)
|
||||
if not workflow:
|
||||
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="工作流不存在")
|
||||
WorkflowService.soft_delete(db, workflow_id, user=user)
|
||||
db.commit()
|
||||
return ApiResponse(data=None)
|
||||
@@ -10,6 +10,9 @@ BIZ_TYPE_DEFAULT_FOLDER: dict[str, str] = {
|
||||
"crm_customer_follow_attachment": "crm/customer/follow",
|
||||
"crm_opportunity_follow_attachment": "crm/opportunity/follow",
|
||||
"crm_clue_follow_attachment": "crm/clue/follow",
|
||||
"advance": "bx/advance",
|
||||
"reimburse_apply": "bx/reimburse",
|
||||
"advance_issue": "bx/advance-issue",
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
"""报销模块认证适配:门户 JWT 用户 → bx 业务上下文。"""
|
||||
from __future__ import annotations
|
||||
|
||||
from dataclasses import dataclass
|
||||
from typing import Any, Dict
|
||||
|
||||
from fastapi import Depends
|
||||
|
||||
from app.core.menu_guard import require_admin_or_super_admin
|
||||
|
||||
|
||||
@dataclass
|
||||
class BxUserContext:
|
||||
"""bx Service/Router 使用的当前用户上下文(sys_user.id 为 UUID 字符串)。"""
|
||||
|
||||
id: str
|
||||
name: str
|
||||
dept_id: str
|
||||
role: str
|
||||
tenant_no: str
|
||||
|
||||
def to_tenant_user_dict(self) -> Dict[str, Any]:
|
||||
"""供 get_tenant_no 等门户工具使用。"""
|
||||
return {
|
||||
"user_id": self.id,
|
||||
"role": self.role,
|
||||
"tenant_no": self.tenant_no,
|
||||
}
|
||||
|
||||
|
||||
def get_bx_current_user(
|
||||
user: dict = Depends(require_admin_or_super_admin),
|
||||
) -> BxUserContext:
|
||||
return BxUserContext(
|
||||
id=(user.get("user_id") or "").strip(),
|
||||
name=(user.get("real_name") or user.get("username") or "").strip(),
|
||||
dept_id=(user.get("region_id") or "").strip(),
|
||||
role=(user.get("role") or "").strip(),
|
||||
tenant_no=(user.get("tenant_no") or "").strip(),
|
||||
)
|
||||
@@ -138,7 +138,14 @@ class Settings(BaseSettings):
|
||||
"/api/web/admin/products/upload-image,"
|
||||
"/api/web/admin/categories/upload-image,"
|
||||
"/api/web/admin/users/upload-avatar,"
|
||||
"/api/invoice/download"
|
||||
"/api/invoice/download,"
|
||||
"/api/bx/health,"
|
||||
"/api/expense-items,"
|
||||
"/api/workflows,"
|
||||
"/api/advances,"
|
||||
"/api/reimburses,"
|
||||
"/api/payments,"
|
||||
"/api/attachments"
|
||||
)
|
||||
|
||||
class Config:
|
||||
|
||||
@@ -13,6 +13,7 @@ from app.core.database import SessionLocal
|
||||
from app.core.api_request_log_middleware import ApiRequestLogMiddleware
|
||||
from app.core.api_crypto_middleware import ApiCryptoMiddleware
|
||||
from app.models import models # noqa: F401
|
||||
import app.models.bx_models # noqa: F401
|
||||
from app.api import (
|
||||
public_router,
|
||||
menu_router,
|
||||
@@ -21,6 +22,7 @@ from app.api import (
|
||||
leave_router,
|
||||
crm_router,
|
||||
monitor_router,
|
||||
bx_router,
|
||||
)
|
||||
|
||||
|
||||
@@ -112,6 +114,7 @@ app.include_router(admin_router, prefix=settings.API_V1_PREFIX)
|
||||
app.include_router(workflow_router, prefix=settings.API_V1_PREFIX)
|
||||
app.include_router(leave_router, prefix=settings.API_V1_PREFIX)
|
||||
app.include_router(crm_router, prefix=settings.API_V1_PREFIX)
|
||||
app.include_router(bx_router, prefix=settings.API_V1_PREFIX)
|
||||
app.include_router(monitor_router, prefix=settings.API_V1_PREFIX)
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,269 @@
|
||||
"""报销(bx)模块数据模型 — 对齐 docs/sql/20260606_bx_tables.sql"""
|
||||
from datetime import datetime
|
||||
|
||||
from sqlalchemy import BigInteger, Column, DateTime, DECIMAL, ForeignKey, Integer, SmallInteger, String
|
||||
from sqlalchemy.orm import relationship
|
||||
|
||||
from app.core.database import Base
|
||||
|
||||
|
||||
class BxExpenseItem(Base):
|
||||
__tablename__ = "bx_expense_item"
|
||||
|
||||
id = Column(String(64), primary_key=True, comment="主键ID(UUID)")
|
||||
parent_id = Column(String(64), nullable=False, default="0", comment="父级项目ID")
|
||||
item_name = Column(String(128), nullable=False, comment="项目名称")
|
||||
item_code = Column(String(64), nullable=True, comment="项目编码")
|
||||
level = Column(SmallInteger, nullable=False, default=1, comment="层级")
|
||||
sort_order = Column(Integer, nullable=False, default=0, comment="排序号")
|
||||
status = Column(SmallInteger, nullable=False, default=1, comment="状态")
|
||||
tenant_no = Column(String(64), nullable=False, default="shanxia2.0", comment="租户编号")
|
||||
order_num = Column(Integer, nullable=True, comment="排序号(公共)")
|
||||
remark = Column(String(512), nullable=True, comment="备注")
|
||||
create_by = Column(String(64), nullable=True, comment="创建人")
|
||||
create_dept_id = Column(String(64), nullable=False, default="", comment="创建部门")
|
||||
create_time = Column(DateTime, nullable=False, default=datetime.now, comment="创建时间")
|
||||
update_by = Column(String(64), nullable=True, comment="更新人")
|
||||
update_time = Column(
|
||||
DateTime, nullable=False, default=datetime.now, onupdate=datetime.now, comment="更新时间"
|
||||
)
|
||||
del_flag = Column(SmallInteger, nullable=False, default=0, comment="删除标记")
|
||||
|
||||
|
||||
class BxWorkflowDef(Base):
|
||||
__tablename__ = "bx_workflow_def"
|
||||
|
||||
id = Column(String(64), primary_key=True, comment="主键ID(UUID)")
|
||||
biz_type = Column(String(32), nullable=False, comment="业务类型")
|
||||
wf_name = Column(String(128), nullable=False, comment="工作流名称")
|
||||
status = Column(SmallInteger, nullable=False, default=1, comment="状态")
|
||||
tenant_no = Column(String(64), nullable=False, default="shanxia2.0", comment="租户编号")
|
||||
order_num = Column(Integer, nullable=True, comment="排序号(公共)")
|
||||
remark = Column(String(512), nullable=True, comment="备注")
|
||||
create_by = Column(String(64), nullable=True, comment="创建人")
|
||||
create_dept_id = Column(String(64), nullable=False, default="", comment="创建部门")
|
||||
create_time = Column(DateTime, nullable=False, default=datetime.now, comment="创建时间")
|
||||
update_by = Column(String(64), nullable=True, comment="更新人")
|
||||
update_time = Column(
|
||||
DateTime, nullable=False, default=datetime.now, onupdate=datetime.now, comment="更新时间"
|
||||
)
|
||||
del_flag = Column(SmallInteger, nullable=False, default=0, comment="删除标记")
|
||||
|
||||
nodes = relationship(
|
||||
"BxWorkflowNode",
|
||||
back_populates="workflow_def",
|
||||
primaryjoin="and_(BxWorkflowDef.id == BxWorkflowNode.wf_id, BxWorkflowNode.del_flag == 0)",
|
||||
foreign_keys="BxWorkflowNode.wf_id",
|
||||
order_by="BxWorkflowNode.node_order",
|
||||
lazy="selectin",
|
||||
)
|
||||
|
||||
|
||||
class BxWorkflowNode(Base):
|
||||
__tablename__ = "bx_workflow_node"
|
||||
|
||||
id = Column(String(64), primary_key=True, comment="主键ID(UUID)")
|
||||
wf_id = Column(
|
||||
String(64),
|
||||
ForeignKey("bx_workflow_def.id"),
|
||||
nullable=False,
|
||||
comment="工作流定义ID",
|
||||
)
|
||||
node_name = Column(String(128), nullable=False, comment="节点名称")
|
||||
node_order = Column(Integer, nullable=False, default=0, comment="节点顺序")
|
||||
approver_id = Column(String(64), nullable=True, comment="审批人用户ID")
|
||||
approver_name = Column(String(64), nullable=True, comment="审批人姓名")
|
||||
tenant_no = Column(String(64), nullable=False, default="shanxia2.0", comment="租户编号")
|
||||
order_num = Column(Integer, nullable=True, comment="排序号(公共)")
|
||||
remark = Column(String(512), nullable=True, comment="备注")
|
||||
create_by = Column(String(64), nullable=True, comment="创建人")
|
||||
create_dept_id = Column(String(64), nullable=False, default="", comment="创建部门")
|
||||
create_time = Column(DateTime, nullable=False, default=datetime.now, comment="创建时间")
|
||||
update_by = Column(String(64), nullable=True, comment="更新人")
|
||||
update_time = Column(
|
||||
DateTime, nullable=False, default=datetime.now, onupdate=datetime.now, comment="更新时间"
|
||||
)
|
||||
del_flag = Column(SmallInteger, nullable=False, default=0, comment="删除标记")
|
||||
|
||||
workflow_def = relationship(
|
||||
"BxWorkflowDef",
|
||||
back_populates="nodes",
|
||||
foreign_keys=[wf_id],
|
||||
)
|
||||
|
||||
|
||||
class BxAdvanceApply(Base):
|
||||
__tablename__ = "bx_advance_apply"
|
||||
|
||||
id = Column(String(64), primary_key=True, comment="主键ID(UUID)")
|
||||
apply_code = Column(String(32), nullable=False, comment="申请单号")
|
||||
applicant_id = Column(String(64), nullable=False, comment="申请人用户ID")
|
||||
applicant_name = Column(String(64), nullable=False, comment="申请人姓名")
|
||||
reason = Column(String(1024), nullable=False, comment="申请原因")
|
||||
purpose = Column(String(1024), nullable=True, comment="申请目的")
|
||||
expense_item_id = Column(String(64), nullable=True, comment="费用项目ID")
|
||||
amount = Column(DECIMAL(14, 2), nullable=False, comment="申请金额")
|
||||
status = Column(String(32), nullable=False, default="draft", comment="状态")
|
||||
current_node = Column(String(128), nullable=True, comment="当前审批节点")
|
||||
wf_id = Column(String(64), nullable=True, comment="工作流定义ID")
|
||||
issue_status = Column(String(32), nullable=True, comment="发放状态")
|
||||
issue_time = Column(DateTime, nullable=True, comment="发放时间")
|
||||
issue_user_id = Column(String(64), nullable=True, comment="发放操作人ID")
|
||||
issue_user_name = Column(String(64), nullable=True, comment="发放操作人姓名")
|
||||
issue_remark = Column(String(512), nullable=True, comment="发放备注")
|
||||
actual_amount = Column(DECIMAL(14, 2), nullable=True, comment="实际发放金额")
|
||||
tenant_no = Column(String(64), nullable=False, default="shanxia2.0", comment="租户编号")
|
||||
order_num = Column(Integer, nullable=True, comment="排序号(公共)")
|
||||
remark = Column(String(512), nullable=True, comment="备注")
|
||||
create_by = Column(String(64), nullable=True, comment="创建人")
|
||||
create_dept_id = Column(String(64), nullable=False, default="", comment="创建部门")
|
||||
create_time = Column(DateTime, nullable=False, default=datetime.now, comment="创建时间")
|
||||
update_by = Column(String(64), nullable=True, comment="更新人")
|
||||
update_time = Column(
|
||||
DateTime, nullable=False, default=datetime.now, onupdate=datetime.now, comment="更新时间"
|
||||
)
|
||||
del_flag = Column(SmallInteger, nullable=False, default=0, comment="删除标记")
|
||||
|
||||
|
||||
class BxAdvanceApproval(Base):
|
||||
__tablename__ = "bx_advance_approval"
|
||||
|
||||
id = Column(String(64), primary_key=True, comment="主键ID(UUID)")
|
||||
apply_id = Column(String(64), nullable=False, comment="备用金申请单ID")
|
||||
node_order = Column(Integer, nullable=False, comment="节点顺序")
|
||||
node_name = Column(String(128), nullable=False, comment="节点名称")
|
||||
approver_id = Column(String(64), nullable=False, comment="审批人用户ID")
|
||||
approver_name = Column(String(64), nullable=False, comment="审批人姓名")
|
||||
approval_status = Column(String(32), nullable=False, comment="审批结果")
|
||||
approval_opinion = Column(String(1024), nullable=True, comment="审批意见")
|
||||
approval_time = Column(DateTime, nullable=False, comment="审批时间")
|
||||
tenant_no = Column(String(64), nullable=False, default="shanxia2.0", comment="租户编号")
|
||||
order_num = Column(Integer, nullable=True, comment="排序号(公共)")
|
||||
remark = Column(String(512), nullable=True, comment="备注")
|
||||
create_by = Column(String(64), nullable=True, comment="创建人")
|
||||
create_dept_id = Column(String(64), nullable=False, default="", comment="创建部门")
|
||||
create_time = Column(DateTime, nullable=False, default=datetime.now, comment="创建时间")
|
||||
update_by = Column(String(64), nullable=True, comment="更新人")
|
||||
update_time = Column(DateTime, nullable=True, onupdate=datetime.now, comment="更新时间")
|
||||
del_flag = Column(SmallInteger, nullable=False, default=0, comment="删除标记")
|
||||
|
||||
|
||||
class BxReimburseApply(Base):
|
||||
__tablename__ = "bx_reimburse_apply"
|
||||
|
||||
id = Column(String(64), primary_key=True, comment="主键ID(UUID)")
|
||||
apply_code = Column(String(32), nullable=False, comment="报销单号")
|
||||
title = Column(String(256), nullable=False, comment="报销标题")
|
||||
applicant_id = Column(String(64), nullable=False, comment="申请人用户ID")
|
||||
applicant_name = Column(String(64), nullable=False, comment="申请人姓名")
|
||||
expense_id = Column(String(64), nullable=False, comment="费用项目ID")
|
||||
expense_name = Column(String(128), nullable=False, comment="费用项目名称")
|
||||
amount = Column(DECIMAL(14, 2), nullable=False, comment="报销金额")
|
||||
invoice_count = Column(Integer, nullable=False, default=0, comment="发票数量")
|
||||
attach_count = Column(Integer, nullable=False, default=0, comment="附件数量")
|
||||
status = Column(String(32), nullable=False, default="draft", comment="状态")
|
||||
current_node = Column(String(128), nullable=True, comment="当前审批节点")
|
||||
wf_id = Column(String(64), nullable=True, comment="工作流定义ID")
|
||||
pay_status = Column(String(32), nullable=True, comment="支付状态")
|
||||
pay_time = Column(DateTime, nullable=True, comment="支付时间")
|
||||
pay_user_id = Column(String(64), nullable=True, comment="支付操作人ID")
|
||||
pay_user_name = Column(String(64), nullable=True, comment="支付操作人姓名")
|
||||
actual_amount = Column(DECIMAL(14, 2), nullable=True, comment="实际发放金额")
|
||||
offset_advance_id = Column(String(64), nullable=True, comment="冲抵备用金单ID")
|
||||
offset_amount = Column(DECIMAL(14, 2), nullable=True, comment="冲抵金额")
|
||||
tenant_no = Column(String(64), nullable=False, default="shanxia2.0", comment="租户编号")
|
||||
order_num = Column(Integer, nullable=True, comment="排序号(公共)")
|
||||
remark = Column(String(512), nullable=True, comment="备注说明")
|
||||
create_by = Column(String(64), nullable=True, comment="创建人")
|
||||
create_dept_id = Column(String(64), nullable=False, default="", comment="创建部门")
|
||||
create_time = Column(DateTime, nullable=False, default=datetime.now, comment="创建时间")
|
||||
update_by = Column(String(64), nullable=True, comment="更新人")
|
||||
update_time = Column(
|
||||
DateTime, nullable=False, default=datetime.now, onupdate=datetime.now, comment="更新时间"
|
||||
)
|
||||
del_flag = Column(SmallInteger, nullable=False, default=0, comment="删除标记")
|
||||
|
||||
|
||||
class BxReimburseDetail(Base):
|
||||
__tablename__ = "bx_reimburse_detail"
|
||||
|
||||
id = Column(String(64), primary_key=True, comment="主键ID(UUID)")
|
||||
reimburse_id = Column(String(64), nullable=False, comment="报销单ID")
|
||||
expense_id = Column(String(64), nullable=False, comment="费用项目ID")
|
||||
expense_name = Column(String(128), nullable=False, comment="费用项目名称")
|
||||
amount = Column(DECIMAL(14, 2), nullable=False, comment="报销金额")
|
||||
tenant_no = Column(String(64), nullable=False, default="shanxia2.0", comment="租户编号")
|
||||
order_num = Column(Integer, nullable=True, comment="排序号(公共)")
|
||||
remark = Column(String(512), nullable=True, comment="备注")
|
||||
create_by = Column(String(64), nullable=True, comment="创建人")
|
||||
create_dept_id = Column(String(64), nullable=False, default="", comment="创建部门")
|
||||
create_time = Column(DateTime, nullable=False, default=datetime.now, comment="创建时间")
|
||||
update_by = Column(String(64), nullable=True, comment="更新人")
|
||||
update_time = Column(
|
||||
DateTime, nullable=False, default=datetime.now, onupdate=datetime.now, comment="更新时间"
|
||||
)
|
||||
del_flag = Column(SmallInteger, nullable=False, default=0, comment="删除标记")
|
||||
|
||||
|
||||
class BxReimburseApproval(Base):
|
||||
__tablename__ = "bx_reimburse_approval"
|
||||
|
||||
id = Column(String(64), primary_key=True, comment="主键ID(UUID)")
|
||||
apply_id = Column(String(64), nullable=False, comment="报销申请单ID")
|
||||
node_order = Column(Integer, nullable=False, comment="节点顺序")
|
||||
node_name = Column(String(128), nullable=False, comment="节点名称")
|
||||
approver_id = Column(String(64), nullable=False, comment="审批人用户ID")
|
||||
approver_name = Column(String(64), nullable=False, comment="审批人姓名")
|
||||
approval_status = Column(String(32), nullable=False, comment="审批结果")
|
||||
approval_opinion = Column(String(1024), nullable=True, comment="审批意见")
|
||||
approval_time = Column(DateTime, nullable=False, comment="审批时间")
|
||||
tenant_no = Column(String(64), nullable=False, default="shanxia2.0", comment="租户编号")
|
||||
order_num = Column(Integer, nullable=True, comment="排序号(公共)")
|
||||
remark = Column(String(512), nullable=True, comment="备注")
|
||||
create_by = Column(String(64), nullable=True, comment="创建人")
|
||||
create_dept_id = Column(String(64), nullable=False, default="", comment="创建部门")
|
||||
create_time = Column(DateTime, nullable=False, default=datetime.now, comment="创建时间")
|
||||
update_by = Column(String(64), nullable=True, comment="更新人")
|
||||
update_time = Column(DateTime, nullable=True, onupdate=datetime.now, comment="更新时间")
|
||||
del_flag = Column(SmallInteger, nullable=False, default=0, comment="删除标记")
|
||||
|
||||
|
||||
class BxReimburseOffset(Base):
|
||||
__tablename__ = "bx_reimburse_offset"
|
||||
|
||||
id = Column(String(64), primary_key=True, comment="主键ID(UUID)")
|
||||
reimburse_id = Column(String(64), nullable=False, comment="报销申请单ID")
|
||||
advance_id = Column(String(64), nullable=False, comment="备用金申请单ID")
|
||||
offset_amount = Column(DECIMAL(14, 2), nullable=False, comment="冲抵金额")
|
||||
tenant_no = Column(String(64), nullable=False, default="shanxia2.0", comment="租户编号")
|
||||
order_num = Column(Integer, nullable=True, comment="排序号(公共)")
|
||||
remark = Column(String(512), nullable=True, comment="备注")
|
||||
create_by = Column(String(64), nullable=True, comment="创建人")
|
||||
create_dept_id = Column(String(64), nullable=False, default="", comment="创建部门")
|
||||
create_time = Column(DateTime, nullable=False, default=datetime.now, comment="创建时间")
|
||||
update_by = Column(String(64), nullable=True, comment="更新人")
|
||||
update_time = Column(DateTime, nullable=True, onupdate=datetime.now, comment="更新时间")
|
||||
del_flag = Column(SmallInteger, nullable=False, default=0, comment="删除标记")
|
||||
|
||||
|
||||
class BxAttachment(Base):
|
||||
__tablename__ = "bx_attachment"
|
||||
|
||||
id = Column(String(64), primary_key=True, comment="主键ID(UUID)")
|
||||
biz_type = Column(String(32), nullable=False, comment="业务类型")
|
||||
biz_id = Column(String(64), nullable=False, comment="业务单据ID")
|
||||
file_name = Column(String(256), nullable=False, comment="文件名")
|
||||
file_path = Column(String(512), nullable=False, comment="文件存储路径")
|
||||
file_type = Column(String(128), nullable=True, comment="文件MIME类型")
|
||||
file_size = Column(BigInteger, nullable=True, comment="文件大小")
|
||||
attach_type = Column(String(32), nullable=True, default="attachment", comment="附件类型")
|
||||
sort_order = Column(Integer, nullable=False, default=0, comment="排序号")
|
||||
tenant_no = Column(String(64), nullable=False, default="shanxia2.0", comment="租户编号")
|
||||
order_num = Column(Integer, nullable=True, comment="排序号(公共)")
|
||||
remark = Column(String(512), nullable=True, comment="备注")
|
||||
create_by = Column(String(64), nullable=True, comment="创建人")
|
||||
create_dept_id = Column(String(64), nullable=False, default="", comment="创建部门")
|
||||
create_time = Column(DateTime, nullable=False, default=datetime.now, comment="创建时间")
|
||||
update_by = Column(String(64), nullable=True, comment="更新人")
|
||||
update_time = Column(DateTime, nullable=True, onupdate=datetime.now, comment="更新时间")
|
||||
del_flag = Column(SmallInteger, nullable=False, default=0, comment="删除标记")
|
||||
@@ -0,0 +1 @@
|
||||
"""报销(bx)Pydantic 模型 — 响应协议与 bx 原系统保持一致"""
|
||||
@@ -0,0 +1,156 @@
|
||||
from typing import Optional
|
||||
|
||||
from pydantic import BaseModel, ConfigDict, Field, field_validator
|
||||
from pydantic.alias_generators import to_camel
|
||||
|
||||
from app.schemas.bx.common import DatetimeToStr, OptDatetimeToStr
|
||||
|
||||
|
||||
def _coerce_optional_id(value):
|
||||
if value is None:
|
||||
return None
|
||||
s = str(value).strip()
|
||||
return s or None
|
||||
|
||||
|
||||
class AdvanceApplyCreate(BaseModel):
|
||||
model_config = ConfigDict(populate_by_name=True, alias_generator=to_camel)
|
||||
|
||||
reason: str
|
||||
purpose: Optional[str] = None
|
||||
amount: float
|
||||
remark: Optional[str] = None
|
||||
expense_item_id: Optional[str] = None
|
||||
|
||||
@field_validator("expense_item_id", mode="before")
|
||||
@classmethod
|
||||
def validate_expense_item_id(cls, value):
|
||||
return _coerce_optional_id(value)
|
||||
|
||||
|
||||
class AdvanceApplyUpdate(BaseModel):
|
||||
model_config = ConfigDict(populate_by_name=True, alias_generator=to_camel)
|
||||
|
||||
reason: Optional[str] = None
|
||||
purpose: Optional[str] = None
|
||||
amount: Optional[float] = None
|
||||
remark: Optional[str] = None
|
||||
expense_item_id: Optional[str] = None
|
||||
|
||||
@field_validator("expense_item_id", mode="before")
|
||||
@classmethod
|
||||
def validate_expense_item_id(cls, value):
|
||||
return _coerce_optional_id(value)
|
||||
|
||||
|
||||
class AdvanceApplyOut(BaseModel):
|
||||
model_config = ConfigDict(from_attributes=True, populate_by_name=True, alias_generator=to_camel)
|
||||
|
||||
id: str
|
||||
apply_code: str
|
||||
applicant_id: str
|
||||
applicant_name: str
|
||||
reason: str
|
||||
purpose: Optional[str] = None
|
||||
expense_item_id: Optional[str] = None
|
||||
amount: float
|
||||
status: str
|
||||
current_node: Optional[str] = None
|
||||
apply_time: DatetimeToStr = Field(validation_alias="create_time")
|
||||
remark: Optional[str] = None
|
||||
actual_amount: Optional[float] = None
|
||||
offset_amount: Optional[float] = None
|
||||
issue_status: Optional[str] = None
|
||||
issue_time: OptDatetimeToStr = None
|
||||
issue_user_name: Optional[str] = None
|
||||
issue_remark: Optional[str] = None
|
||||
|
||||
|
||||
class AdvanceApprovalCreate(BaseModel):
|
||||
model_config = ConfigDict(populate_by_name=True, alias_generator=to_camel)
|
||||
|
||||
approval_status: Optional[str] = None
|
||||
approval_opinion: Optional[str] = None
|
||||
|
||||
|
||||
class AdvanceApprovalOut(BaseModel):
|
||||
model_config = ConfigDict(from_attributes=True, populate_by_name=True, alias_generator=to_camel)
|
||||
|
||||
id: str
|
||||
advance_id: str
|
||||
node_name: str
|
||||
node_order: int
|
||||
approval_status: str
|
||||
approval_opinion: Optional[str] = None
|
||||
approver_name: str
|
||||
approval_time: OptDatetimeToStr = None
|
||||
|
||||
|
||||
class AdvanceMyStatsOut(BaseModel):
|
||||
model_config = ConfigDict(populate_by_name=True, alias_generator=to_camel)
|
||||
|
||||
total_count: int
|
||||
pending_count: int
|
||||
approved_pass_count: int
|
||||
rejected_count: int
|
||||
pending_issue_count: int
|
||||
issued_count: int
|
||||
issued_amount: float
|
||||
month_apply_amount: float
|
||||
month_apply_count: int
|
||||
offset_total: float
|
||||
|
||||
|
||||
class AdvanceApproverPendingStatsOut(BaseModel):
|
||||
model_config = ConfigDict(populate_by_name=True, alias_generator=to_camel)
|
||||
|
||||
pending_total: int
|
||||
month_pending_amount: float
|
||||
|
||||
|
||||
class AdvanceIssueOut(BaseModel):
|
||||
model_config = ConfigDict(from_attributes=True, populate_by_name=True, alias_generator=to_camel)
|
||||
|
||||
id: str
|
||||
apply_code: str
|
||||
applicant_id: str
|
||||
applicant_name: str
|
||||
reason: str
|
||||
amount: float
|
||||
apply_time: DatetimeToStr = Field(validation_alias="create_time")
|
||||
approve_time: DatetimeToStr = Field(validation_alias="update_time")
|
||||
issue_status: Optional[str] = None
|
||||
issue_time: OptDatetimeToStr = None
|
||||
issue_user_name: Optional[str] = None
|
||||
issue_remark: Optional[str] = None
|
||||
actual_amount: Optional[float] = None
|
||||
offset_amount: Optional[float] = None
|
||||
|
||||
|
||||
class AdvanceIssueRequest(BaseModel):
|
||||
model_config = ConfigDict(populate_by_name=True, alias_generator=to_camel)
|
||||
|
||||
issue_remark: Optional[str] = None
|
||||
actual_amount: Optional[float] = None
|
||||
|
||||
|
||||
class AdvanceOffsetRecordOut(BaseModel):
|
||||
model_config = ConfigDict(populate_by_name=True, alias_generator=to_camel)
|
||||
|
||||
reimburse_id: str
|
||||
reimburse_apply_code: str
|
||||
reimburse_title: Optional[str] = None
|
||||
reimburse_applicant_name: Optional[str] = None
|
||||
offset_amount: float
|
||||
remark: Optional[str] = None
|
||||
operator: Optional[str] = None
|
||||
create_time: OptDatetimeToStr = None
|
||||
|
||||
|
||||
class AdvanceFinanceIssueStatsOut(BaseModel):
|
||||
model_config = ConfigDict(populate_by_name=True, alias_generator=to_camel)
|
||||
|
||||
pending_count: int
|
||||
issued_count: int
|
||||
pending_amount: float
|
||||
issued_month_amount: float
|
||||
@@ -0,0 +1,19 @@
|
||||
from typing import Optional
|
||||
|
||||
from pydantic import BaseModel, ConfigDict
|
||||
from pydantic.alias_generators import to_camel
|
||||
|
||||
from app.schemas.bx.common import DatetimeToStr
|
||||
|
||||
|
||||
class AttachmentOut(BaseModel):
|
||||
model_config = ConfigDict(from_attributes=True, populate_by_name=True, alias_generator=to_camel)
|
||||
|
||||
id: str
|
||||
file_name: str
|
||||
file_path: str
|
||||
file_size: Optional[int] = None
|
||||
file_type: Optional[str] = None
|
||||
biz_type: Optional[str] = None
|
||||
biz_id: Optional[str] = None
|
||||
create_time: DatetimeToStr
|
||||
@@ -0,0 +1,46 @@
|
||||
"""bx 原系统 API 响应包装(code=0 / msg / data.rows),与门户 success_response 分离。"""
|
||||
from datetime import datetime
|
||||
from typing import Annotated, Generic, List, Optional, TypeVar
|
||||
|
||||
from pydantic import BaseModel, ConfigDict, PlainSerializer
|
||||
from pydantic.alias_generators import to_camel
|
||||
|
||||
T = TypeVar("T")
|
||||
|
||||
|
||||
def _dt_to_str(v: Optional[datetime]) -> Optional[str]:
|
||||
if v is None:
|
||||
return None
|
||||
return v.strftime("%Y-%m-%d %H:%M:%S")
|
||||
|
||||
|
||||
DatetimeToStr = Annotated[datetime, PlainSerializer(_dt_to_str, return_type=str)]
|
||||
OptDatetimeToStr = Annotated[Optional[datetime], PlainSerializer(_dt_to_str, return_type=Optional[str])]
|
||||
|
||||
|
||||
class PagedQuery(BaseModel):
|
||||
model_config = ConfigDict(populate_by_name=True, alias_generator=to_camel)
|
||||
|
||||
page: int = 1
|
||||
page_size: int = 10
|
||||
|
||||
|
||||
class ApiResponse(BaseModel, Generic[T]):
|
||||
code: int = 0
|
||||
msg: str = "success"
|
||||
data: Optional[T] = None
|
||||
|
||||
|
||||
class PagedData(BaseModel, Generic[T]):
|
||||
model_config = ConfigDict(populate_by_name=True, alias_generator=to_camel)
|
||||
|
||||
rows: List[T]
|
||||
total: int
|
||||
page: int
|
||||
page_size: int
|
||||
|
||||
|
||||
class PagedResponse(BaseModel, Generic[T]):
|
||||
code: int = 0
|
||||
msg: str = "success"
|
||||
data: Optional[PagedData[T]] = None
|
||||
@@ -0,0 +1,64 @@
|
||||
from typing import List, Optional
|
||||
|
||||
from pydantic import BaseModel, ConfigDict, field_validator
|
||||
from pydantic.alias_generators import to_camel
|
||||
|
||||
|
||||
def _coerce_id(value) -> str:
|
||||
if value is None:
|
||||
return "0"
|
||||
return str(value).strip()
|
||||
|
||||
|
||||
class ExpenseItemCreate(BaseModel):
|
||||
model_config = ConfigDict(populate_by_name=True, alias_generator=to_camel)
|
||||
|
||||
parent_id: str = "0"
|
||||
item_name: str
|
||||
item_code: str
|
||||
level: int = 1
|
||||
sort_order: int = 0
|
||||
status: int = 1
|
||||
remark: Optional[str] = None
|
||||
|
||||
@field_validator("parent_id", mode="before")
|
||||
@classmethod
|
||||
def validate_parent_id(cls, value):
|
||||
return _coerce_id(value)
|
||||
|
||||
|
||||
class ExpenseItemUpdate(BaseModel):
|
||||
model_config = ConfigDict(populate_by_name=True, alias_generator=to_camel)
|
||||
|
||||
parent_id: Optional[str] = None
|
||||
item_name: Optional[str] = None
|
||||
item_code: Optional[str] = None
|
||||
level: Optional[int] = None
|
||||
sort_order: Optional[int] = None
|
||||
status: Optional[int] = None
|
||||
remark: Optional[str] = None
|
||||
|
||||
@field_validator("parent_id", mode="before")
|
||||
@classmethod
|
||||
def validate_parent_id(cls, value):
|
||||
if value is None:
|
||||
return None
|
||||
return _coerce_id(value)
|
||||
|
||||
|
||||
class ExpenseItemOut(BaseModel):
|
||||
model_config = ConfigDict(from_attributes=True, populate_by_name=True, alias_generator=to_camel)
|
||||
|
||||
id: str
|
||||
parent_id: str
|
||||
item_name: str
|
||||
item_code: Optional[str] = None
|
||||
level: int
|
||||
sort_order: int
|
||||
status: int
|
||||
remark: Optional[str] = None
|
||||
child_count: int = 0
|
||||
children: Optional[List["ExpenseItemOut"]] = None
|
||||
|
||||
|
||||
ExpenseItemOut.model_rebuild()
|
||||
@@ -0,0 +1,193 @@
|
||||
from typing import List, Optional
|
||||
|
||||
from pydantic import BaseModel, ConfigDict, Field, field_validator
|
||||
from pydantic.alias_generators import to_camel
|
||||
|
||||
from app.schemas.bx.common import DatetimeToStr, OptDatetimeToStr
|
||||
|
||||
|
||||
def _coerce_id(value):
|
||||
if value is None:
|
||||
return None
|
||||
return str(value).strip()
|
||||
|
||||
|
||||
class ReimburseDetailCreate(BaseModel):
|
||||
model_config = ConfigDict(populate_by_name=True, alias_generator=to_camel)
|
||||
|
||||
expense_item_id: str
|
||||
amount: float
|
||||
remark: Optional[str] = None
|
||||
|
||||
@field_validator("expense_item_id", mode="before")
|
||||
@classmethod
|
||||
def validate_expense_item_id(cls, value):
|
||||
s = _coerce_id(value)
|
||||
if not s:
|
||||
raise ValueError("费用项目不能为空")
|
||||
return s
|
||||
|
||||
|
||||
class ReimburseDetailOut(BaseModel):
|
||||
model_config = ConfigDict(from_attributes=True, populate_by_name=True, alias_generator=to_camel)
|
||||
|
||||
id: str
|
||||
expense_id: str
|
||||
expense_name: str
|
||||
amount: float
|
||||
remark: Optional[str] = None
|
||||
|
||||
|
||||
class ReimburseApplyCreate(BaseModel):
|
||||
model_config = ConfigDict(populate_by_name=True, alias_generator=to_camel)
|
||||
|
||||
title: Optional[str] = None
|
||||
details: List[ReimburseDetailCreate] = Field(..., min_length=1)
|
||||
remark: Optional[str] = None
|
||||
|
||||
@field_validator("details")
|
||||
@classmethod
|
||||
def details_must_not_be_empty(cls, value):
|
||||
if not value or len(value) < 1:
|
||||
raise ValueError("至少需要一条报销明细")
|
||||
return value
|
||||
|
||||
|
||||
class ReimburseApplyUpdate(BaseModel):
|
||||
model_config = ConfigDict(populate_by_name=True, alias_generator=to_camel)
|
||||
|
||||
details: Optional[List[ReimburseDetailCreate]] = None
|
||||
remark: Optional[str] = None
|
||||
|
||||
|
||||
class ReimburseApplyOut(BaseModel):
|
||||
model_config = ConfigDict(from_attributes=True, populate_by_name=True, alias_generator=to_camel)
|
||||
|
||||
id: str
|
||||
apply_code: str
|
||||
applicant_id: str
|
||||
applicant_name: str
|
||||
title: str
|
||||
expense_id: Optional[str] = None
|
||||
expense_name: str
|
||||
amount: float
|
||||
current_node: Optional[str] = None
|
||||
apply_time: DatetimeToStr = Field(validation_alias="create_time")
|
||||
status: Optional[str] = None
|
||||
remark: Optional[str] = None
|
||||
invoice_count: int = 0
|
||||
attach_count: int = 0
|
||||
pay_status: Optional[str] = None
|
||||
pay_time: OptDatetimeToStr = None
|
||||
pay_user_name: Optional[str] = None
|
||||
actual_amount: Optional[float] = None
|
||||
offset_advance_id: Optional[str] = None
|
||||
offset_amount: Optional[float] = None
|
||||
details: Optional[List[ReimburseDetailOut]] = None
|
||||
|
||||
|
||||
class ReimburseApprovalCreate(BaseModel):
|
||||
model_config = ConfigDict(populate_by_name=True, alias_generator=to_camel)
|
||||
|
||||
approval_status: Optional[str] = None
|
||||
approval_opinion: Optional[str] = None
|
||||
|
||||
|
||||
class ReimburseApprovalOut(BaseModel):
|
||||
model_config = ConfigDict(from_attributes=True, populate_by_name=True, alias_generator=to_camel)
|
||||
|
||||
id: str
|
||||
reimburse_id: str
|
||||
node_name: str
|
||||
node_order: int
|
||||
approval_status: str
|
||||
approval_opinion: Optional[str] = None
|
||||
approver_name: str
|
||||
approval_time: OptDatetimeToStr = None
|
||||
|
||||
|
||||
class ReimburseMyStatsOut(BaseModel):
|
||||
model_config = ConfigDict(populate_by_name=True, alias_generator=to_camel)
|
||||
|
||||
total_count: int
|
||||
pending_count: int
|
||||
approved_count: int
|
||||
rejected_count: int
|
||||
approved_amount: float
|
||||
month_apply_amount: float
|
||||
month_apply_count: int
|
||||
|
||||
|
||||
class ReimburseApproverPendingStatsOut(BaseModel):
|
||||
model_config = ConfigDict(populate_by_name=True, alias_generator=to_camel)
|
||||
|
||||
pending_total: int
|
||||
month_pending_amount: float
|
||||
|
||||
|
||||
class PayRequest(BaseModel):
|
||||
model_config = ConfigDict(populate_by_name=True, alias_generator=to_camel)
|
||||
|
||||
pay_remark: Optional[str] = None
|
||||
actual_amount: Optional[float] = None
|
||||
|
||||
|
||||
class OffsetRequest(BaseModel):
|
||||
model_config = ConfigDict(populate_by_name=True, alias_generator=to_camel)
|
||||
|
||||
advance_id: str
|
||||
offset_amount: float
|
||||
remark: Optional[str] = None
|
||||
|
||||
@field_validator("advance_id", mode="before")
|
||||
@classmethod
|
||||
def validate_advance_id(cls, value):
|
||||
s = _coerce_id(value)
|
||||
if not s:
|
||||
raise ValueError("备用金单不能为空")
|
||||
return s
|
||||
|
||||
|
||||
class OffsetItem(BaseModel):
|
||||
model_config = ConfigDict(populate_by_name=True, alias_generator=to_camel)
|
||||
|
||||
advance_id: str
|
||||
offset_amount: float
|
||||
|
||||
@field_validator("advance_id", mode="before")
|
||||
@classmethod
|
||||
def validate_advance_id(cls, value):
|
||||
s = _coerce_id(value)
|
||||
if not s:
|
||||
raise ValueError("备用金单不能为空")
|
||||
return s
|
||||
|
||||
|
||||
class BatchOffsetRequest(BaseModel):
|
||||
model_config = ConfigDict(populate_by_name=True, alias_generator=to_camel)
|
||||
|
||||
items: List[OffsetItem]
|
||||
pay_amount: float = 0
|
||||
remark: Optional[str] = None
|
||||
|
||||
|
||||
class ReimburseOffsetRecordOut(BaseModel):
|
||||
model_config = ConfigDict(populate_by_name=True, alias_generator=to_camel)
|
||||
|
||||
advance_id: str
|
||||
advance_apply_code: str
|
||||
advance_applicant_name: Optional[str] = None
|
||||
advance_reason: Optional[str] = None
|
||||
offset_amount: float
|
||||
remark: Optional[str] = None
|
||||
operator: Optional[str] = None
|
||||
create_time: OptDatetimeToStr = None
|
||||
|
||||
|
||||
class PaymentFinanceStatsOut(BaseModel):
|
||||
model_config = ConfigDict(populate_by_name=True, alias_generator=to_camel)
|
||||
|
||||
pending_count: int
|
||||
paid_count: int
|
||||
offset_count: int
|
||||
month_processed_amount: float
|
||||
@@ -0,0 +1,62 @@
|
||||
from typing import List, Optional
|
||||
|
||||
from pydantic import BaseModel, ConfigDict, field_validator
|
||||
from pydantic.alias_generators import to_camel
|
||||
|
||||
|
||||
def _coerce_optional_id(value):
|
||||
if value is None:
|
||||
return None
|
||||
return str(value).strip()
|
||||
|
||||
|
||||
class WorkflowNodeCreate(BaseModel):
|
||||
model_config = ConfigDict(populate_by_name=True, alias_generator=to_camel)
|
||||
|
||||
node_name: str
|
||||
node_order: int
|
||||
approver_id: Optional[str] = None
|
||||
approver_name: Optional[str] = None
|
||||
|
||||
@field_validator("approver_id", mode="before")
|
||||
@classmethod
|
||||
def validate_approver_id(cls, value):
|
||||
return _coerce_optional_id(value)
|
||||
|
||||
|
||||
class WorkflowNodeOut(BaseModel):
|
||||
model_config = ConfigDict(from_attributes=True, populate_by_name=True, alias_generator=to_camel)
|
||||
|
||||
id: str
|
||||
node_name: str
|
||||
node_order: int
|
||||
approver_id: Optional[str] = None
|
||||
approver_name: Optional[str] = None
|
||||
|
||||
|
||||
class WorkflowDefCreate(BaseModel):
|
||||
model_config = ConfigDict(populate_by_name=True, alias_generator=to_camel)
|
||||
|
||||
biz_type: str
|
||||
wf_name: str
|
||||
status: int = 1
|
||||
nodes: Optional[List[WorkflowNodeCreate]] = None
|
||||
|
||||
|
||||
class WorkflowDefUpdate(BaseModel):
|
||||
model_config = ConfigDict(populate_by_name=True, alias_generator=to_camel)
|
||||
|
||||
biz_type: Optional[str] = None
|
||||
wf_name: Optional[str] = None
|
||||
status: Optional[int] = None
|
||||
nodes: Optional[List[WorkflowNodeCreate]] = None
|
||||
|
||||
|
||||
class WorkflowDefOut(BaseModel):
|
||||
model_config = ConfigDict(from_attributes=True, populate_by_name=True, alias_generator=to_camel)
|
||||
|
||||
id: str
|
||||
biz_type: str
|
||||
wf_name: str
|
||||
status: int
|
||||
nodes: List[WorkflowNodeOut] = []
|
||||
@@ -0,0 +1 @@
|
||||
"""报销模块 Service 包。"""
|
||||
@@ -0,0 +1,606 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from datetime import datetime
|
||||
from typing import Any, Dict, List, Optional, Sequence, Tuple
|
||||
|
||||
from sqlalchemy import and_, func, or_
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
from app.core.bx_auth import BxUserContext
|
||||
from app.core.tenant_context import get_tenant_no
|
||||
from app.core.utils import generate_uuid
|
||||
from app.models.bx_models import (
|
||||
BxAdvanceApply,
|
||||
BxAdvanceApproval,
|
||||
BxReimburseOffset,
|
||||
BxWorkflowDef,
|
||||
BxWorkflowNode,
|
||||
)
|
||||
from app.services.bx.approval_cycle import filter_current_cycle_approvals
|
||||
from app.services.bx.base import BxCrudService
|
||||
from app.utils.bx_codegen import generate_apply_code
|
||||
from app.utils.bx_date_range import current_month_bounds, parse_create_time_day_bounds
|
||||
|
||||
|
||||
class AdvanceService:
|
||||
@staticmethod
|
||||
def _tenant_no(db: Session, user: BxUserContext) -> str:
|
||||
return get_tenant_no(db, user.to_tenant_user_dict())
|
||||
|
||||
@staticmethod
|
||||
def get_by_id(db: Session, advance_id: str, tenant_no: str) -> Optional[BxAdvanceApply]:
|
||||
return BxCrudService.get_by_id(BxAdvanceApply, db, advance_id, tenant_no)
|
||||
|
||||
@staticmethod
|
||||
def get_paged(
|
||||
db: Session,
|
||||
tenant_no: str,
|
||||
page: int,
|
||||
page_size: int,
|
||||
filters: Optional[List[Any]] = None,
|
||||
) -> Tuple[Sequence[BxAdvanceApply], int]:
|
||||
return BxCrudService.get_paged(BxAdvanceApply, db, tenant_no, page, page_size, filters)
|
||||
|
||||
@staticmethod
|
||||
def create(
|
||||
db: Session,
|
||||
obj_in: dict,
|
||||
*,
|
||||
user: BxUserContext,
|
||||
) -> BxAdvanceApply:
|
||||
tenant_no = AdvanceService._tenant_no(db, user)
|
||||
return BxCrudService.create(
|
||||
BxAdvanceApply,
|
||||
db,
|
||||
obj_in,
|
||||
tenant_no=tenant_no,
|
||||
user_id=user.id,
|
||||
dept_id=user.dept_id,
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def update(
|
||||
db: Session,
|
||||
advance_id: str,
|
||||
obj_in: dict,
|
||||
*,
|
||||
user: BxUserContext,
|
||||
) -> Optional[BxAdvanceApply]:
|
||||
tenant_no = AdvanceService._tenant_no(db, user)
|
||||
return BxCrudService.update(
|
||||
BxAdvanceApply,
|
||||
db,
|
||||
advance_id,
|
||||
tenant_no,
|
||||
obj_in,
|
||||
user_id=user.id,
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def soft_delete(db: Session, advance_id: str, *, user: BxUserContext) -> bool:
|
||||
tenant_no = AdvanceService._tenant_no(db, user)
|
||||
return BxCrudService.soft_delete(
|
||||
BxAdvanceApply, db, advance_id, tenant_no, user_id=user.id
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def pending_approval(
|
||||
db: Session,
|
||||
user: BxUserContext,
|
||||
tenant_no: str,
|
||||
page: int,
|
||||
page_size: int,
|
||||
keyword: str = "",
|
||||
applicant_id: Optional[str] = None,
|
||||
apply_date: Optional[str] = None,
|
||||
):
|
||||
subquery = (
|
||||
db.query(BxAdvanceApply.id)
|
||||
.join(
|
||||
BxWorkflowNode,
|
||||
and_(
|
||||
BxWorkflowNode.wf_id == BxAdvanceApply.wf_id,
|
||||
BxWorkflowNode.node_name == BxAdvanceApply.current_node,
|
||||
BxWorkflowNode.tenant_no == tenant_no,
|
||||
BxWorkflowNode.del_flag == 0,
|
||||
),
|
||||
)
|
||||
.filter(
|
||||
BxAdvanceApply.del_flag == 0,
|
||||
BxAdvanceApply.tenant_no == tenant_no,
|
||||
BxAdvanceApply.status == "pending",
|
||||
BxWorkflowNode.approver_id == user.id,
|
||||
)
|
||||
)
|
||||
if keyword:
|
||||
subquery = subquery.filter(
|
||||
or_(
|
||||
BxAdvanceApply.apply_code.contains(keyword),
|
||||
BxAdvanceApply.applicant_name.contains(keyword),
|
||||
)
|
||||
)
|
||||
if applicant_id:
|
||||
subquery = subquery.filter(BxAdvanceApply.applicant_id == applicant_id)
|
||||
bounds = parse_create_time_day_bounds(apply_date)
|
||||
if bounds:
|
||||
d0, d1 = bounds
|
||||
subquery = subquery.filter(
|
||||
BxAdvanceApply.create_time >= d0, BxAdvanceApply.create_time < d1
|
||||
)
|
||||
subquery = subquery.subquery()
|
||||
total = db.query(func.count()).select_from(subquery).scalar() or 0
|
||||
rows = (
|
||||
db.query(BxAdvanceApply)
|
||||
.join(subquery, BxAdvanceApply.id == subquery.c.id)
|
||||
.order_by(BxAdvanceApply.create_time.desc())
|
||||
.offset((page - 1) * page_size)
|
||||
.limit(page_size)
|
||||
.all()
|
||||
)
|
||||
return rows, total
|
||||
|
||||
@staticmethod
|
||||
def approved_by_me(
|
||||
db: Session,
|
||||
user: BxUserContext,
|
||||
tenant_no: str,
|
||||
page: int,
|
||||
page_size: int,
|
||||
keyword: str = "",
|
||||
applicant_id: Optional[str] = None,
|
||||
apply_date: Optional[str] = None,
|
||||
):
|
||||
subquery = (
|
||||
db.query(BxAdvanceApproval.apply_id)
|
||||
.filter(
|
||||
BxAdvanceApproval.approver_id == user.id,
|
||||
BxAdvanceApproval.tenant_no == tenant_no,
|
||||
BxAdvanceApproval.del_flag == 0,
|
||||
)
|
||||
.distinct()
|
||||
.subquery()
|
||||
)
|
||||
query = (
|
||||
db.query(BxAdvanceApply)
|
||||
.join(subquery, BxAdvanceApply.id == subquery.c.apply_id)
|
||||
.filter(BxAdvanceApply.del_flag == 0, BxAdvanceApply.tenant_no == tenant_no)
|
||||
)
|
||||
if keyword:
|
||||
query = query.filter(
|
||||
or_(
|
||||
BxAdvanceApply.apply_code.contains(keyword),
|
||||
BxAdvanceApply.applicant_name.contains(keyword),
|
||||
)
|
||||
)
|
||||
if applicant_id:
|
||||
query = query.filter(BxAdvanceApply.applicant_id == applicant_id)
|
||||
bounds = parse_create_time_day_bounds(apply_date)
|
||||
if bounds:
|
||||
d0, d1 = bounds
|
||||
query = query.filter(BxAdvanceApply.create_time >= d0, BxAdvanceApply.create_time < d1)
|
||||
total = query.count()
|
||||
rows = (
|
||||
query.order_by(BxAdvanceApply.create_time.desc())
|
||||
.offset((page - 1) * page_size)
|
||||
.limit(page_size)
|
||||
.all()
|
||||
)
|
||||
return rows, total
|
||||
|
||||
@staticmethod
|
||||
def _workflow_nodes(db: Session, wf_id: str, tenant_no: str) -> List[BxWorkflowNode]:
|
||||
return (
|
||||
db.query(BxWorkflowNode)
|
||||
.filter(
|
||||
BxWorkflowNode.wf_id == wf_id,
|
||||
BxWorkflowNode.tenant_no == tenant_no,
|
||||
BxWorkflowNode.del_flag == 0,
|
||||
)
|
||||
.order_by(BxWorkflowNode.node_order)
|
||||
.all()
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def submit(db: Session, apply_id: str, user: BxUserContext) -> Optional[BxAdvanceApply]:
|
||||
tenant_no = AdvanceService._tenant_no(db, user)
|
||||
apply_obj = AdvanceService.get_by_id(db, apply_id, tenant_no)
|
||||
if not apply_obj:
|
||||
return None
|
||||
apply_obj.status = "pending"
|
||||
if not apply_obj.apply_code:
|
||||
apply_obj.apply_code = generate_apply_code(db, "BYJ", tenant_no)
|
||||
apply_obj.update_by = user.id
|
||||
if apply_obj.wf_id:
|
||||
nodes = AdvanceService._workflow_nodes(db, apply_obj.wf_id, tenant_no)
|
||||
if nodes:
|
||||
apply_obj.current_node = nodes[0].node_name
|
||||
db.flush()
|
||||
return apply_obj
|
||||
|
||||
@staticmethod
|
||||
def approve(
|
||||
db: Session, apply_id: str, approver: BxUserContext, opinion: str
|
||||
) -> Optional[BxAdvanceApply]:
|
||||
tenant_no = AdvanceService._tenant_no(db, approver)
|
||||
apply_obj = AdvanceService.get_by_id(db, apply_id, tenant_no)
|
||||
if not apply_obj or not apply_obj.wf_id:
|
||||
return None
|
||||
nodes = AdvanceService._workflow_nodes(db, apply_obj.wf_id, tenant_no)
|
||||
if not nodes:
|
||||
return None
|
||||
current_idx = None
|
||||
for i, node in enumerate(nodes):
|
||||
if node.node_name == apply_obj.current_node:
|
||||
current_idx = i
|
||||
break
|
||||
if current_idx is None:
|
||||
return None
|
||||
current_node = nodes[current_idx]
|
||||
if current_node.approver_id != approver.id:
|
||||
return None
|
||||
approval = BxAdvanceApproval(
|
||||
id=generate_uuid(),
|
||||
apply_id=apply_id,
|
||||
approver_id=approver.id,
|
||||
approver_name=approver.name,
|
||||
approval_opinion=opinion,
|
||||
node_name=current_node.node_name,
|
||||
node_order=current_node.node_order,
|
||||
approval_status="approved",
|
||||
approval_time=datetime.now(),
|
||||
tenant_no=tenant_no,
|
||||
create_by=approver.id,
|
||||
create_dept_id=approver.dept_id or "",
|
||||
)
|
||||
db.add(approval)
|
||||
if current_idx == len(nodes) - 1:
|
||||
apply_obj.status = "approved"
|
||||
apply_obj.current_node = None
|
||||
else:
|
||||
apply_obj.current_node = nodes[current_idx + 1].node_name
|
||||
apply_obj.update_by = approver.id
|
||||
db.flush()
|
||||
return apply_obj
|
||||
|
||||
@staticmethod
|
||||
def reject(
|
||||
db: Session, apply_id: str, approver: BxUserContext, opinion: str
|
||||
) -> Optional[BxAdvanceApply]:
|
||||
tenant_no = AdvanceService._tenant_no(db, approver)
|
||||
apply_obj = AdvanceService.get_by_id(db, apply_id, tenant_no)
|
||||
if not apply_obj or not apply_obj.wf_id:
|
||||
return None
|
||||
nodes = AdvanceService._workflow_nodes(db, apply_obj.wf_id, tenant_no)
|
||||
current_node = None
|
||||
for node in nodes:
|
||||
if node.node_name == apply_obj.current_node:
|
||||
current_node = node
|
||||
break
|
||||
if current_node is None or current_node.approver_id != approver.id:
|
||||
return None
|
||||
approval = BxAdvanceApproval(
|
||||
id=generate_uuid(),
|
||||
apply_id=apply_id,
|
||||
approver_id=approver.id,
|
||||
approver_name=approver.name,
|
||||
approval_opinion=opinion,
|
||||
node_name=current_node.node_name,
|
||||
node_order=current_node.node_order,
|
||||
approval_status="rejected",
|
||||
approval_time=datetime.now(),
|
||||
tenant_no=tenant_no,
|
||||
create_by=approver.id,
|
||||
create_dept_id=approver.dept_id or "",
|
||||
)
|
||||
db.add(approval)
|
||||
apply_obj.status = "rejected"
|
||||
apply_obj.current_node = None
|
||||
apply_obj.update_by = approver.id
|
||||
db.flush()
|
||||
return apply_obj
|
||||
|
||||
@staticmethod
|
||||
def _approval_record_dict(approval: BxAdvanceApproval, apply_id: str) -> Dict[str, Any]:
|
||||
return {
|
||||
"id": approval.id,
|
||||
"advance_id": apply_id,
|
||||
"node_name": approval.node_name,
|
||||
"node_order": approval.node_order,
|
||||
"approval_status": approval.approval_status,
|
||||
"approval_opinion": approval.approval_opinion,
|
||||
"approver_name": approval.approver_name,
|
||||
"approval_time": approval.approval_time,
|
||||
}
|
||||
|
||||
@staticmethod
|
||||
def _latest_approval_per_node(
|
||||
approvals: Sequence[BxAdvanceApproval],
|
||||
) -> Dict[int, BxAdvanceApproval]:
|
||||
"""同一节点多次审批时,取 approval_time 最新的一条作为当前节点状态。"""
|
||||
approval_map: Dict[int, BxAdvanceApproval] = {}
|
||||
for approval in approvals:
|
||||
existing = approval_map.get(approval.node_order)
|
||||
if existing is None:
|
||||
approval_map[approval.node_order] = approval
|
||||
continue
|
||||
approval_time = approval.approval_time or datetime.min
|
||||
existing_time = existing.approval_time or datetime.min
|
||||
if approval_time >= existing_time:
|
||||
approval_map[approval.node_order] = approval
|
||||
return approval_map
|
||||
|
||||
@staticmethod
|
||||
def _query_approvals(db: Session, apply_id: str, tenant_no: str) -> List[BxAdvanceApproval]:
|
||||
return (
|
||||
db.query(BxAdvanceApproval)
|
||||
.filter(
|
||||
BxAdvanceApproval.apply_id == apply_id,
|
||||
BxAdvanceApproval.tenant_no == tenant_no,
|
||||
BxAdvanceApproval.del_flag == 0,
|
||||
)
|
||||
.all()
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def get_approvals(db: Session, apply_id: str, tenant_no: str) -> List[Dict[str, Any]]:
|
||||
apply_obj = AdvanceService.get_by_id(db, apply_id, tenant_no)
|
||||
if not apply_obj or not apply_obj.wf_id:
|
||||
return []
|
||||
wf = BxCrudService.get_by_id(BxWorkflowDef, db, apply_obj.wf_id, tenant_no)
|
||||
if not wf:
|
||||
return []
|
||||
nodes = AdvanceService._workflow_nodes(db, wf.id, tenant_no)
|
||||
if not nodes:
|
||||
return []
|
||||
approvals = AdvanceService._query_approvals(db, apply_id, tenant_no)
|
||||
cycle_approvals = filter_current_cycle_approvals(approvals, apply_obj.status)
|
||||
approval_map = AdvanceService._latest_approval_per_node(cycle_approvals)
|
||||
result: List[Dict[str, Any]] = []
|
||||
for node in nodes:
|
||||
approval = approval_map.get(node.node_order)
|
||||
if approval:
|
||||
result.append(AdvanceService._approval_record_dict(approval, apply_id))
|
||||
else:
|
||||
result.append(
|
||||
{
|
||||
"id": "0",
|
||||
"advance_id": apply_id,
|
||||
"node_name": node.node_name,
|
||||
"node_order": node.node_order,
|
||||
"approval_status": "pending",
|
||||
"approval_opinion": None,
|
||||
"approver_name": node.approver_name or "",
|
||||
"approval_time": None,
|
||||
}
|
||||
)
|
||||
return result
|
||||
|
||||
@staticmethod
|
||||
def get_approval_history(db: Session, apply_id: str, tenant_no: str) -> List[Dict[str, Any]]:
|
||||
"""返回全部审批动作,按时间正序排列,用于展示完整审批历史。"""
|
||||
if not AdvanceService.get_by_id(db, apply_id, tenant_no):
|
||||
return []
|
||||
approvals = (
|
||||
db.query(BxAdvanceApproval)
|
||||
.filter(
|
||||
BxAdvanceApproval.apply_id == apply_id,
|
||||
BxAdvanceApproval.tenant_no == tenant_no,
|
||||
BxAdvanceApproval.del_flag == 0,
|
||||
)
|
||||
.order_by(BxAdvanceApproval.approval_time.asc(), BxAdvanceApproval.create_time.asc())
|
||||
.all()
|
||||
)
|
||||
return [AdvanceService._approval_record_dict(a, apply_id) for a in approvals]
|
||||
|
||||
@staticmethod
|
||||
def global_status_counts(db: Session, tenant_no: str) -> Dict[str, int]:
|
||||
rows = (
|
||||
db.query(BxAdvanceApply.status, func.count())
|
||||
.filter(BxAdvanceApply.del_flag == 0, BxAdvanceApply.tenant_no == tenant_no)
|
||||
.group_by(BxAdvanceApply.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_(
|
||||
BxAdvanceApply.del_flag == 0,
|
||||
BxAdvanceApply.tenant_no == tenant_no,
|
||||
or_(
|
||||
BxAdvanceApply.applicant_id == user_id,
|
||||
BxAdvanceApply.create_by == user_id,
|
||||
),
|
||||
)
|
||||
total_count = db.query(func.count()).select_from(BxAdvanceApply).filter(base).scalar() or 0
|
||||
pending = (
|
||||
db.query(func.count())
|
||||
.select_from(BxAdvanceApply)
|
||||
.filter(base, BxAdvanceApply.status == "pending")
|
||||
.scalar()
|
||||
or 0
|
||||
)
|
||||
approved_pass = (
|
||||
db.query(func.count())
|
||||
.select_from(BxAdvanceApply)
|
||||
.filter(base, BxAdvanceApply.status == "approved")
|
||||
.scalar()
|
||||
or 0
|
||||
)
|
||||
rejected_count = (
|
||||
db.query(func.count())
|
||||
.select_from(BxAdvanceApply)
|
||||
.filter(base, BxAdvanceApply.status == "rejected")
|
||||
.scalar()
|
||||
or 0
|
||||
)
|
||||
pending_issue = approved_pass
|
||||
issued = (
|
||||
db.query(func.count())
|
||||
.select_from(BxAdvanceApply)
|
||||
.filter(base, BxAdvanceApply.status == "issued")
|
||||
.scalar()
|
||||
or 0
|
||||
)
|
||||
issued_amount = (
|
||||
db.query(func.coalesce(func.sum(BxAdvanceApply.amount), 0))
|
||||
.filter(base, BxAdvanceApply.status == "issued")
|
||||
.scalar()
|
||||
or 0
|
||||
)
|
||||
m0, m1 = current_month_bounds()
|
||||
month_apply_amount = (
|
||||
db.query(func.coalesce(func.sum(BxAdvanceApply.amount), 0))
|
||||
.filter(base, BxAdvanceApply.create_time >= m0, BxAdvanceApply.create_time < m1)
|
||||
.scalar()
|
||||
or 0
|
||||
)
|
||||
month_apply_count = (
|
||||
db.query(func.count())
|
||||
.select_from(BxAdvanceApply)
|
||||
.filter(base, BxAdvanceApply.create_time >= m0, BxAdvanceApply.create_time < m1)
|
||||
.scalar()
|
||||
or 0
|
||||
)
|
||||
offset_total = (
|
||||
db.query(func.coalesce(func.sum(BxReimburseOffset.offset_amount), 0))
|
||||
.join(BxAdvanceApply, BxReimburseOffset.advance_id == BxAdvanceApply.id)
|
||||
.filter(
|
||||
BxAdvanceApply.applicant_id == user_id,
|
||||
BxAdvanceApply.del_flag == 0,
|
||||
BxAdvanceApply.tenant_no == tenant_no,
|
||||
BxReimburseOffset.tenant_no == tenant_no,
|
||||
BxReimburseOffset.del_flag == 0,
|
||||
)
|
||||
.scalar()
|
||||
or 0
|
||||
)
|
||||
return {
|
||||
"total_count": int(total_count),
|
||||
"pending_count": int(pending),
|
||||
"approved_pass_count": int(approved_pass),
|
||||
"rejected_count": int(rejected_count),
|
||||
"pending_issue_count": int(pending_issue),
|
||||
"issued_count": int(issued),
|
||||
"issued_amount": float(issued_amount),
|
||||
"month_apply_amount": float(month_apply_amount),
|
||||
"month_apply_count": int(month_apply_count),
|
||||
"offset_total": float(offset_total),
|
||||
}
|
||||
|
||||
@staticmethod
|
||||
def pending_approval_stats(db: Session, user: BxUserContext, tenant_no: str) -> dict:
|
||||
subquery = (
|
||||
db.query(BxAdvanceApply.id)
|
||||
.join(
|
||||
BxWorkflowNode,
|
||||
and_(
|
||||
BxWorkflowNode.wf_id == BxAdvanceApply.wf_id,
|
||||
BxWorkflowNode.node_name == BxAdvanceApply.current_node,
|
||||
BxWorkflowNode.tenant_no == tenant_no,
|
||||
BxWorkflowNode.del_flag == 0,
|
||||
),
|
||||
)
|
||||
.filter(
|
||||
BxAdvanceApply.del_flag == 0,
|
||||
BxAdvanceApply.tenant_no == tenant_no,
|
||||
BxAdvanceApply.status == "pending",
|
||||
BxWorkflowNode.approver_id == user.id,
|
||||
)
|
||||
).subquery()
|
||||
total = db.query(func.count()).select_from(subquery).scalar() or 0
|
||||
m0, m1 = current_month_bounds()
|
||||
month_sum = (
|
||||
db.query(func.coalesce(func.sum(BxAdvanceApply.amount), 0))
|
||||
.join(subquery, BxAdvanceApply.id == subquery.c.id)
|
||||
.filter(BxAdvanceApply.create_time >= m0, BxAdvanceApply.create_time < m1)
|
||||
.scalar()
|
||||
or 0
|
||||
)
|
||||
return {"pending_total": int(total), "month_pending_amount": float(month_sum)}
|
||||
|
||||
@staticmethod
|
||||
def offset_amount_map(db: Session, tenant_no: str, advance_ids: List[str]) -> Dict[str, float]:
|
||||
if not advance_ids:
|
||||
return {}
|
||||
rows = (
|
||||
db.query(
|
||||
BxReimburseOffset.advance_id,
|
||||
func.coalesce(func.sum(BxReimburseOffset.offset_amount), 0),
|
||||
)
|
||||
.filter(
|
||||
BxReimburseOffset.advance_id.in_(advance_ids),
|
||||
BxReimburseOffset.tenant_no == tenant_no,
|
||||
BxReimburseOffset.del_flag == 0,
|
||||
)
|
||||
.group_by(BxReimburseOffset.advance_id)
|
||||
.all()
|
||||
)
|
||||
return {str(advance_id): float(amount) for advance_id, amount in rows}
|
||||
|
||||
@staticmethod
|
||||
def issue(
|
||||
db: Session,
|
||||
advance_id: str,
|
||||
user: BxUserContext,
|
||||
remark: str = "",
|
||||
actual_amount: Optional[float] = None,
|
||||
) -> Optional[BxAdvanceApply]:
|
||||
tenant_no = AdvanceService._tenant_no(db, user)
|
||||
apply_obj = AdvanceService.get_by_id(db, advance_id, tenant_no)
|
||||
if not apply_obj:
|
||||
return None
|
||||
apply_obj.status = "issued"
|
||||
apply_obj.update_by = user.id
|
||||
apply_obj.issue_status = "issued"
|
||||
apply_obj.issue_time = datetime.now()
|
||||
apply_obj.issue_user_id = user.id
|
||||
apply_obj.issue_user_name = user.name
|
||||
if remark:
|
||||
apply_obj.issue_remark = remark
|
||||
if actual_amount is not None:
|
||||
apply_obj.actual_amount = actual_amount
|
||||
db.flush()
|
||||
return apply_obj
|
||||
|
||||
@staticmethod
|
||||
def finance_issue_stats(db: Session, tenant_no: str) -> dict:
|
||||
base = and_(BxAdvanceApply.del_flag == 0, BxAdvanceApply.tenant_no == tenant_no)
|
||||
pending_f = and_(
|
||||
BxAdvanceApply.status == "approved",
|
||||
or_(BxAdvanceApply.issue_status.is_(None), BxAdvanceApply.issue_status != "issued"),
|
||||
)
|
||||
pending_n = db.query(func.count()).select_from(BxAdvanceApply).filter(base, pending_f).scalar() or 0
|
||||
issued_n = (
|
||||
db.query(func.count())
|
||||
.select_from(BxAdvanceApply)
|
||||
.filter(base, BxAdvanceApply.status == "issued")
|
||||
.scalar()
|
||||
or 0
|
||||
)
|
||||
pending_amount = (
|
||||
db.query(func.coalesce(func.sum(BxAdvanceApply.amount), 0))
|
||||
.filter(base, pending_f)
|
||||
.scalar()
|
||||
or 0
|
||||
)
|
||||
m0, m1 = current_month_bounds()
|
||||
amt_expr = func.coalesce(BxAdvanceApply.actual_amount, BxAdvanceApply.amount)
|
||||
issued_month = (
|
||||
db.query(func.coalesce(func.sum(amt_expr), 0))
|
||||
.filter(
|
||||
base,
|
||||
BxAdvanceApply.status == "issued",
|
||||
BxAdvanceApply.issue_time.isnot(None),
|
||||
BxAdvanceApply.issue_time >= m0,
|
||||
BxAdvanceApply.issue_time < m1,
|
||||
)
|
||||
.scalar()
|
||||
or 0
|
||||
)
|
||||
return {
|
||||
"pending_count": int(pending_n),
|
||||
"issued_count": int(issued_n),
|
||||
"pending_amount": float(pending_amount),
|
||||
"issued_month_amount": float(issued_month),
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
"""审批轮次过滤 — 驳回后重新提交时,进度接口仅展示当前轮次。"""
|
||||
from __future__ import annotations
|
||||
|
||||
from datetime import datetime
|
||||
from typing import List, Sequence, TypeVar
|
||||
|
||||
T = TypeVar("T")
|
||||
|
||||
|
||||
def filter_current_cycle_approvals(
|
||||
approvals: Sequence[T],
|
||||
apply_status: str,
|
||||
*,
|
||||
status_attr: str = "approval_status",
|
||||
time_attr: str = "approval_time",
|
||||
) -> List[T]:
|
||||
"""审批进度仅展示当前轮次;完整历史由 get_approval_history 返回。"""
|
||||
rejections = [a for a in approvals if getattr(a, status_attr) == "rejected"]
|
||||
if not rejections:
|
||||
return list(approvals)
|
||||
|
||||
sorted_rejections = sorted(
|
||||
rejections,
|
||||
key=lambda a: getattr(a, time_attr) or datetime.min,
|
||||
)
|
||||
last_rejection_time = getattr(sorted_rejections[-1], time_attr) or datetime.min
|
||||
|
||||
if apply_status != "rejected":
|
||||
return [
|
||||
a
|
||||
for a in approvals
|
||||
if (getattr(a, time_attr) or datetime.min) > last_rejection_time
|
||||
]
|
||||
|
||||
cycle_start = datetime.min
|
||||
if len(sorted_rejections) >= 2:
|
||||
cycle_start = getattr(sorted_rejections[-2], time_attr) or datetime.min
|
||||
return [
|
||||
a
|
||||
for a in approvals
|
||||
if (getattr(a, time_attr) or datetime.min) > cycle_start
|
||||
]
|
||||
@@ -0,0 +1,119 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import List, Optional
|
||||
|
||||
from sqlalchemy import case as sql_case, func, or_
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
from app.core.bx_auth import BxUserContext
|
||||
from app.core.tenant_context import get_tenant_no
|
||||
from app.models.bx_models import BxAttachment
|
||||
from app.services.bx.base import BxCrudService
|
||||
|
||||
|
||||
class AttachmentService:
|
||||
@staticmethod
|
||||
def _tenant_no(db: Session, user: BxUserContext) -> str:
|
||||
return get_tenant_no(db, user.to_tenant_user_dict())
|
||||
|
||||
@staticmethod
|
||||
def get_by_id(db: Session, attachment_id: str, tenant_no: str) -> Optional[BxAttachment]:
|
||||
return BxCrudService.get_by_id(BxAttachment, db, attachment_id, tenant_no)
|
||||
|
||||
@staticmethod
|
||||
def create(
|
||||
db: Session,
|
||||
obj_in: dict,
|
||||
*,
|
||||
user: BxUserContext,
|
||||
) -> BxAttachment:
|
||||
tenant_no = AttachmentService._tenant_no(db, user)
|
||||
return BxCrudService.create(
|
||||
BxAttachment,
|
||||
db,
|
||||
obj_in,
|
||||
tenant_no=tenant_no,
|
||||
user_id=user.id,
|
||||
dept_id=user.dept_id,
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def soft_delete(db: Session, attachment_id: str, *, user: BxUserContext) -> bool:
|
||||
tenant_no = AttachmentService._tenant_no(db, user)
|
||||
return BxCrudService.soft_delete(
|
||||
BxAttachment, db, attachment_id, tenant_no, user_id=user.id
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def get_by_biz(db: Session, biz_type: str, biz_id: str, tenant_no: str) -> List[BxAttachment]:
|
||||
query = db.query(BxAttachment).filter(
|
||||
BxAttachment.biz_type == biz_type,
|
||||
BxAttachment.biz_id == biz_id,
|
||||
BxAttachment.tenant_no == tenant_no,
|
||||
BxAttachment.del_flag == 0,
|
||||
)
|
||||
return query.order_by(BxAttachment.sort_order, BxAttachment.create_time).all()
|
||||
|
||||
@staticmethod
|
||||
def bind_biz(
|
||||
db: Session,
|
||||
ids: List[str],
|
||||
biz_type: str,
|
||||
biz_id: str,
|
||||
*,
|
||||
user: BxUserContext,
|
||||
) -> int:
|
||||
tenant_no = AttachmentService._tenant_no(db, user)
|
||||
if not ids:
|
||||
return 0
|
||||
count = (
|
||||
db.query(BxAttachment)
|
||||
.filter(
|
||||
BxAttachment.id.in_(ids),
|
||||
BxAttachment.tenant_no == tenant_no,
|
||||
BxAttachment.del_flag == 0,
|
||||
)
|
||||
.update(
|
||||
{
|
||||
BxAttachment.biz_type: biz_type,
|
||||
BxAttachment.biz_id: biz_id,
|
||||
BxAttachment.update_by: user.id,
|
||||
},
|
||||
synchronize_session="fetch",
|
||||
)
|
||||
)
|
||||
db.flush()
|
||||
return int(count or 0)
|
||||
|
||||
@staticmethod
|
||||
def count_invoice_attach_by_biz_ids(
|
||||
db: Session, biz_type: str, biz_ids: List[str], tenant_no: str
|
||||
) -> dict[str, tuple[int, int]]:
|
||||
if not biz_ids:
|
||||
return {}
|
||||
if biz_type == "reimburse_apply":
|
||||
inv_cond = or_(
|
||||
BxAttachment.attach_type == "invoice",
|
||||
BxAttachment.file_type.isnot(None) & BxAttachment.file_type.like("image/%"),
|
||||
BxAttachment.file_type == "application/pdf",
|
||||
)
|
||||
else:
|
||||
inv_cond = BxAttachment.attach_type == "invoice"
|
||||
inv_case = sql_case((inv_cond, 1), else_=0)
|
||||
att_case = sql_case((inv_cond, 0), else_=1)
|
||||
rows = (
|
||||
db.query(
|
||||
BxAttachment.biz_id,
|
||||
func.coalesce(func.sum(inv_case), 0).label("inv"),
|
||||
func.coalesce(func.sum(att_case), 0).label("att"),
|
||||
)
|
||||
.filter(
|
||||
BxAttachment.biz_type == biz_type,
|
||||
BxAttachment.biz_id.in_(biz_ids),
|
||||
BxAttachment.tenant_no == tenant_no,
|
||||
BxAttachment.del_flag == 0,
|
||||
)
|
||||
.group_by(BxAttachment.biz_id)
|
||||
.all()
|
||||
)
|
||||
return {str(r.biz_id): (int(r.inv), int(r.att)) for r in rows}
|
||||
@@ -0,0 +1,92 @@
|
||||
"""报销模块 Service 基类 — 租户隔离 + UUID + 软删除。"""
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Any, List, Optional, Sequence, Tuple, Type, TypeVar
|
||||
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
from app.core.utils import generate_uuid
|
||||
|
||||
M = TypeVar("M")
|
||||
|
||||
|
||||
class BxCrudService:
|
||||
@staticmethod
|
||||
def get_by_id(model: Type[M], db: Session, id: str, tenant_no: str) -> Optional[M]:
|
||||
query = db.query(model).filter(model.id == id, model.tenant_no == tenant_no)
|
||||
if hasattr(model, "del_flag"):
|
||||
query = query.filter(model.del_flag == 0)
|
||||
return query.first()
|
||||
|
||||
@staticmethod
|
||||
def get_paged(
|
||||
model: Type[M],
|
||||
db: Session,
|
||||
tenant_no: str,
|
||||
page: int,
|
||||
page_size: int,
|
||||
filters: Optional[List[Any]] = None,
|
||||
) -> Tuple[Sequence[M], int]:
|
||||
query = db.query(model).filter(model.tenant_no == tenant_no)
|
||||
if hasattr(model, "del_flag"):
|
||||
query = query.filter(model.del_flag == 0)
|
||||
if filters:
|
||||
query = query.filter(*filters)
|
||||
total = query.count()
|
||||
if hasattr(model, "sort_order"):
|
||||
query = query.order_by(model.sort_order.asc(), model.create_time.desc())
|
||||
else:
|
||||
query = query.order_by(model.create_time.desc())
|
||||
rows = query.offset((page - 1) * page_size).limit(page_size).all()
|
||||
return rows, total
|
||||
|
||||
@staticmethod
|
||||
def create(
|
||||
model: Type[M],
|
||||
db: Session,
|
||||
obj_in: dict,
|
||||
*,
|
||||
tenant_no: str,
|
||||
user_id: str,
|
||||
dept_id: str,
|
||||
) -> M:
|
||||
data = dict(obj_in)
|
||||
data.setdefault("id", generate_uuid())
|
||||
data["tenant_no"] = tenant_no
|
||||
data["create_by"] = user_id
|
||||
data["create_dept_id"] = dept_id or ""
|
||||
obj = model(**data)
|
||||
db.add(obj)
|
||||
db.flush()
|
||||
return obj
|
||||
|
||||
@staticmethod
|
||||
def update(
|
||||
model: Type[M],
|
||||
db: Session,
|
||||
id: str,
|
||||
tenant_no: str,
|
||||
obj_in: dict,
|
||||
*,
|
||||
user_id: str,
|
||||
) -> Optional[M]:
|
||||
obj = BxCrudService.get_by_id(model, db, id, tenant_no)
|
||||
if not obj:
|
||||
return None
|
||||
for key, value in obj_in.items():
|
||||
setattr(obj, key, value)
|
||||
if hasattr(obj, "update_by"):
|
||||
obj.update_by = user_id
|
||||
db.flush()
|
||||
return obj
|
||||
|
||||
@staticmethod
|
||||
def soft_delete(model: Type[M], db: Session, id: str, tenant_no: str, *, user_id: str = "") -> bool:
|
||||
obj = BxCrudService.get_by_id(model, db, id, tenant_no)
|
||||
if not obj:
|
||||
return False
|
||||
obj.del_flag = 1
|
||||
if hasattr(obj, "update_by") and user_id:
|
||||
obj.update_by = user_id
|
||||
db.flush()
|
||||
return True
|
||||
@@ -0,0 +1,114 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import List, Optional
|
||||
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
from app.core.bx_auth import BxUserContext
|
||||
from app.core.tenant_context import get_tenant_no
|
||||
from app.models.bx_models import BxExpenseItem
|
||||
from app.services.bx.base import BxCrudService
|
||||
|
||||
|
||||
class ExpenseItemService:
|
||||
@staticmethod
|
||||
def _tenant_no(db: Session, user: BxUserContext) -> str:
|
||||
return get_tenant_no(db, user.to_tenant_user_dict())
|
||||
|
||||
@staticmethod
|
||||
def get_by_id(db: Session, item_id: str, tenant_no: str) -> Optional[BxExpenseItem]:
|
||||
return BxCrudService.get_by_id(BxExpenseItem, db, item_id, tenant_no)
|
||||
|
||||
@staticmethod
|
||||
def create(
|
||||
db: Session,
|
||||
obj_in: dict,
|
||||
*,
|
||||
user: BxUserContext,
|
||||
) -> BxExpenseItem:
|
||||
tenant_no = ExpenseItemService._tenant_no(db, user)
|
||||
data = dict(obj_in)
|
||||
parent_id = data.get("parent_id") or "0"
|
||||
data["parent_id"] = parent_id
|
||||
if parent_id and parent_id != "0":
|
||||
parent = ExpenseItemService.get_by_id(db, parent_id, tenant_no)
|
||||
if not parent:
|
||||
raise ValueError("父级费用项目不存在")
|
||||
data.setdefault("level", (parent.level or 1) + 1)
|
||||
else:
|
||||
data["parent_id"] = "0"
|
||||
data.setdefault("level", 1)
|
||||
return BxCrudService.create(
|
||||
BxExpenseItem,
|
||||
db,
|
||||
data,
|
||||
tenant_no=tenant_no,
|
||||
user_id=user.id,
|
||||
dept_id=user.dept_id,
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def update(
|
||||
db: Session,
|
||||
item_id: str,
|
||||
obj_in: dict,
|
||||
*,
|
||||
user: BxUserContext,
|
||||
) -> Optional[BxExpenseItem]:
|
||||
tenant_no = ExpenseItemService._tenant_no(db, user)
|
||||
data = dict(obj_in)
|
||||
if "parent_id" in data and data["parent_id"] is not None:
|
||||
parent_id = data["parent_id"] or "0"
|
||||
data["parent_id"] = parent_id
|
||||
if parent_id != "0":
|
||||
if parent_id == item_id:
|
||||
raise ValueError("不能将项目设置为自己的父级")
|
||||
parent = ExpenseItemService.get_by_id(db, parent_id, tenant_no)
|
||||
if not parent:
|
||||
raise ValueError("父级费用项目不存在")
|
||||
return BxCrudService.update(
|
||||
BxExpenseItem,
|
||||
db,
|
||||
item_id,
|
||||
tenant_no,
|
||||
data,
|
||||
user_id=user.id,
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def soft_delete(db: Session, item_id: str, *, user: BxUserContext) -> bool:
|
||||
tenant_no = ExpenseItemService._tenant_no(db, user)
|
||||
return BxCrudService.soft_delete(
|
||||
BxExpenseItem, db, item_id, tenant_no, user_id=user.id
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def get_item_tree(db: Session, tenant_no: str) -> List[BxExpenseItem]:
|
||||
items = (
|
||||
db.query(BxExpenseItem)
|
||||
.filter(BxExpenseItem.del_flag == 0, BxExpenseItem.tenant_no == tenant_no)
|
||||
.order_by(BxExpenseItem.sort_order.asc(), BxExpenseItem.create_time.desc())
|
||||
.all()
|
||||
)
|
||||
return ExpenseItemService._build_tree(items)
|
||||
|
||||
@staticmethod
|
||||
def _build_tree(items: List[BxExpenseItem]) -> List[BxExpenseItem]:
|
||||
item_map = {item.id: item for item in items}
|
||||
roots: List[BxExpenseItem] = []
|
||||
for item in items:
|
||||
parent_id = item.parent_id or "0"
|
||||
if not parent_id or parent_id == "0":
|
||||
roots.append(item)
|
||||
else:
|
||||
parent = item_map.get(parent_id)
|
||||
if parent:
|
||||
if not hasattr(parent, "children") or parent.children is None:
|
||||
parent.children = []
|
||||
parent.children.append(item)
|
||||
for item in items:
|
||||
if hasattr(item, "children") and item.children:
|
||||
item.child_count = len(item.children)
|
||||
else:
|
||||
item.child_count = 0
|
||||
return roots
|
||||
@@ -0,0 +1,765 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from datetime import datetime
|
||||
from decimal import Decimal
|
||||
from typing import Any, Dict, List, Optional, Sequence, Tuple
|
||||
|
||||
from sqlalchemy import and_, func, or_
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
from app.core.bx_auth import BxUserContext
|
||||
from app.core.tenant_context import get_tenant_no
|
||||
from app.core.utils import generate_uuid
|
||||
from app.models.bx_models import (
|
||||
BxReimburseApply,
|
||||
BxReimburseApproval,
|
||||
BxReimburseDetail,
|
||||
BxReimburseOffset,
|
||||
BxWorkflowDef,
|
||||
BxWorkflowNode,
|
||||
)
|
||||
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.utils.bx_codegen import generate_apply_code, generate_title
|
||||
from app.utils.bx_date_range import current_month_bounds, parse_create_time_day_bounds
|
||||
|
||||
_REIMBURSE_MY_STATS_PASSED_STATUSES = ("approved", "processed", "paid", "offset")
|
||||
|
||||
|
||||
class ReimburseService:
|
||||
@staticmethod
|
||||
def _tenant_no(db: Session, user: BxUserContext) -> str:
|
||||
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)
|
||||
|
||||
@staticmethod
|
||||
def get_paged(
|
||||
db: Session,
|
||||
tenant_no: str,
|
||||
page: int,
|
||||
page_size: int,
|
||||
filters: Optional[List[Any]] = None,
|
||||
) -> Tuple[Sequence[BxReimburseApply], int]:
|
||||
return BxCrudService.get_paged(BxReimburseApply, db, tenant_no, page, page_size, filters)
|
||||
|
||||
@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
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def _workflow_nodes(db: Session, wf_id: str, tenant_no: str) -> List[BxWorkflowNode]:
|
||||
return (
|
||||
db.query(BxWorkflowNode)
|
||||
.filter(
|
||||
BxWorkflowNode.wf_id == wf_id,
|
||||
BxWorkflowNode.tenant_no == tenant_no,
|
||||
BxWorkflowNode.del_flag == 0,
|
||||
)
|
||||
.order_by(BxWorkflowNode.node_order)
|
||||
.all()
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def pending_approval(
|
||||
db: Session,
|
||||
user: BxUserContext,
|
||||
tenant_no: str,
|
||||
page: int,
|
||||
page_size: int,
|
||||
keyword: str = "",
|
||||
applicant_id: Optional[str] = None,
|
||||
apply_date: Optional[str] = None,
|
||||
):
|
||||
subquery = (
|
||||
db.query(BxReimburseApply.id)
|
||||
.join(
|
||||
BxWorkflowNode,
|
||||
and_(
|
||||
BxWorkflowNode.wf_id == BxReimburseApply.wf_id,
|
||||
BxWorkflowNode.node_name == BxReimburseApply.current_node,
|
||||
BxWorkflowNode.tenant_no == tenant_no,
|
||||
BxWorkflowNode.del_flag == 0,
|
||||
),
|
||||
)
|
||||
.filter(
|
||||
BxReimburseApply.del_flag == 0,
|
||||
BxReimburseApply.tenant_no == tenant_no,
|
||||
BxReimburseApply.status == "pending",
|
||||
BxWorkflowNode.approver_id == user.id,
|
||||
)
|
||||
)
|
||||
if keyword:
|
||||
subquery = subquery.filter(
|
||||
or_(
|
||||
BxReimburseApply.apply_code.contains(keyword),
|
||||
BxReimburseApply.applicant_name.contains(keyword),
|
||||
)
|
||||
)
|
||||
if applicant_id:
|
||||
subquery = subquery.filter(BxReimburseApply.applicant_id == applicant_id)
|
||||
bounds = parse_create_time_day_bounds(apply_date)
|
||||
if bounds:
|
||||
d0, d1 = bounds
|
||||
subquery = subquery.filter(
|
||||
BxReimburseApply.create_time >= d0, BxReimburseApply.create_time < d1
|
||||
)
|
||||
subquery = subquery.subquery()
|
||||
total = db.query(func.count()).select_from(subquery).scalar() or 0
|
||||
rows = (
|
||||
db.query(BxReimburseApply)
|
||||
.join(subquery, BxReimburseApply.id == subquery.c.id)
|
||||
.order_by(BxReimburseApply.create_time.desc())
|
||||
.offset((page - 1) * page_size)
|
||||
.limit(page_size)
|
||||
.all()
|
||||
)
|
||||
return rows, total
|
||||
|
||||
@staticmethod
|
||||
def approved_by_me(
|
||||
db: Session,
|
||||
user: BxUserContext,
|
||||
tenant_no: str,
|
||||
page: int,
|
||||
page_size: int,
|
||||
keyword: str = "",
|
||||
applicant_id: Optional[str] = None,
|
||||
apply_date: Optional[str] = None,
|
||||
):
|
||||
subquery = (
|
||||
db.query(BxReimburseApproval.apply_id)
|
||||
.filter(
|
||||
BxReimburseApproval.approver_id == user.id,
|
||||
BxReimburseApproval.tenant_no == tenant_no,
|
||||
BxReimburseApproval.del_flag == 0,
|
||||
)
|
||||
.distinct()
|
||||
.subquery()
|
||||
)
|
||||
query = (
|
||||
db.query(BxReimburseApply)
|
||||
.join(subquery, BxReimburseApply.id == subquery.c.apply_id)
|
||||
.filter(BxReimburseApply.del_flag == 0, BxReimburseApply.tenant_no == tenant_no)
|
||||
)
|
||||
if keyword:
|
||||
query = query.filter(
|
||||
or_(
|
||||
BxReimburseApply.apply_code.contains(keyword),
|
||||
BxReimburseApply.applicant_name.contains(keyword),
|
||||
)
|
||||
)
|
||||
if applicant_id:
|
||||
query = query.filter(BxReimburseApply.applicant_id == applicant_id)
|
||||
bounds = parse_create_time_day_bounds(apply_date)
|
||||
if bounds:
|
||||
d0, d1 = bounds
|
||||
query = query.filter(BxReimburseApply.create_time >= d0, BxReimburseApply.create_time < d1)
|
||||
total = query.count()
|
||||
rows = (
|
||||
query.order_by(BxReimburseApply.create_time.desc())
|
||||
.offset((page - 1) * page_size)
|
||||
.limit(page_size)
|
||||
.all()
|
||||
)
|
||||
return rows, total
|
||||
|
||||
@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)
|
||||
if not apply_obj:
|
||||
return None
|
||||
apply_obj.status = "pending"
|
||||
if not apply_obj.apply_code:
|
||||
apply_obj.apply_code = generate_apply_code(db, "BX", tenant_no)
|
||||
apply_obj.update_by = user.id
|
||||
if apply_obj.wf_id:
|
||||
nodes = ReimburseService._workflow_nodes(db, apply_obj.wf_id, tenant_no)
|
||||
if nodes:
|
||||
apply_obj.current_node = nodes[0].node_name
|
||||
db.flush()
|
||||
return apply_obj
|
||||
|
||||
@staticmethod
|
||||
def approve(
|
||||
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)
|
||||
if not apply_obj or not apply_obj.wf_id:
|
||||
return None
|
||||
nodes = ReimburseService._workflow_nodes(db, apply_obj.wf_id, tenant_no)
|
||||
if not nodes:
|
||||
return None
|
||||
current_idx = None
|
||||
for i, node in enumerate(nodes):
|
||||
if node.node_name == apply_obj.current_node:
|
||||
current_idx = i
|
||||
break
|
||||
if current_idx is None:
|
||||
return None
|
||||
current_node = nodes[current_idx]
|
||||
if current_node.approver_id != approver.id:
|
||||
return None
|
||||
approval = BxReimburseApproval(
|
||||
id=generate_uuid(),
|
||||
apply_id=apply_id,
|
||||
approver_id=approver.id,
|
||||
approver_name=approver.name,
|
||||
approval_opinion=opinion,
|
||||
node_name=current_node.node_name,
|
||||
node_order=current_node.node_order,
|
||||
approval_status="approved",
|
||||
approval_time=datetime.now(),
|
||||
tenant_no=tenant_no,
|
||||
create_by=approver.id,
|
||||
create_dept_id=approver.dept_id or "",
|
||||
)
|
||||
db.add(approval)
|
||||
if current_idx == len(nodes) - 1:
|
||||
apply_obj.status = "approved"
|
||||
apply_obj.current_node = None
|
||||
else:
|
||||
apply_obj.current_node = nodes[current_idx + 1].node_name
|
||||
apply_obj.update_by = approver.id
|
||||
db.flush()
|
||||
return apply_obj
|
||||
|
||||
@staticmethod
|
||||
def reject(
|
||||
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)
|
||||
if not apply_obj or not apply_obj.wf_id:
|
||||
return None
|
||||
nodes = ReimburseService._workflow_nodes(db, apply_obj.wf_id, tenant_no)
|
||||
current_node = None
|
||||
for node in nodes:
|
||||
if node.node_name == apply_obj.current_node:
|
||||
current_node = node
|
||||
break
|
||||
if current_node is None or current_node.approver_id != approver.id:
|
||||
return None
|
||||
approval = BxReimburseApproval(
|
||||
id=generate_uuid(),
|
||||
apply_id=apply_id,
|
||||
approver_id=approver.id,
|
||||
approver_name=approver.name,
|
||||
approval_opinion=opinion,
|
||||
node_name=current_node.node_name,
|
||||
node_order=current_node.node_order,
|
||||
approval_status="rejected",
|
||||
approval_time=datetime.now(),
|
||||
tenant_no=tenant_no,
|
||||
create_by=approver.id,
|
||||
create_dept_id=approver.dept_id or "",
|
||||
)
|
||||
db.add(approval)
|
||||
apply_obj.status = "rejected"
|
||||
apply_obj.current_node = None
|
||||
apply_obj.update_by = approver.id
|
||||
db.flush()
|
||||
return apply_obj
|
||||
|
||||
@staticmethod
|
||||
def _approval_record_dict(approval: BxReimburseApproval, apply_id: str) -> Dict[str, Any]:
|
||||
return {
|
||||
"id": approval.id,
|
||||
"reimburse_id": apply_id,
|
||||
"node_name": approval.node_name,
|
||||
"node_order": approval.node_order,
|
||||
"approval_status": approval.approval_status,
|
||||
"approval_opinion": approval.approval_opinion,
|
||||
"approver_name": approval.approver_name,
|
||||
"approval_time": approval.approval_time,
|
||||
}
|
||||
|
||||
@staticmethod
|
||||
def _latest_approval_per_node(
|
||||
approvals: Sequence[BxReimburseApproval],
|
||||
) -> Dict[int, BxReimburseApproval]:
|
||||
"""同一节点多次审批时,取 approval_time 最新的一条作为当前节点状态。"""
|
||||
approval_map: Dict[int, BxReimburseApproval] = {}
|
||||
for approval in approvals:
|
||||
existing = approval_map.get(approval.node_order)
|
||||
if existing is None:
|
||||
approval_map[approval.node_order] = approval
|
||||
continue
|
||||
approval_time = approval.approval_time or datetime.min
|
||||
existing_time = existing.approval_time or datetime.min
|
||||
if approval_time >= existing_time:
|
||||
approval_map[approval.node_order] = approval
|
||||
return approval_map
|
||||
|
||||
@staticmethod
|
||||
def _query_approvals(db: Session, apply_id: str, tenant_no: str) -> List[BxReimburseApproval]:
|
||||
return (
|
||||
db.query(BxReimburseApproval)
|
||||
.filter(
|
||||
BxReimburseApproval.apply_id == apply_id,
|
||||
BxReimburseApproval.tenant_no == tenant_no,
|
||||
BxReimburseApproval.del_flag == 0,
|
||||
)
|
||||
.all()
|
||||
)
|
||||
|
||||
@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)
|
||||
if not apply_obj or not apply_obj.wf_id:
|
||||
return []
|
||||
wf = BxCrudService.get_by_id(BxWorkflowDef, db, apply_obj.wf_id, tenant_no)
|
||||
if not wf:
|
||||
return []
|
||||
nodes = ReimburseService._workflow_nodes(db, wf.id, tenant_no)
|
||||
if not nodes:
|
||||
return []
|
||||
approvals = ReimburseService._query_approvals(db, apply_id, tenant_no)
|
||||
cycle_approvals = filter_current_cycle_approvals(approvals, apply_obj.status)
|
||||
approval_map = ReimburseService._latest_approval_per_node(cycle_approvals)
|
||||
result: List[Dict[str, Any]] = []
|
||||
for node in nodes:
|
||||
approval = approval_map.get(node.node_order)
|
||||
if approval:
|
||||
result.append(ReimburseService._approval_record_dict(approval, apply_id))
|
||||
else:
|
||||
result.append(
|
||||
{
|
||||
"id": "0",
|
||||
"reimburse_id": apply_id,
|
||||
"node_name": node.node_name,
|
||||
"node_order": node.node_order,
|
||||
"approval_status": "pending",
|
||||
"approval_opinion": None,
|
||||
"approver_name": node.approver_name or "",
|
||||
"approval_time": None,
|
||||
}
|
||||
)
|
||||
return result
|
||||
|
||||
@staticmethod
|
||||
def get_approval_history(db: Session, apply_id: str, tenant_no: str) -> List[Dict[str, Any]]:
|
||||
"""返回全部审批动作,按时间正序排列,用于展示完整审批历史。"""
|
||||
if not ReimburseService.get_by_id(db, apply_id, tenant_no):
|
||||
return []
|
||||
approvals = (
|
||||
db.query(BxReimburseApproval)
|
||||
.filter(
|
||||
BxReimburseApproval.apply_id == apply_id,
|
||||
BxReimburseApproval.tenant_no == tenant_no,
|
||||
BxReimburseApproval.del_flag == 0,
|
||||
)
|
||||
.order_by(BxReimburseApproval.approval_time.asc(), BxReimburseApproval.create_time.asc())
|
||||
.all()
|
||||
)
|
||||
return [ReimburseService._approval_record_dict(a, apply_id) for a in approvals]
|
||||
|
||||
@staticmethod
|
||||
def create_with_details(
|
||||
db: Session,
|
||||
obj_in: dict,
|
||||
details: List[dict],
|
||||
*,
|
||||
user: BxUserContext,
|
||||
) -> BxReimburseApply:
|
||||
tenant_no = ReimburseService._tenant_no(db, user)
|
||||
data = dict(obj_in)
|
||||
total_amount = sum(float(d.get("amount", 0) or 0) for d in details)
|
||||
title = data.pop("title", None) or generate_title(db, user.name, tenant_no)
|
||||
first_detail = details[0] if details else {}
|
||||
|
||||
apply_obj = BxReimburseApply(
|
||||
id=generate_uuid(),
|
||||
title=title,
|
||||
amount=total_amount,
|
||||
expense_id=str(first_detail.get("expense_id") or ""),
|
||||
expense_name=first_detail.get("expense_name") or "",
|
||||
applicant_id=user.id,
|
||||
applicant_name=user.name,
|
||||
tenant_no=tenant_no,
|
||||
create_by=user.id,
|
||||
create_dept_id=user.dept_id or "",
|
||||
**data,
|
||||
)
|
||||
db.add(apply_obj)
|
||||
db.flush()
|
||||
|
||||
for d in details:
|
||||
detail = BxReimburseDetail(
|
||||
id=generate_uuid(),
|
||||
reimburse_id=apply_obj.id,
|
||||
expense_id=str(d["expense_id"]),
|
||||
expense_name=d["expense_name"],
|
||||
amount=d["amount"],
|
||||
remark=d.get("remark"),
|
||||
tenant_no=tenant_no,
|
||||
create_by=user.id,
|
||||
create_dept_id=user.dept_id or "",
|
||||
)
|
||||
db.add(detail)
|
||||
db.flush()
|
||||
return apply_obj
|
||||
|
||||
@staticmethod
|
||||
def update_with_details(
|
||||
db: Session,
|
||||
apply_id: str,
|
||||
obj_in: dict,
|
||||
details: Optional[List[dict]],
|
||||
*,
|
||||
user: BxUserContext,
|
||||
) -> Optional[BxReimburseApply]:
|
||||
tenant_no = ReimburseService._tenant_no(db, user)
|
||||
apply_obj = ReimburseService.get_by_id(db, apply_id, tenant_no)
|
||||
if not apply_obj:
|
||||
return None
|
||||
|
||||
for key, value in obj_in.items():
|
||||
setattr(apply_obj, key, value)
|
||||
|
||||
if details is not None:
|
||||
db.query(BxReimburseDetail).filter(
|
||||
BxReimburseDetail.reimburse_id == apply_id,
|
||||
BxReimburseDetail.tenant_no == tenant_no,
|
||||
BxReimburseDetail.del_flag == 0,
|
||||
).update({"del_flag": 1}, synchronize_session=False)
|
||||
|
||||
total_amount = Decimal("0")
|
||||
first_expense_name = ""
|
||||
first_expense_id = ""
|
||||
for i, d in enumerate(details):
|
||||
detail = BxReimburseDetail(
|
||||
id=generate_uuid(),
|
||||
reimburse_id=apply_id,
|
||||
expense_id=str(d["expense_id"]),
|
||||
expense_name=d["expense_name"],
|
||||
amount=d["amount"],
|
||||
remark=d.get("remark"),
|
||||
tenant_no=tenant_no,
|
||||
create_by=user.id,
|
||||
create_dept_id=user.dept_id or "",
|
||||
)
|
||||
db.add(detail)
|
||||
total_amount += Decimal(str(d["amount"]))
|
||||
if i == 0:
|
||||
first_expense_name = d["expense_name"]
|
||||
first_expense_id = str(d["expense_id"])
|
||||
|
||||
apply_obj.amount = total_amount
|
||||
apply_obj.expense_name = first_expense_name
|
||||
apply_obj.expense_id = first_expense_id
|
||||
|
||||
apply_obj.update_by = user.id
|
||||
db.flush()
|
||||
return apply_obj
|
||||
|
||||
@staticmethod
|
||||
def get_details(db: Session, reimburse_id: str, tenant_no: str) -> List[BxReimburseDetail]:
|
||||
return (
|
||||
db.query(BxReimburseDetail)
|
||||
.filter(
|
||||
BxReimburseDetail.reimburse_id == reimburse_id,
|
||||
BxReimburseDetail.tenant_no == tenant_no,
|
||||
BxReimburseDetail.del_flag == 0,
|
||||
)
|
||||
.order_by(BxReimburseDetail.create_time)
|
||||
.all()
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def out_rows_with_attachment_counts(
|
||||
db: Session, tenant_no: str, rows: List[BxReimburseApply]
|
||||
) -> List[ReimburseApplyOut]:
|
||||
if not rows:
|
||||
return []
|
||||
ids = [r.id for r in rows]
|
||||
counts = AttachmentService.count_invoice_attach_by_biz_ids(
|
||||
db, "reimburse_apply", ids, tenant_no
|
||||
)
|
||||
out_list: List[ReimburseApplyOut] = []
|
||||
for row in rows:
|
||||
out = ReimburseApplyOut.model_validate(row)
|
||||
inv, att = counts.get(row.id, (0, 0))
|
||||
out_list.append(out.model_copy(update={"invoice_count": inv, "attach_count": att}))
|
||||
return out_list
|
||||
|
||||
@staticmethod
|
||||
def out_one_with_attachment_counts(
|
||||
db: Session, tenant_no: str, row: BxReimburseApply
|
||||
) -> ReimburseApplyOut:
|
||||
return ReimburseService.out_rows_with_attachment_counts(db, tenant_no, [row])[0]
|
||||
|
||||
@staticmethod
|
||||
def build_apply_out_with_details(
|
||||
db: Session, tenant_no: str, reimburse: BxReimburseApply
|
||||
) -> ReimburseApplyOut:
|
||||
out = ReimburseService.out_one_with_attachment_counts(db, tenant_no, reimburse)
|
||||
detail_rows = ReimburseService.get_details(db, reimburse.id, tenant_no)
|
||||
out.details = [ReimburseDetailOut.model_validate(d) for d in detail_rows]
|
||||
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()
|
||||
)
|
||||
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_(
|
||||
BxReimburseApply.del_flag == 0,
|
||||
BxReimburseApply.tenant_no == tenant_no,
|
||||
or_(
|
||||
BxReimburseApply.applicant_id == user_id,
|
||||
BxReimburseApply.create_by == user_id,
|
||||
),
|
||||
)
|
||||
total_count = db.query(func.count()).select_from(BxReimburseApply).filter(base).scalar() or 0
|
||||
pending = (
|
||||
db.query(func.count())
|
||||
.select_from(BxReimburseApply)
|
||||
.filter(base, BxReimburseApply.status == "pending")
|
||||
.scalar()
|
||||
or 0
|
||||
)
|
||||
approved_count = (
|
||||
db.query(func.count())
|
||||
.select_from(BxReimburseApply)
|
||||
.filter(base, BxReimburseApply.status.in_(_REIMBURSE_MY_STATS_PASSED_STATUSES))
|
||||
.scalar()
|
||||
or 0
|
||||
)
|
||||
rejected_count = (
|
||||
db.query(func.count())
|
||||
.select_from(BxReimburseApply)
|
||||
.filter(base, BxReimburseApply.status == "rejected")
|
||||
.scalar()
|
||||
or 0
|
||||
)
|
||||
approved_amount = (
|
||||
db.query(func.coalesce(func.sum(BxReimburseApply.amount), 0))
|
||||
.filter(base, BxReimburseApply.status.in_(_REIMBURSE_MY_STATS_PASSED_STATUSES))
|
||||
.scalar()
|
||||
or 0
|
||||
)
|
||||
m0, m1 = current_month_bounds()
|
||||
month_apply_amount = (
|
||||
db.query(func.coalesce(func.sum(BxReimburseApply.amount), 0))
|
||||
.filter(base, BxReimburseApply.create_time >= m0, BxReimburseApply.create_time < m1)
|
||||
.scalar()
|
||||
or 0
|
||||
)
|
||||
month_apply_count = (
|
||||
db.query(func.count())
|
||||
.select_from(BxReimburseApply)
|
||||
.filter(base, BxReimburseApply.create_time >= m0, BxReimburseApply.create_time < m1)
|
||||
.scalar()
|
||||
or 0
|
||||
)
|
||||
return {
|
||||
"total_count": int(total_count),
|
||||
"pending_count": int(pending),
|
||||
"approved_count": int(approved_count),
|
||||
"rejected_count": int(rejected_count),
|
||||
"approved_amount": float(approved_amount),
|
||||
"month_apply_amount": float(month_apply_amount),
|
||||
"month_apply_count": int(month_apply_count),
|
||||
}
|
||||
|
||||
@staticmethod
|
||||
def pending_approval_stats(db: Session, user: BxUserContext, tenant_no: str) -> dict:
|
||||
subquery = (
|
||||
db.query(BxReimburseApply.id)
|
||||
.join(
|
||||
BxWorkflowNode,
|
||||
and_(
|
||||
BxWorkflowNode.wf_id == BxReimburseApply.wf_id,
|
||||
BxWorkflowNode.node_name == BxReimburseApply.current_node,
|
||||
BxWorkflowNode.tenant_no == tenant_no,
|
||||
BxWorkflowNode.del_flag == 0,
|
||||
),
|
||||
)
|
||||
.filter(
|
||||
BxReimburseApply.del_flag == 0,
|
||||
BxReimburseApply.tenant_no == tenant_no,
|
||||
BxReimburseApply.status == "pending",
|
||||
BxWorkflowNode.approver_id == user.id,
|
||||
)
|
||||
).subquery()
|
||||
total = db.query(func.count()).select_from(subquery).scalar() or 0
|
||||
m0, m1 = current_month_bounds()
|
||||
month_sum = (
|
||||
db.query(func.coalesce(func.sum(BxReimburseApply.amount), 0))
|
||||
.join(subquery, BxReimburseApply.id == subquery.c.id)
|
||||
.filter(BxReimburseApply.create_time >= m0, BxReimburseApply.create_time < m1)
|
||||
.scalar()
|
||||
or 0
|
||||
)
|
||||
return {"pending_total": int(total), "month_pending_amount": float(month_sum)}
|
||||
|
||||
@staticmethod
|
||||
def pay(
|
||||
db: Session,
|
||||
apply_id: str,
|
||||
user: BxUserContext,
|
||||
pay_remark: str = "",
|
||||
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)
|
||||
if not apply_obj:
|
||||
return None
|
||||
apply_obj.status = "processed"
|
||||
apply_obj.update_by = user.id
|
||||
apply_obj.pay_status = "paid"
|
||||
apply_obj.pay_time = datetime.now()
|
||||
apply_obj.pay_user_id = user.id
|
||||
apply_obj.pay_user_name = user.name
|
||||
if actual_amount is not None:
|
||||
apply_obj.actual_amount = actual_amount
|
||||
db.flush()
|
||||
return apply_obj
|
||||
|
||||
@staticmethod
|
||||
def offset(
|
||||
db: Session,
|
||||
apply_id: str,
|
||||
advance_id: str,
|
||||
amount: float,
|
||||
user: BxUserContext,
|
||||
remark: str = "",
|
||||
) -> Optional[BxReimburseApply]:
|
||||
tenant_no = ReimburseService._tenant_no(db, user)
|
||||
apply_obj = ReimburseService.get_by_id(db, apply_id, tenant_no)
|
||||
if not apply_obj:
|
||||
return None
|
||||
apply_obj.status = "offset"
|
||||
apply_obj.offset_advance_id = advance_id
|
||||
apply_obj.offset_amount = amount
|
||||
apply_obj.update_by = user.id
|
||||
offset_record = BxReimburseOffset(
|
||||
id=generate_uuid(),
|
||||
reimburse_id=apply_id,
|
||||
advance_id=advance_id,
|
||||
offset_amount=amount,
|
||||
remark=remark or None,
|
||||
tenant_no=tenant_no,
|
||||
create_by=user.name,
|
||||
create_dept_id=user.dept_id or "",
|
||||
)
|
||||
db.add(offset_record)
|
||||
db.flush()
|
||||
return apply_obj
|
||||
|
||||
@staticmethod
|
||||
def batch_offset(
|
||||
db: Session,
|
||||
apply_id: str,
|
||||
items: List[dict],
|
||||
pay_amount: float,
|
||||
user: BxUserContext,
|
||||
remark: str = "",
|
||||
) -> Optional[BxReimburseApply]:
|
||||
tenant_no = ReimburseService._tenant_no(db, user)
|
||||
apply_obj = ReimburseService.get_by_id(db, apply_id, tenant_no)
|
||||
if not apply_obj:
|
||||
return None
|
||||
|
||||
has_offsets = bool(items)
|
||||
total_offset = 0.0
|
||||
first_advance_id = None
|
||||
|
||||
for item in items:
|
||||
advance_id = str(item["advance_id"])
|
||||
offset_amount = float(item["offset_amount"])
|
||||
if first_advance_id is None:
|
||||
first_advance_id = advance_id
|
||||
total_offset += offset_amount
|
||||
offset_record = BxReimburseOffset(
|
||||
id=generate_uuid(),
|
||||
reimburse_id=apply_id,
|
||||
advance_id=advance_id,
|
||||
offset_amount=offset_amount,
|
||||
remark=remark or None,
|
||||
tenant_no=tenant_no,
|
||||
create_by=user.name,
|
||||
create_dept_id=user.dept_id or "",
|
||||
)
|
||||
db.add(offset_record)
|
||||
|
||||
if first_advance_id is not None:
|
||||
apply_obj.offset_advance_id = first_advance_id
|
||||
apply_obj.offset_amount = total_offset
|
||||
|
||||
if pay_amount > 0:
|
||||
apply_obj.pay_status = "paid"
|
||||
apply_obj.pay_time = datetime.now()
|
||||
apply_obj.pay_user_id = user.id
|
||||
apply_obj.pay_user_name = user.name
|
||||
apply_obj.actual_amount = pay_amount
|
||||
apply_obj.status = "processed"
|
||||
elif has_offsets:
|
||||
apply_obj.actual_amount = 0
|
||||
apply_obj.status = "processed"
|
||||
|
||||
apply_obj.update_by = user.id
|
||||
db.flush()
|
||||
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)
|
||||
pending = (
|
||||
db.query(func.count())
|
||||
.select_from(BxReimburseApply)
|
||||
.filter(base, BxReimburseApply.status == "approved")
|
||||
.scalar()
|
||||
or 0
|
||||
)
|
||||
bank_paid = BxReimburseApply.pay_time.isnot(None)
|
||||
paid = (
|
||||
db.query(func.count()).select_from(BxReimburseApply).filter(base, bank_paid).scalar() or 0
|
||||
)
|
||||
offset_settled = or_(
|
||||
BxReimburseApply.status == "offset",
|
||||
and_(
|
||||
BxReimburseApply.status == "processed",
|
||||
BxReimburseApply.pay_time.is_(None),
|
||||
func.coalesce(BxReimburseApply.offset_amount, 0) > 0,
|
||||
),
|
||||
)
|
||||
offset = (
|
||||
db.query(func.count()).select_from(BxReimburseApply).filter(base, offset_settled).scalar() or 0
|
||||
)
|
||||
m0, m1 = current_month_bounds()
|
||||
month_paid = (
|
||||
db.query(func.coalesce(func.sum(BxReimburseApply.amount), 0))
|
||||
.filter(base, bank_paid, BxReimburseApply.pay_time >= m0, BxReimburseApply.pay_time < m1)
|
||||
.scalar()
|
||||
or 0
|
||||
)
|
||||
month_offset = (
|
||||
db.query(func.coalesce(func.sum(BxReimburseApply.amount), 0))
|
||||
.filter(base, offset_settled, BxReimburseApply.update_time >= m0, BxReimburseApply.update_time < m1)
|
||||
.scalar()
|
||||
or 0
|
||||
)
|
||||
return {
|
||||
"pending_count": int(pending),
|
||||
"paid_count": int(paid),
|
||||
"offset_count": int(offset),
|
||||
"month_processed_amount": float(month_paid) + float(month_offset),
|
||||
}
|
||||
@@ -0,0 +1,103 @@
|
||||
"""报销附件存储适配 — 复用门户 app.core.storage,对外保持 bx 协议。"""
|
||||
from __future__ import annotations
|
||||
|
||||
from datetime import timedelta
|
||||
from io import BytesIO
|
||||
from pathlib import Path
|
||||
|
||||
from app.core.config import settings
|
||||
from app.core.storage import LocalStorage, MinIOStorage, get_storage, storage
|
||||
|
||||
|
||||
def normalize_storage_path(file_url: str) -> str:
|
||||
"""将 upload 返回的完整 URL 归一化为存储相对路径(与 admin 附件 upload 一致)。"""
|
||||
u = (file_url or "").strip()
|
||||
if not u:
|
||||
return ""
|
||||
if "?" in u:
|
||||
u = u.split("?", 1)[0]
|
||||
base_url = (settings.MINIO_BASE_URL or "").rstrip("/")
|
||||
if base_url and u.startswith(base_url + "/"):
|
||||
return u[len(base_url) + 1 :]
|
||||
local_base = settings.LOCAL_STORAGE_URL.rstrip("/")
|
||||
if u.startswith(local_base + "/"):
|
||||
return u[len(local_base) + 1 :]
|
||||
if u.startswith("http://") or u.startswith("https://"):
|
||||
store = get_storage()
|
||||
if isinstance(store, MinIOStorage):
|
||||
return store._extract_object_key(u)
|
||||
return u.lstrip("/")
|
||||
|
||||
|
||||
def upload_bx_file(file_content: bytes, filename: str, *, biz_type: str = "") -> tuple[str, str]:
|
||||
"""
|
||||
上传文件到对象存储。
|
||||
返回 (relative_path, access_url)。
|
||||
"""
|
||||
folder = "bx"
|
||||
if biz_type:
|
||||
folder = f"bx/{biz_type.strip('/')}"
|
||||
full_url = storage.upload_file(file_content, filename, folder)
|
||||
relative_path = normalize_storage_path(full_url)
|
||||
return relative_path, full_url
|
||||
|
||||
|
||||
def get_access_url(file_path: str) -> str:
|
||||
"""获取可访问 URL(本地/MinIO 公开地址)。"""
|
||||
store = get_storage()
|
||||
key = normalize_storage_path(file_path)
|
||||
if not key:
|
||||
return ""
|
||||
return store.get_url(key)
|
||||
|
||||
|
||||
def get_preview_url(file_path: str, *, expires_seconds: int = 3600) -> str:
|
||||
"""图片/附件预览 URL:MinIO 预签名 inline,本地/其他存储用 get_url。"""
|
||||
store = get_storage()
|
||||
key = normalize_storage_path(file_path)
|
||||
if not key:
|
||||
return ""
|
||||
if isinstance(store, MinIOStorage):
|
||||
return store.client.presigned_get_object(
|
||||
bucket_name=store.bucket_name,
|
||||
object_name=key,
|
||||
expires=timedelta(seconds=expires_seconds),
|
||||
)
|
||||
return store.get_url(key)
|
||||
|
||||
|
||||
def get_download_url(file_path: str, file_name: str, *, expires_seconds: int = 3600) -> str:
|
||||
"""带文件名的下载 URL(对齐门户 attachment/download-url)。"""
|
||||
store = get_storage()
|
||||
key = normalize_storage_path(file_path)
|
||||
return store.presigned_download_url(key, file_name, expires_seconds)
|
||||
|
||||
|
||||
def download_file_bytes(file_path: str) -> bytes:
|
||||
"""读取文件二进制,供 StreamingResponse 下载。"""
|
||||
store = get_storage()
|
||||
key = normalize_storage_path(file_path)
|
||||
if not key:
|
||||
raise ValueError("无效的文件路径")
|
||||
if isinstance(store, MinIOStorage):
|
||||
response = store.client.get_object(store.bucket_name, key)
|
||||
try:
|
||||
return response.read()
|
||||
finally:
|
||||
response.close()
|
||||
response.release_conn()
|
||||
if isinstance(store, LocalStorage):
|
||||
file_full_path = Path(store.upload_dir) / key
|
||||
if not file_full_path.is_file():
|
||||
raise FileNotFoundError(f"文件不存在: {key}")
|
||||
return file_full_path.read_bytes()
|
||||
# 七牛/OSS 等:回退 HTTP 拉取(开发环境较少用到)
|
||||
import urllib.request
|
||||
|
||||
url = store.get_url(key)
|
||||
with urllib.request.urlopen(url, timeout=60) as resp:
|
||||
return resp.read()
|
||||
|
||||
|
||||
def file_stream(file_path: str) -> BytesIO:
|
||||
return BytesIO(download_file_bytes(file_path))
|
||||
@@ -0,0 +1,169 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import List, Optional, Sequence, Tuple
|
||||
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
from app.core.bx_auth import BxUserContext
|
||||
from app.core.tenant_context import get_tenant_no
|
||||
from app.core.utils import generate_uuid
|
||||
from app.models.bx_models import BxWorkflowDef, BxWorkflowNode
|
||||
from app.services.bx.base import BxCrudService
|
||||
|
||||
|
||||
_DEFAULT_WORKFLOWS = {
|
||||
"advance": {
|
||||
"wf_name": "备用金审批流程",
|
||||
"remark": "备用金申请默认审批流程",
|
||||
},
|
||||
"reimburse": {
|
||||
"wf_name": "报销单审批流程",
|
||||
"remark": "报销申请默认审批流程",
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
class WorkflowService:
|
||||
@staticmethod
|
||||
def _tenant_no(db: Session, user: BxUserContext) -> str:
|
||||
return get_tenant_no(db, user.to_tenant_user_dict())
|
||||
|
||||
@staticmethod
|
||||
def get_by_id(db: Session, workflow_id: str, tenant_no: str) -> Optional[BxWorkflowDef]:
|
||||
return BxCrudService.get_by_id(BxWorkflowDef, db, workflow_id, tenant_no)
|
||||
|
||||
@staticmethod
|
||||
def get_paged(
|
||||
db: Session,
|
||||
tenant_no: str,
|
||||
page: int,
|
||||
page_size: int,
|
||||
) -> Tuple[Sequence[BxWorkflowDef], int]:
|
||||
return BxCrudService.get_paged(BxWorkflowDef, db, tenant_no, page, page_size)
|
||||
|
||||
@staticmethod
|
||||
def create(
|
||||
db: Session,
|
||||
obj_in: dict,
|
||||
*,
|
||||
user: BxUserContext,
|
||||
) -> BxWorkflowDef:
|
||||
tenant_no = WorkflowService._tenant_no(db, user)
|
||||
return BxCrudService.create(
|
||||
BxWorkflowDef,
|
||||
db,
|
||||
obj_in,
|
||||
tenant_no=tenant_no,
|
||||
user_id=user.id,
|
||||
dept_id=user.dept_id,
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def update(
|
||||
db: Session,
|
||||
workflow_id: str,
|
||||
obj_in: dict,
|
||||
*,
|
||||
user: BxUserContext,
|
||||
) -> Optional[BxWorkflowDef]:
|
||||
tenant_no = WorkflowService._tenant_no(db, user)
|
||||
return BxCrudService.update(
|
||||
BxWorkflowDef,
|
||||
db,
|
||||
workflow_id,
|
||||
tenant_no,
|
||||
obj_in,
|
||||
user_id=user.id,
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def soft_delete(db: Session, workflow_id: str, *, user: BxUserContext) -> bool:
|
||||
tenant_no = WorkflowService._tenant_no(db, user)
|
||||
deleted = BxCrudService.soft_delete(
|
||||
BxWorkflowDef, db, workflow_id, tenant_no, user_id=user.id
|
||||
)
|
||||
if deleted:
|
||||
db.query(BxWorkflowNode).filter(
|
||||
BxWorkflowNode.wf_id == workflow_id,
|
||||
BxWorkflowNode.tenant_no == tenant_no,
|
||||
).update({"del_flag": 1}, synchronize_session=False)
|
||||
db.flush()
|
||||
return deleted
|
||||
|
||||
@staticmethod
|
||||
def get_by_biz_type(db: Session, biz_type: str, tenant_no: str) -> Optional[BxWorkflowDef]:
|
||||
return (
|
||||
db.query(BxWorkflowDef)
|
||||
.filter(
|
||||
BxWorkflowDef.biz_type == biz_type,
|
||||
BxWorkflowDef.tenant_no == tenant_no,
|
||||
BxWorkflowDef.del_flag == 0,
|
||||
)
|
||||
.first()
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def ensure_by_biz_type(
|
||||
db: Session,
|
||||
biz_type: str,
|
||||
*,
|
||||
user: BxUserContext,
|
||||
) -> Optional[BxWorkflowDef]:
|
||||
"""按业务类型获取工作流;已知类型不存在时自动创建空定义(无节点)。"""
|
||||
tenant_no = WorkflowService._tenant_no(db, user)
|
||||
workflow = WorkflowService.get_by_biz_type(db, biz_type, tenant_no)
|
||||
if workflow:
|
||||
return workflow
|
||||
|
||||
meta = _DEFAULT_WORKFLOWS.get(biz_type)
|
||||
if not meta:
|
||||
return None
|
||||
|
||||
workflow = WorkflowService.create(
|
||||
db,
|
||||
{
|
||||
"biz_type": biz_type,
|
||||
"wf_name": meta["wf_name"],
|
||||
"remark": meta["remark"],
|
||||
"status": 1,
|
||||
},
|
||||
user=user,
|
||||
)
|
||||
db.commit()
|
||||
db.refresh(workflow)
|
||||
return workflow
|
||||
|
||||
@staticmethod
|
||||
def save_nodes(
|
||||
db: Session,
|
||||
wf_id: str,
|
||||
nodes: List[dict],
|
||||
*,
|
||||
user: BxUserContext,
|
||||
) -> List[BxWorkflowNode]:
|
||||
tenant_no = WorkflowService._tenant_no(db, user)
|
||||
workflow = WorkflowService.get_by_id(db, wf_id, tenant_no)
|
||||
if not workflow:
|
||||
raise ValueError("工作流不存在")
|
||||
|
||||
db.query(BxWorkflowNode).filter(
|
||||
BxWorkflowNode.wf_id == wf_id,
|
||||
BxWorkflowNode.tenant_no == tenant_no,
|
||||
).delete(synchronize_session=False)
|
||||
|
||||
created: List[BxWorkflowNode] = []
|
||||
for node_data in nodes:
|
||||
data = dict(node_data)
|
||||
data["id"] = generate_uuid()
|
||||
data["wf_id"] = wf_id
|
||||
data["tenant_no"] = tenant_no
|
||||
data["create_by"] = user.id
|
||||
data["create_dept_id"] = user.dept_id or ""
|
||||
if data.get("approver_id") is not None:
|
||||
data["approver_id"] = str(data["approver_id"]).strip() or None
|
||||
node = BxWorkflowNode(**data)
|
||||
db.add(node)
|
||||
created.append(node)
|
||||
db.flush()
|
||||
db.expire(workflow, ["nodes"])
|
||||
return created
|
||||
@@ -0,0 +1,46 @@
|
||||
"""报销单号/标题生成(从 bx-backend 迁移,增加 tenant_no 隔离)。"""
|
||||
from datetime import datetime
|
||||
|
||||
from sqlalchemy import text
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
|
||||
def generate_apply_code(db: Session, prefix: str, tenant_no: str) -> str:
|
||||
"""
|
||||
生成顺序单号:{prefix}{YYYYMMDD}{3位序号}。
|
||||
prefix 示例:BYJ(备用金)、BX(报销)。
|
||||
"""
|
||||
today = datetime.now().strftime("%Y%m%d")
|
||||
like_pattern = f"{prefix}{today}%"
|
||||
|
||||
result = db.execute(
|
||||
text(
|
||||
"SELECT MAX(CAST(SUBSTRING(apply_code, -3) AS UNSIGNED)) FROM ("
|
||||
"SELECT apply_code FROM bx_advance_apply "
|
||||
"WHERE tenant_no = :tenant_no AND apply_code LIKE :p1 AND del_flag = 0 "
|
||||
"UNION ALL "
|
||||
"SELECT apply_code FROM bx_reimburse_apply "
|
||||
"WHERE tenant_no = :tenant_no AND apply_code LIKE :p2 AND del_flag = 0"
|
||||
") t"
|
||||
),
|
||||
{"tenant_no": tenant_no, "p1": like_pattern, "p2": like_pattern},
|
||||
).scalar()
|
||||
|
||||
seq = (result or 0) + 1
|
||||
return f"{prefix}{today}{seq:03d}"
|
||||
|
||||
|
||||
def generate_title(db: Session, applicant_name: str, tenant_no: str) -> str:
|
||||
today = datetime.now().strftime("%Y%m%d")
|
||||
like_pattern = f"%报销单{today}%"
|
||||
|
||||
result = db.execute(
|
||||
text(
|
||||
"SELECT COUNT(*) FROM bx_reimburse_apply "
|
||||
"WHERE tenant_no = :tenant_no AND title LIKE :p AND del_flag = 0"
|
||||
),
|
||||
{"tenant_no": tenant_no, "p": like_pattern},
|
||||
).scalar()
|
||||
|
||||
seq = (result or 0) + 1
|
||||
return f"{applicant_name}报销单{today}{seq:03d}"
|
||||
@@ -0,0 +1,26 @@
|
||||
"""报销模块日期范围工具(从 bx-backend 迁移)。"""
|
||||
from __future__ import annotations
|
||||
|
||||
from datetime import datetime, timedelta
|
||||
|
||||
|
||||
def current_month_bounds(now: datetime | None = None) -> tuple[datetime, datetime]:
|
||||
"""当前自然月 [month_start, next_month_start)。"""
|
||||
if now is None:
|
||||
now = datetime.now()
|
||||
month_start = now.replace(day=1, hour=0, minute=0, second=0, microsecond=0)
|
||||
if now.month == 12:
|
||||
month_end = datetime(now.year + 1, 1, 1)
|
||||
else:
|
||||
month_end = datetime(now.year, now.month + 1, 1)
|
||||
return month_start, month_end
|
||||
|
||||
|
||||
def parse_create_time_day_bounds(apply_date: str | None) -> tuple[datetime, datetime] | None:
|
||||
if not apply_date or not str(apply_date).strip():
|
||||
return None
|
||||
try:
|
||||
day_start = datetime.strptime(str(apply_date).strip(), "%Y-%m-%d")
|
||||
return day_start, day_start + timedelta(days=1)
|
||||
except ValueError:
|
||||
return None
|
||||
@@ -103,6 +103,30 @@
|
||||
"101": "Community 101",
|
||||
"102": "Community 102",
|
||||
"103": "Community 103",
|
||||
"104": "Community 104",
|
||||
"105": "Community 105",
|
||||
"106": "Community 106",
|
||||
"107": "Community 107",
|
||||
"108": "Community 108",
|
||||
"109": "Community 109",
|
||||
"113": "Community 113"
|
||||
"110": "Community 110",
|
||||
"111": "Community 111",
|
||||
"112": "Community 112",
|
||||
"113": "Community 113",
|
||||
"114": "Community 114",
|
||||
"115": "Community 115",
|
||||
"116": "Community 116",
|
||||
"117": "Community 117",
|
||||
"118": "Community 118",
|
||||
"119": "Community 119",
|
||||
"120": "Community 120",
|
||||
"121": "Community 121",
|
||||
"122": "Community 122",
|
||||
"123": "Community 123",
|
||||
"124": "Community 124",
|
||||
"125": "Community 125",
|
||||
"126": "Community 126",
|
||||
"127": "Community 127",
|
||||
"128": "Community 128",
|
||||
"129": "Community 129"
|
||||
}
|
||||
@@ -1,16 +1,16 @@
|
||||
# Graph Report - backend (2026-06-06)
|
||||
|
||||
## Corpus Check
|
||||
- 122 files · ~93,527 words
|
||||
- 149 files · ~105,173 words
|
||||
- Verdict: corpus is large enough that graph structure adds value.
|
||||
|
||||
## Summary
|
||||
- 2643 nodes · 18676 edges · 106 communities (103 shown, 3 thin omitted)
|
||||
- Extraction: 45% EXTRACTED · 55% INFERRED · 0% AMBIGUOUS · INFERRED: 10230 edges (avg confidence: 0.51)
|
||||
- 3047 nodes · 20600 edges · 130 communities (125 shown, 5 thin omitted)
|
||||
- Extraction: 47% EXTRACTED · 53% INFERRED · 0% AMBIGUOUS · INFERRED: 10854 edges (avg confidence: 0.51)
|
||||
- Token cost: 0 input · 0 output
|
||||
|
||||
## Graph Freshness
|
||||
- Built from commit: `dacfdc9f`
|
||||
- Built from commit: `f9676f87`
|
||||
- Run `git rev-parse HEAD` and compare to check if the graph is stale.
|
||||
- Run `graphify update .` after code changes (no API cost).
|
||||
|
||||
@@ -112,94 +112,117 @@
|
||||
- [[_COMMUNITY_Community 101|Community 101]]
|
||||
- [[_COMMUNITY_Community 102|Community 102]]
|
||||
- [[_COMMUNITY_Community 103|Community 103]]
|
||||
- [[_COMMUNITY_Community 104|Community 104]]
|
||||
- [[_COMMUNITY_Community 105|Community 105]]
|
||||
- [[_COMMUNITY_Community 106|Community 106]]
|
||||
- [[_COMMUNITY_Community 107|Community 107]]
|
||||
- [[_COMMUNITY_Community 108|Community 108]]
|
||||
- [[_COMMUNITY_Community 109|Community 109]]
|
||||
- [[_COMMUNITY_Community 110|Community 110]]
|
||||
- [[_COMMUNITY_Community 111|Community 111]]
|
||||
- [[_COMMUNITY_Community 112|Community 112]]
|
||||
- [[_COMMUNITY_Community 113|Community 113]]
|
||||
- [[_COMMUNITY_Community 114|Community 114]]
|
||||
- [[_COMMUNITY_Community 116|Community 116]]
|
||||
- [[_COMMUNITY_Community 117|Community 117]]
|
||||
- [[_COMMUNITY_Community 118|Community 118]]
|
||||
- [[_COMMUNITY_Community 119|Community 119]]
|
||||
- [[_COMMUNITY_Community 120|Community 120]]
|
||||
- [[_COMMUNITY_Community 121|Community 121]]
|
||||
- [[_COMMUNITY_Community 122|Community 122]]
|
||||
- [[_COMMUNITY_Community 123|Community 123]]
|
||||
- [[_COMMUNITY_Community 124|Community 124]]
|
||||
- [[_COMMUNITY_Community 125|Community 125]]
|
||||
- [[_COMMUNITY_Community 126|Community 126]]
|
||||
- [[_COMMUNITY_Community 127|Community 127]]
|
||||
- [[_COMMUNITY_Community 128|Community 128]]
|
||||
- [[_COMMUNITY_Community 129|Community 129]]
|
||||
|
||||
## God Nodes (most connected - your core abstractions)
|
||||
1. `Session` - 256 edges
|
||||
2. `success_response()` - 246 edges
|
||||
3. `Session` - 243 edges
|
||||
4. `BaseModel` - 242 edges
|
||||
1. `BaseModel` - 281 edges
|
||||
2. `Session` - 256 edges
|
||||
3. `success_response()` - 246 edges
|
||||
4. `Session` - 243 edges
|
||||
5. `error_response()` - 234 edges
|
||||
6. `SysUser` - 180 edges
|
||||
7. `get_tenant_no()` - 140 edges
|
||||
8. `int` - 111 edges
|
||||
9. `CustomerListBody` - 108 edges
|
||||
10. `CustomerCreateBody` - 108 edges
|
||||
7. `get_tenant_no()` - 170 edges
|
||||
8. `generate_uuid()` - 114 edges
|
||||
9. `int` - 111 edges
|
||||
10. `CustomerListBody` - 108 edges
|
||||
|
||||
## Surprising Connections (you probably didn't know these)
|
||||
- `bool` --uses--> `SysUser` [INFERRED]
|
||||
app/crud/sample_code.py → app/models/models.py
|
||||
- `date` --uses--> `CrmContact` [INFERRED]
|
||||
app/crud/crm/contact.py → app/models/crm_models.py
|
||||
- `bool` --uses--> `CrmInvoiceInfo` [INFERRED]
|
||||
app/crud/crm/invoice_info.py → app/models/crm_models.py
|
||||
- `pool_recovery_job()` --calls--> `execute_pool_rules()` [INFERRED]
|
||||
app/tasks/customer_pool.py → app/crud/crm/pool_rule.py
|
||||
- `Session` --uses--> `CrmCustomer` [INFERRED]
|
||||
app/tasks/customer_pool.py → app/models/crm_models.py
|
||||
- `Any` --uses--> `SysApiRequestLog` [INFERRED]
|
||||
app/core/api_request_log_middleware.py → app/models/models.py
|
||||
- `bytes` --uses--> `SysApiRequestLog` [INFERRED]
|
||||
app/core/api_request_log_middleware.py → app/models/models.py
|
||||
- `bool` --uses--> `SysApiRequestLog` [INFERRED]
|
||||
app/core/api_request_log_middleware.py → app/models/models.py
|
||||
- `UploadFile` --uses--> `BxUserContext` [INFERRED]
|
||||
app/api/bx/attachment.py → app/core/bx_auth.py
|
||||
- `int` --uses--> `BxUserContext` [INFERRED]
|
||||
app/api/bx/workflow.py → app/core/bx_auth.py
|
||||
|
||||
## Communities (106 total, 3 thin omitted)
|
||||
## Communities (130 total, 5 thin omitted)
|
||||
|
||||
### Community 0 - "Community 0"
|
||||
Cohesion: 0.15
|
||||
Nodes (42): Any, int, Session, str, Any, bool, CRM 公海池规则 CRUD + 规则执行逻辑, int (+34 more)
|
||||
Cohesion: 0.25
|
||||
Nodes (27): Any, bool, CRM 公海池规则 CRUD + 规则执行逻辑, int, Session, str, generate_uuid(), create_pool_rule() (+19 more)
|
||||
|
||||
### Community 1 - "Community 1"
|
||||
Cohesion: 0.09
|
||||
Nodes (84): Any, ProcessDefCreateBody, ProcessDefUpdateBody, PublishVersionBody, 审批意见:前端传 commentText,兼容 comment。, StartInstanceBody, TaskActionBody, Any (+76 more)
|
||||
Cohesion: 0.14
|
||||
Nodes (28): Any, Any, bool, str, WfProcessInstance, Any, bool, Session (+20 more)
|
||||
|
||||
### Community 2 - "Community 2"
|
||||
Cohesion: 0.22
|
||||
Nodes (11): Any, bool, int, Session, str, bool, camel_to_snake(), CRUDBase (+3 more)
|
||||
Cohesion: 0.23
|
||||
Nodes (10): Any, bool, int, Session, str, camel_to_snake(), CRUDBase, get_model_attr() (+2 more)
|
||||
|
||||
### Community 3 - "Community 3"
|
||||
Cohesion: 0.13
|
||||
Nodes (15): Any, bool, int, str, get_wechat_pay_client(), get_wechat_pay_v2(), 微信支付工具模块 支持微信支付 V3 API 文档参考: https://pay.weixin.qq.com/docs/v3/apis/index.html, 统一下单接口 (V3) Args: out_trade_no: 商户订单号 total_amo (+7 more)
|
||||
|
||||
### Community 4 - "Community 4"
|
||||
Cohesion: 0.20
|
||||
Nodes (29): bool, CRM 产品模块 CRUD(产品分类 + 产品 + 附件), Session, str, barcode_exists(), category_code_exists(), _category_row_to_dict(), create_category() (+21 more)
|
||||
Cohesion: 0.14
|
||||
Nodes (41): Any, bool, CRM 产品模块 CRUD(产品分类 + 产品 + 附件), int, Session, str, barcode_exists(), _build_category_tree() (+33 more)
|
||||
|
||||
### Community 5 - "Community 5"
|
||||
Cohesion: 0.09
|
||||
Nodes (33): Any, bool, bytes, int, str, Exception, bool, bytes (+25 more)
|
||||
Cohesion: 0.14
|
||||
Nodes (5): bool, BaseStorage, OSSStorage, QiniuStorage, 文件存储工具模块 支持多种存储方式: 1. 本地存储 (local) - 默认 2. 七牛云存储 (qiniu) - 推荐生产环境使用 3. 阿里云OSS (
|
||||
|
||||
### Community 6 - "Community 6"
|
||||
Cohesion: 0.09
|
||||
Nodes (94): attachment_download_url(), AttachmentDownloadUrlBody, create_dept(), create_dict_data(), create_dict_type(), create_menu(), create_post(), create_role_management() (+86 more)
|
||||
Cohesion: 0.11
|
||||
Nodes (72): attachment_download_url(), create_dept(), create_dict_data(), create_dict_type(), create_menu(), create_post(), create_role_management(), create_site() (+64 more)
|
||||
|
||||
### Community 7 - "Community 7"
|
||||
Cohesion: 0.22
|
||||
Nodes (9): create_new_version(), Java: createNewVersion — 返回新报价单 id, Java: createNewVersion — 返回新报价单 id, Java: createNewVersion — 返回新报价单 id, Java: createNewVersion — 返回新报价单 id, Java: createNewVersion — 返回新报价单 id, Java: createNewVersion — 返回新报价单 id, Java: createNewVersion — 返回新报价单 id (+1 more)
|
||||
|
||||
### Community 8 - "Community 8"
|
||||
Cohesion: 0.15
|
||||
Nodes (34): Session, str, Any, bool, int, Session, str, apply_data_scope() (+26 more)
|
||||
Cohesion: 0.11
|
||||
Nodes (50): Session, str, Any, bool, int, Session, str, Any (+42 more)
|
||||
|
||||
### Community 9 - "Community 9"
|
||||
Cohesion: 0.33
|
||||
Nodes (15): Any, int, Session, str, BizLeaveRequest, create_leave(), get_leave(), list_leaves() (+7 more)
|
||||
|
||||
### Community 10 - "Community 10"
|
||||
Cohesion: 0.09
|
||||
Nodes (56): register_contract_sub_routes(), Any, bool, datetime, int, Session, str, _advance_contract_after_approval() (+48 more)
|
||||
Cohesion: 0.08
|
||||
Nodes (68): Any, bool, CrmContract, datetime, int, Query, Session, str (+60 more)
|
||||
|
||||
### Community 11 - "Community 11"
|
||||
Cohesion: 0.05
|
||||
Nodes (168): _apply_default_invoice_info_to_customers(), category_add(), category_delete(), category_tree(), category_update(), clue_assign(), clue_check_convert(), clue_check_duplicate() (+160 more)
|
||||
Nodes (167): _apply_default_invoice_info_to_customers(), category_add(), category_delete(), category_tree(), category_update(), clue_assign(), clue_check_convert(), clue_check_duplicate() (+159 more)
|
||||
|
||||
### Community 12 - "Community 12"
|
||||
Cohesion: 0.06
|
||||
Nodes (68): str, CRM 客户管理 Pydantic Schemas, BaseModel, PageResult, ResponseModel, ContactByCustomerBody, ContactDetailBody, ContactSetPrimaryBody (+60 more)
|
||||
Cohesion: 0.15
|
||||
Nodes (52): ProcessDefCreateBody, ProcessDefUpdateBody, PublishVersionBody, 审批意见:前端传 commentText,兼容 comment。, StartInstanceBody, TaskActionBody, Any, int (+44 more)
|
||||
|
||||
### Community 13 - "Community 13"
|
||||
Cohesion: 0.36
|
||||
Nodes (213): Any, bool, str, UploadFile, CRM 线索管理 Pydantic Schemas, CRM 商机管理 Pydantic Schemas, CRM 客户公海池规则 Pydantic Schemas, CRM 产品模块 Pydantic Schemas (+205 more)
|
||||
|
||||
### Community 14 - "Community 14"
|
||||
Cohesion: 0.18
|
||||
Nodes (39): Any, bool, CRM 客户 CRUD(客户主表 + 转移/成交/公海池操作), CrmCustomer, date, datetime, float, int (+31 more)
|
||||
Cohesion: 0.17
|
||||
Nodes (45): Any, bool, CRM 客户 CRUD(客户主表 + 转移/成交/公海池操作), CrmCustomer, date, datetime, float, int (+37 more)
|
||||
|
||||
### Community 15 - "Community 15"
|
||||
Cohesion: 0.08
|
||||
@@ -210,16 +233,16 @@ Cohesion: 0.12
|
||||
Nodes (31): CRM 报价单 API 路由 — 挂接到 crm.router, CRM 报价单 Pydantic Schemas, QuoteAcceptBody, QuoteApprovalApproveBody, QuoteApprovalListBody, QuoteApprovalRefreshNamesBody, QuoteApprovalWithdrawBody, QuoteCreateBody (+23 more)
|
||||
|
||||
### Community 17 - "Community 17"
|
||||
Cohesion: 0.26
|
||||
Nodes (22): Any, bool, datetime, int, Session, str, BizSampleCode, batch_generate_sample_codes() (+14 more)
|
||||
Cohesion: 0.11
|
||||
Nodes (59): BxUserContext, int, Session, str, BxUserContext, int, Session, str (+51 more)
|
||||
|
||||
### Community 18 - "Community 18"
|
||||
Cohesion: 0.17
|
||||
Nodes (34): Any, bool, int, Session, str, SysUser, create_user(), get_user() (+26 more)
|
||||
|
||||
### Community 19 - "Community 19"
|
||||
Cohesion: 0.35
|
||||
Nodes (9): check_customer_protect_time(), _execute_single_rule(), _get_all_tenant_nos(), pool_recovery_job(), 公海池自动回收任务(由 APScheduler 调度) 遍历所有租户的启用规则,执行自动回收。, 每天凌晨1点:检查保护期到期客户,跟进次数不足则退回公海, 每天早上9点:保护期到期提醒(3天内到期且跟进不足), remind_customer_recycle() (+1 more)
|
||||
Cohesion: 0.23
|
||||
Nodes (21): Any, bool, CRM 供方信息 CRUD — 对照 CrmSupplierInfoServiceImpl.java, int, Session, str, _apply_list_filters(), create_supplier_info() (+13 more)
|
||||
|
||||
### Community 20 - "Community 20"
|
||||
Cohesion: 0.37
|
||||
@@ -230,12 +253,12 @@ Cohesion: 0.34
|
||||
Nodes (16): Any, int, Session, str, _build_tree(), _cascade_soft_delete(), _collect_with_ancestors(), create_dept() (+8 more)
|
||||
|
||||
### Community 22 - "Community 22"
|
||||
Cohesion: 0.07
|
||||
Nodes (48): 导出供方列表 — Java: CrmSupplierInfoController.export, 导出供方列表 — Java: CrmSupplierInfoController.export, 导出供方列表 — Java: CrmSupplierInfoController.export, 导出供方列表 — Java: CrmSupplierInfoController.export, 导出供方列表 — Java: CrmSupplierInfoController.export, 导出供方列表 — Java: CrmSupplierInfoController.export, 导出供方列表 — Java: CrmSupplierInfoController.export, 导出供方列表 — Java: CrmSupplierInfoController.export (+40 more)
|
||||
Cohesion: 0.18
|
||||
Nodes (19): str, Any, bool, Session, str, StreamingResponse, CRM 模块 Excel 导出列定义(字段与字典类型对齐 Java *Vo @ExcelDictFormat)。, _yes_no() (+11 more)
|
||||
|
||||
### Community 23 - "Community 23"
|
||||
Cohesion: 0.09
|
||||
Nodes (23): download_contract_pdf(), export_contracts(), get_contract_detail(), ORM → camelCase(单点真相), ORM → camelCase(单点真相), ORM → camelCase(单点真相), ORM → camelCase(单点真相), ORM → camelCase(单点真相) (+15 more)
|
||||
Cohesion: 0.13
|
||||
Nodes (17): CrmContract, contract_row_to_dict(), _parse_letter_oss_ids_from_tier(), Java: validateFrameworkContractForSubmitApproval, Java: validateFrameworkContractForSubmitApproval, Java: validateFrameworkContractForSubmitApproval, Java: validateFrameworkContractForSubmitApproval, ORM → camelCase(单点真相) (+9 more)
|
||||
|
||||
### Community 24 - "Community 24"
|
||||
Cohesion: 0.29
|
||||
@@ -250,12 +273,12 @@ Cohesion: 0.27
|
||||
Nodes (11): Any, bool, str, decrypt_login_payload(), ensure_initialized(), extract_login_credentials(), get_public_pem(), 登录凭据 RSA 解密(与前端 JSEncrypt PKCS#1 v1.5 兼容)。 (+3 more)
|
||||
|
||||
### Community 27 - "Community 27"
|
||||
Cohesion: 0.26
|
||||
Nodes (20): Any, bool, int, Session, str, create_follow(), _enrich_follow_dict(), _follow_row_to_dict() (+12 more)
|
||||
Cohesion: 0.16
|
||||
Nodes (31): Any, bool, int, Session, str, Any, Session, str (+23 more)
|
||||
|
||||
### Community 28 - "Community 28"
|
||||
Cohesion: 0.26
|
||||
Nodes (19): Any, bool, date, int, Session, str, _contact_row_to_dict(), create_contact() (+11 more)
|
||||
Cohesion: 0.23
|
||||
Nodes (34): AdvanceApplyCreate, AdvanceApplyOut, AdvanceApplyUpdate, AdvanceApprovalCreate, BxUserContext, int, Session, str (+26 more)
|
||||
|
||||
### Community 29 - "Community 29"
|
||||
Cohesion: 0.32
|
||||
@@ -266,76 +289,76 @@ Cohesion: 0.40
|
||||
Nodes (3): BaseSettings, Config, Settings
|
||||
|
||||
### Community 36 - "Community 36"
|
||||
Cohesion: 0.17
|
||||
Nodes (32): Any, int, Session, str, Any, bool, int, Session (+24 more)
|
||||
Cohesion: 0.27
|
||||
Nodes (14): Any, bool, bytes, int, str, ApiCryptoError, _b64url_decode(), _b64url_encode() (+6 more)
|
||||
|
||||
### Community 37 - "Community 37"
|
||||
Cohesion: 0.19
|
||||
Nodes (17): Any, int, str, BusinessException, InvalidStatusTransitionException, log_api_request(), log_delivery_operation(), log_operation() (+9 more)
|
||||
Cohesion: 0.08
|
||||
Nodes (46): str, ContractApprovalPageListBody, 全局审批记录分页(approval/index.vue), CustomerFollowByCustomerBody, CustomerFollowDetailBody, BaseModel, AttachmentUploadResponse, ChangePasswordRequest (+38 more)
|
||||
|
||||
### Community 38 - "Community 38"
|
||||
Cohesion: 0.40
|
||||
Nodes (4): str, Config, format_api_error_message(), 将 HTTP/SQLAlchemy 等异常转为可展示的错误文案(避免 str([]) 空列表)。
|
||||
Cohesion: 0.26
|
||||
Nodes (21): approve_task(), _business_type_label(), create_process_def(), delete_process_def(), _enrich_task_list(), get_business_all_tasks(), _get_business_form_fields(), get_designer_data() (+13 more)
|
||||
|
||||
### Community 39 - "Community 39"
|
||||
Cohesion: 0.20
|
||||
Nodes (26): Any, bool, Decimal, int, Session, str, batch_insert_quote_products(), calculate_subtotal() (+18 more)
|
||||
|
||||
### Community 40 - "Community 40"
|
||||
Cohesion: 0.22
|
||||
Nodes (33): Any, bool, CRM 线索 CRUD(线索主表 + 转化/分配/无效/等级操作), date, datetime, int, Session, str (+25 more)
|
||||
Cohesion: 0.10
|
||||
Nodes (60): Any, bool, int, Session, str, Any, bool, CRM 线索 CRUD(线索主表 + 转化/分配/无效/等级操作) (+52 more)
|
||||
|
||||
### Community 41 - "Community 41"
|
||||
Cohesion: 0.11
|
||||
Nodes (19): 供方全量列表(下拉)— Java: CrmSupplierInfoController.listAll, 供方全量列表(下拉)— Java: CrmSupplierInfoController.listAll, 供方全量列表(下拉)— Java: CrmSupplierInfoController.listAll, 供方全量列表(下拉)— Java: CrmSupplierInfoController.listAll, 供方全量列表(下拉)— Java: CrmSupplierInfoController.listAll, 供方全量列表(下拉)— Java: CrmSupplierInfoController.listAll, 供方全量列表(下拉)— Java: CrmSupplierInfoController.listAll, 供方全量列表(下拉)— Java: CrmSupplierInfoController.listAll (+11 more)
|
||||
Cohesion: 0.17
|
||||
Nodes (22): BxUserContext, Session, str, str, bool, BxUserContext, Session, str (+14 more)
|
||||
|
||||
### Community 42 - "Community 42"
|
||||
Cohesion: 0.34
|
||||
Nodes (16): Any, bool, int, Session, str, create_dict_type(), dict_type_code_exists(), get_dict_type() (+8 more)
|
||||
|
||||
### Community 43 - "Community 43"
|
||||
Cohesion: 0.23
|
||||
Nodes (16): bool, int, Redis, Request, str, _claims_from_auth(), _coerce_post_method_override_to_get(), _get_redis_client() (+8 more)
|
||||
Cohesion: 0.30
|
||||
Nodes (11): bool, BxUserContext, BxWorkflowNode, int, Session, str, 按业务类型获取工作流;已知类型不存在时自动创建空定义(无节点)。, WorkflowService (+3 more)
|
||||
|
||||
### Community 44 - "Community 44"
|
||||
Cohesion: 0.16
|
||||
Nodes (21): _error_json(), lifespan(), _mask_secret(), Exception, int, Request, str, 未捕获异常:统一 JSON 500,确保跨域场景下仍有 Access-Control-Allow-Origin (+13 more)
|
||||
Cohesion: 0.22
|
||||
Nodes (16): Any, bool, bytes, int, Request, str, _claims_from_auth(), _format_body_bytes() (+8 more)
|
||||
|
||||
### Community 45 - "Community 45"
|
||||
Cohesion: 0.08
|
||||
Nodes (76): register_contract_routes(), bool, CRM 合同 CRUD — 对照 CrmContractServiceImpl.java(列表/详情 P1), Session, str, batch_assign_owner(), batch_submit_approval(), _build_customer_address() (+68 more)
|
||||
Cohesion: 0.29
|
||||
Nodes (34): AdvanceIssueRequest, BxUserContext, int, ReimburseApplyOut, Session, str, str, BatchOffsetRequest (+26 more)
|
||||
|
||||
### Community 46 - "Community 46"
|
||||
Cohesion: 0.17
|
||||
Nodes (23): Any, bool, bytes, int, Request, str, bool, int (+15 more)
|
||||
Cohesion: 0.05
|
||||
Nodes (83): _avatar_url_field(), _build_user_info_payload(), get_current_user_profile(), get_web_auth_menu_codes(), _jwt_user_payload(), logout(), public_quote_share(), 公共接口(Web 登录、刷新 Token、登出;用户模型对齐 docs/sql/shanxia2.0.sql 基线) (+75 more)
|
||||
|
||||
### Community 47 - "Community 47"
|
||||
Cohesion: 0.17
|
||||
Nodes (26): API 路由包 — 山峡化工生产一体化门户, get_menu_list(), 运营端菜单接口(与 web-admin 前端静态路由 sqxp.ts 对齐,14 个一级菜单), approve_task(), _business_type_label(), create_process_def(), delete_process_def(), _enrich_task_list() (+18 more)
|
||||
Cohesion: 0.20
|
||||
Nodes (25): Any, bool, BxUserContext, BxWorkflowNode, float, int, ReimburseApplyOut, Session (+17 more)
|
||||
|
||||
### Community 48 - "Community 48"
|
||||
Cohesion: 0.07
|
||||
Nodes (51): CRM 合同 API 路由 — GET/PUT/DELETE/POST 对齐原 Java CRM, CRM 合同子模块路由 — 变更/模板/审批独立页, CRM 合同 Pydantic Schemas — 对照 CrmContractBo / CrmContractVo, ContractApprovalActionBody, ContractApprovalApproveBody, ContractApprovalByContractBody, ContractApprovalExportBody, ContractApprovalListBody (+43 more)
|
||||
Nodes (52): CRM 合同 API 路由 — GET/PUT/DELETE/POST 对齐原 Java CRM, CRM 合同子模块路由 — 变更/模板/审批独立页, register_contract_sub_routes(), CRM 合同 Pydantic Schemas — 对照 CrmContractBo / CrmContractVo, ContractApprovalActionBody, ContractApprovalApproveBody, ContractApprovalByContractBody, ContractApprovalExportBody (+44 more)
|
||||
|
||||
### Community 49 - "Community 49"
|
||||
Cohesion: 0.44
|
||||
Nodes (11): Any, Session, str, get_follow_statistics(), get_industry_statistics(), get_level_statistics(), get_overview_statistics(), get_owner_statistics() (+3 more)
|
||||
Cohesion: 0.29
|
||||
Nodes (29): AttachmentDownloadUrlBody, DeptCreateBody, DeptUpdateBody, DictDataCreateBody, DictDataUpdateBody, DictTypeCreateBody, DictTypeUpdateBody, MenuCreateBody (+21 more)
|
||||
|
||||
### Community 50 - "Community 50"
|
||||
Cohesion: 0.19
|
||||
Nodes (20): operlog_detail(), operlog_list(), 操作日志分页列表(基于 API 请求日志适配 RuoYi OperLog 结构), Session, Any, int, Session, str (+12 more)
|
||||
Cohesion: 0.14
|
||||
Nodes (22): _error_json(), lifespan(), _mask_secret(), Exception, int, Request, str, 未捕获异常:统一 JSON 500,确保跨域场景下仍有 Access-Control-Allow-Origin (+14 more)
|
||||
|
||||
### Community 51 - "Community 51"
|
||||
Cohesion: 0.16
|
||||
Nodes (13): float, int, str, 微信消息通知服务 支持微信小程序模板消息推送 使用方式: from app.core.wechat_message import WechatMes, 发送订单状态通知 Args: openid: 用户openid order_n, 发送支付成功通知 Args: openid: 用户openid order_n, 发送配送通知 Args: openid: 配送员openid task_no:, 发送配送时效预警 Args: openid: 配送员openid task_n (+5 more)
|
||||
|
||||
### Community 52 - "Community 52"
|
||||
Cohesion: 0.37
|
||||
Nodes (13): create_leave(), delete_leave(), get_leave(), _leave_local_callback(), leave_workflow_callback(), list_leaves(), submit_leave(), update_leave() (+5 more)
|
||||
Cohesion: 0.33
|
||||
Nodes (6): int, Config, LeaveCreate, LeaveResponse, LeaveUpdate, Pydantic schemas - 请假申请
|
||||
|
||||
### Community 53 - "Community 53"
|
||||
Cohesion: 0.29
|
||||
Nodes (7): batch_submit_contract_approval(), Java: batchSubmitApproval, Java: batchSubmitApproval, Java: batchSubmitApproval, Java: batchSubmitApproval, Java: batchSubmitApproval, Java: batchSubmitApproval
|
||||
Cohesion: 0.28
|
||||
Nodes (20): Any, bool, date, int, Session, str, _contact_row_to_dict(), create_contact() (+12 more)
|
||||
|
||||
### Community 54 - "Community 54"
|
||||
Cohesion: 0.34
|
||||
@@ -351,7 +374,7 @@ Nodes (10): Any, Request, str, str, parse_admin_request_json(), 运营 Web(/we
|
||||
|
||||
### Community 57 - "Community 57"
|
||||
Cohesion: 0.11
|
||||
Nodes (26): _avatar_url_field(), _build_user_info_payload(), get_current_user_profile(), get_web_auth_menu_codes(), _jwt_user_payload(), logout(), public_quote_share(), 登出:吊销 Redis 会话(若已配置 REDIS_HOST)。 (+18 more)
|
||||
Nodes (19): 供方全量列表(下拉)— Java: CrmSupplierInfoController.listAll, 供方全量列表(下拉)— Java: CrmSupplierInfoController.listAll, 供方全量列表(下拉)— Java: CrmSupplierInfoController.listAll, 供方全量列表(下拉)— Java: CrmSupplierInfoController.listAll, 供方全量列表(下拉)— Java: CrmSupplierInfoController.listAll, 供方全量列表(下拉)— Java: CrmSupplierInfoController.listAll, 供方全量列表(下拉)— Java: CrmSupplierInfoController.listAll, 供方全量列表(下拉)— Java: CrmSupplierInfoController.listAll (+11 more)
|
||||
|
||||
### Community 59 - "Community 59"
|
||||
Cohesion: 0.11
|
||||
@@ -362,8 +385,8 @@ Cohesion: 0.19
|
||||
Nodes (32): Any, bool, CrmContractProductPriceTier, date, Decimal, int, Session, str (+24 more)
|
||||
|
||||
### Community 61 - "Community 61"
|
||||
Cohesion: 0.17
|
||||
Nodes (30): register_quote_routes(), bool, int, Session, str, accept_quote(), generate_pdf(), generate_share() (+22 more)
|
||||
Cohesion: 0.11
|
||||
Nodes (27): API 路由包 — 山峡化工生产一体化门户, create_leave(), delete_leave(), get_leave(), _leave_local_callback(), leave_workflow_callback(), list_leaves(), submit_leave() (+19 more)
|
||||
|
||||
### Community 62 - "Community 62"
|
||||
Cohesion: 0.35
|
||||
@@ -371,51 +394,51 @@ Nodes (17): Any, bool, int, Session, str, _build_tree(), _cascade_soft_delete(),
|
||||
|
||||
### Community 63 - "Community 63"
|
||||
Cohesion: 0.17
|
||||
Nodes (29): Any, bool, int, Session, str, Query, approve_quote(), can_user_approve() (+21 more)
|
||||
Nodes (30): Any, bool, int, Session, str, date, Query, approve_quote() (+22 more)
|
||||
|
||||
### Community 65 - "Community 65"
|
||||
Cohesion: 0.12
|
||||
Nodes (16): invoice_info_list(), 按客户ID查询开票信息(与 by-customer 等价), 按客户ID查询开票信息(与 by-customer 等价), 按客户ID查询开票信息(与 by-customer 等价), 按客户ID查询开票信息(与 by-customer 等价), 按客户ID查询开票信息(与 by-customer 等价), 按客户ID查询开票信息(与 by-customer 等价), 按客户ID查询开票信息(与 by-customer 等价) (+8 more)
|
||||
|
||||
### Community 68 - "Community 68"
|
||||
Cohesion: 0.27
|
||||
Nodes (18): Any, bool, int, Session, str, create_clue_follow(), delete_clue_follow(), get_clue_follow() (+10 more)
|
||||
Cohesion: 0.33
|
||||
Nodes (14): BxUserContext, Session, str, UploadFile, AttachmentOut, bind_biz(), delete_attachment(), download_file() (+6 more)
|
||||
|
||||
### Community 69 - "Community 69"
|
||||
Cohesion: 0.19
|
||||
Nodes (45): Any, CRM 商机 CRUD(主表 + 阶段/赢输单/统计/看板/漏斗), date, datetime, Decimal, int, Session, str (+37 more)
|
||||
|
||||
### Community 70 - "Community 70"
|
||||
Cohesion: 0.20
|
||||
Nodes (28): 公共接口(Web 登录、刷新 Token、登出;用户模型对齐 docs/sql/shanxia2.0.sql 基线), refresh_token(), bool, Redis, Session, str, create_access_token(), create_refresh_token() (+20 more)
|
||||
Cohesion: 0.33
|
||||
Nodes (14): Any, int, Session, str, create_dict_data(), get_dict_data(), list_dict_data(), list_dict_data_options() (+6 more)
|
||||
|
||||
### Community 71 - "Community 71"
|
||||
Cohesion: 0.14
|
||||
Nodes (17): Any, int, _build_category_tree(), _collect_category_with_ancestors(), list_category_tree(), list_products(), _product_row_to_dict(), 获取产品分类树(嵌套 children,供树形表格/树选择器使用) (+9 more)
|
||||
Cohesion: 0.40
|
||||
Nodes (5): _product_row_to_dict(), 产品 ORM 对象转 dict(camelCase 键名), 产品 ORM 对象转 dict(camelCase 键名), 产品 ORM 对象转 dict(camelCase 键名), 产品 ORM 对象转 dict(camelCase 键名)
|
||||
|
||||
### Community 72 - "Community 72"
|
||||
Cohesion: 0.38
|
||||
Nodes (15): Any, bool, int, Session, str, create_post(), get_post(), list_posts() (+7 more)
|
||||
Nodes (15): Any, bool, int, Session, str, create_site(), get_site(), list_sites() (+7 more)
|
||||
|
||||
### Community 73 - "Community 73"
|
||||
Cohesion: 0.24
|
||||
Nodes (12): Session, str, iter_user_menu_perm_codes(), _map_role_name_to_web(), Web 管理端登录:基于 V0.3 sys_user / sys_user_role / sys_role 的角色与菜单权限解析, 将 sys_role.role_name 映射为 web-admin 使用的 role 字符串。, 根据用户关联角色解析 Web 端 role(admin / super_admin)。, 根据用户关联角色解析 Web 端 role(admin / super_admin)。 (+4 more)
|
||||
Cohesion: 0.33
|
||||
Nodes (6): bx_health(), P0 健康检查:验证 bx 路由已挂载且响应协议为 code=0。, P0 健康检查:验证 bx 路由已挂载且响应协议为 code=0。, P0 健康检查:验证 bx 路由已挂载且响应协议为 code=0。, P0 健康检查:验证 bx 路由已挂载且响应协议为 code=0。, P0 健康检查:验证 bx 路由已挂载且响应协议为 code=0。
|
||||
|
||||
### Community 74 - "Community 74"
|
||||
Cohesion: 0.07
|
||||
Nodes (46): Decimal, _apply_contract_entity_fields(), _apply_contract_scalar_fields(), _build_contract_filters(), _calc_amount_with_tax(), create_contract(), create_from_opportunity(), create_from_quote() (+38 more)
|
||||
Cohesion: 0.08
|
||||
Nodes (99): register_contract_routes(), Any, bool, CRM 合同 CRUD — 对照 CrmContractServiceImpl.java(列表/详情 P1), Decimal, int, Session, str (+91 more)
|
||||
|
||||
### Community 75 - "Community 75"
|
||||
Cohesion: 0.16
|
||||
Nodes (21): Any, bool, Session, str, Java: viewByShareCode, Java: viewByShareCode, Java: viewByShareCode, Java: viewByShareCode (+13 more)
|
||||
|
||||
### Community 76 - "Community 76"
|
||||
Cohesion: 0.34
|
||||
Nodes (18): Any, bool, datetime, int, Session, str, create_opportunity_follow(), get_opportunity_follow() (+10 more)
|
||||
Cohesion: 0.35
|
||||
Nodes (19): Any, bool, datetime, int, Session, str, create_opportunity_follow(), get_opportunity_follow() (+11 more)
|
||||
|
||||
### Community 78 - "Community 78"
|
||||
Cohesion: 0.11
|
||||
Nodes (42): Any, CRM 报价单 CRUD — 对照 CrmQuoteServiceImpl.java(P2 全量), date, datetime, Decimal, _build_quote_filters(), calculate_quote_amount(), create_quote() (+34 more)
|
||||
Cohesion: 0.42
|
||||
Nodes (13): Any, bool, Session, str, _clear_default_for_customer(), create_invoice_info(), get_invoice_info(), list_invoice_info_by_customer() (+5 more)
|
||||
|
||||
### Community 79 - "Community 79"
|
||||
Cohesion: 0.22
|
||||
@@ -426,16 +449,16 @@ Cohesion: 0.22
|
||||
Nodes (9): generate_contract_no(), Java: generateContractNo — {供方编码}/X-JT + yyyyMMdd + 3位流水, Java: generateContractNo — {供方编码}/X-JT + yyyyMMdd + 3位流水, Java: generateContractNo — {供方编码}/X-JT{yyyyMMdd}{3位序号}, Java: generateContractNo — {供方编码}/X-JT{yyyyMMdd}{3位序号}, Java: generateContractNo — {供方编码}/X-JT{yyyyMMdd}{3位序号}, Java: generateContractNo — {供方编码}/X-JT{yyyyMMdd}{3位序号}, Java: generateContractNo — {供方编码}/X-JT{yyyyMMdd}{3位序号} (+1 more)
|
||||
|
||||
### Community 81 - "Community 81"
|
||||
Cohesion: 0.60
|
||||
Nodes (10): Any, Session, str, _apply_create_range(), _base_query(), get_clue_level_statistics(), get_clue_overview_statistics(), get_clue_owner_statistics() (+2 more)
|
||||
Cohesion: 0.22
|
||||
Nodes (18): bytes, int, str, download_file_bytes(), file_stream(), get_access_url(), get_download_url(), get_preview_url() (+10 more)
|
||||
|
||||
### Community 82 - "Community 82"
|
||||
Cohesion: 0.33
|
||||
Nodes (11): SysOss, int, Session, str, SysOss, create_oss(), _oss_row_to_dict(), create_oss() (+3 more)
|
||||
|
||||
### Community 83 - "Community 83"
|
||||
Cohesion: 0.18
|
||||
Nodes (31): CrmContract, Query, Any, CrmContract, CrmContractProductPriceTier, date, datetime, int (+23 more)
|
||||
Cohesion: 0.14
|
||||
Nodes (14): _build_contract_filters(), export_contracts(), Java: queryList for export, Java: queryList for export, Java: queryList for export, Java: queryList for export, Java: buildQueryWrapper, Java: queryList for export (+6 more)
|
||||
|
||||
### Community 84 - "Community 84"
|
||||
Cohesion: 0.33
|
||||
@@ -446,16 +469,16 @@ Cohesion: 0.11
|
||||
Nodes (19): 分页查询供方列表 — Java: CrmSupplierInfoController.list, 分页查询供方列表 — Java: CrmSupplierInfoController.list, 分页查询供方列表 — Java: CrmSupplierInfoController.list, 分页查询供方列表 — Java: CrmSupplierInfoController.list, 分页查询供方列表 — Java: CrmSupplierInfoController.list, 分页查询供方列表 — Java: CrmSupplierInfoController.list, 分页查询供方列表 — Java: CrmSupplierInfoController.list, 分页查询供方列表 — Java: CrmSupplierInfoController.list (+11 more)
|
||||
|
||||
### Community 86 - "Community 86"
|
||||
Cohesion: 0.20
|
||||
Nodes (10): 供方详情 — Java: CrmSupplierInfoController.getInfo, 供方详情 — Java: CrmSupplierInfoController.getInfo, 供方详情 — Java: CrmSupplierInfoController.getInfo, 供方详情 — Java: CrmSupplierInfoController.getInfo, 供方详情 — Java: CrmSupplierInfoController.getInfo, 供方详情 — Java: CrmSupplierInfoController.getInfo, 供方详情 — Java: CrmSupplierInfoController.getInfo, 供方详情 — Java: CrmSupplierInfoController.getInfo (+2 more)
|
||||
Cohesion: 0.30
|
||||
Nodes (8): Any, bool, int, Session, str, BxCrudService, 报销模块 Service 基类 — 租户隔离 + UUID + 软删除。, M
|
||||
|
||||
### Community 87 - "Community 87"
|
||||
Cohesion: 0.20
|
||||
Nodes (10): 删除供方 — Java: CrmSupplierInfoController.remove, 删除供方 — Java: CrmSupplierInfoController.remove, 删除供方 — Java: CrmSupplierInfoController.remove, 删除供方 — Java: CrmSupplierInfoController.remove, 删除供方 — Java: CrmSupplierInfoController.remove, 删除供方 — Java: CrmSupplierInfoController.remove, 删除供方 — Java: CrmSupplierInfoController.remove, 删除供方 — Java: CrmSupplierInfoController.remove (+2 more)
|
||||
|
||||
### Community 88 - "Community 88"
|
||||
Cohesion: 0.33
|
||||
Nodes (10): Any, int, Session, str, list_ethnics(), 民族码表 CRUD(全局 sys_ethnic), _row_to_dict(), 民族码表 sys_ethnic(国标 GB/T 3304,全局) (+2 more)
|
||||
Cohesion: 0.21
|
||||
Nodes (16): Any, int, str, BusinessException, InvalidStatusTransitionException, log_api_request(), log_delivery_operation(), log_operation() (+8 more)
|
||||
|
||||
### Community 89 - "Community 89"
|
||||
Cohesion: 0.25
|
||||
@@ -474,71 +497,155 @@ Cohesion: 0.29
|
||||
Nodes (7): Java: renewContract — 基础续签, Java: renewContract — 基础续签, Java: renewContract — 基础续签, Java: renewContract — 基础续签, Java: renewContract — 基础续签, Java: renewContract — 基础续签, renew_contract()
|
||||
|
||||
### Community 93 - "Community 93"
|
||||
Cohesion: 0.42
|
||||
Nodes (13): Any, bool, Session, str, _clear_default_for_customer(), create_invoice_info(), get_invoice_info(), list_invoice_info_by_customer() (+5 more)
|
||||
Cohesion: 0.26
|
||||
Nodes (22): Any, bool, datetime, int, Session, str, BizSampleCode, batch_generate_sample_codes() (+14 more)
|
||||
|
||||
### Community 94 - "Community 94"
|
||||
Cohesion: 0.17
|
||||
Nodes (21): Decimal, str, Any, str, derive_legacy_status_from_three(), derive_three_status_from_legacy(), 阶段A兼容:从旧 status 推导三字段。 约束:旧 status 本身混合了支付/配送/订单生命周期,因此只能尽力推断; 若业务侧已有更精确, 阶段A兼容:从三字段反推旧 status(用于旧前端/旧筛选参数兼容)。 (+13 more)
|
||||
Cohesion: 0.18
|
||||
Nodes (20): Decimal, str, Any, str, derive_legacy_status_from_three(), derive_three_status_from_legacy(), 阶段A兼容:从旧 status 推导三字段。 约束:旧 status 本身混合了支付/配送/订单生命周期,因此只能尽力推断; 若业务侧已有更精确, 阶段A兼容:从三字段反推旧 status(用于旧前端/旧筛选参数兼容)。 (+12 more)
|
||||
|
||||
### Community 95 - "Community 95"
|
||||
Cohesion: 0.13
|
||||
Nodes (15): generate_auto_product_no(), _get_quote_item_field(), Java: generateAutoProductNo — SXWL + 8位随机大写字符, Java: generateAutoProductNo — SXWL + 8位随机大写字符, Java: resolveProductIdForQuoteItem(CrmProduct 无 tax_rate,跳过税率匹配), Java: resolveProductIdForQuoteItem(CrmProduct 无 tax_rate,跳过税率匹配), Java: generateAutoProductNo — SXWL + 8位随机大写字符, Java: generateAutoProductNo — SXWL + 8位随机大写字符 (+7 more)
|
||||
|
||||
### Community 96 - "Community 96"
|
||||
Cohesion: 0.18
|
||||
Nodes (19): datetime, int, str, datetime, int, Session, str, BizNoKind (+11 more)
|
||||
Cohesion: 0.21
|
||||
Nodes (14): Any, str, bool, BxUserContext, int, Session, str, AttachmentService (+6 more)
|
||||
|
||||
### Community 97 - "Community 97"
|
||||
Cohesion: 0.22
|
||||
Nodes (9): Java: statisticsOverview, Java: statisticsOverview, Java: statisticsOverview, Java: statisticsOverview, Java: statisticsOverview, Java: statisticsOverview, Java: statisticsOverview, Java: statisticsOverview (+1 more)
|
||||
Cohesion: 0.10
|
||||
Nodes (61): register_quote_routes(), Any, bool, CRM 报价单 CRUD — 对照 CrmQuoteServiceImpl.java(P2 全量), int, Session, str, accept_quote() (+53 more)
|
||||
|
||||
### Community 98 - "Community 98"
|
||||
Cohesion: 0.22
|
||||
Nodes (9): Java: statisticsTrend, Java: statisticsTrend, Java: statisticsTrend, Java: statisticsTrend, Java: statisticsTrend, Java: statisticsTrend, Java: statisticsTrend, Java: statisticsTrend (+1 more)
|
||||
Cohesion: 0.26
|
||||
Nodes (9): Exception, bytes, str, bytes, BytesIO, convert_heic_to_jpeg(), process_image_content(), 将 HEIC/HEIF 格式转换为 JPEG 格式 (+1 more)
|
||||
|
||||
### Community 99 - "Community 99"
|
||||
Cohesion: 0.29
|
||||
Nodes (7): _parse_letter_oss_ids_from_tier(), Java: validateFrameworkContractForSubmitApproval, Java: validateFrameworkContractForSubmitApproval, Java: validateFrameworkContractForSubmitApproval, Java: validateFrameworkContractForSubmitApproval, Java: validateFrameworkContractForSubmitApproval, validate_framework_contract_for_submit_approval()
|
||||
Cohesion: 0.20
|
||||
Nodes (10): 供方详情 — Java: CrmSupplierInfoController.getInfo, 供方详情 — Java: CrmSupplierInfoController.getInfo, 供方详情 — Java: CrmSupplierInfoController.getInfo, 供方详情 — Java: CrmSupplierInfoController.getInfo, 供方详情 — Java: CrmSupplierInfoController.getInfo, 供方详情 — Java: CrmSupplierInfoController.getInfo, 供方详情 — Java: CrmSupplierInfoController.getInfo, 供方详情 — Java: CrmSupplierInfoController.getInfo (+2 more)
|
||||
|
||||
### Community 100 - "Community 100"
|
||||
Cohesion: 0.40
|
||||
Nodes (5): bool, str, get_password_hash(), 验证密码(哈希非 bcrypt 或损坏时返回 False,避免抛错), verify_password()
|
||||
Cohesion: 0.36
|
||||
Nodes (9): Any, int, Session, str, get_pool_record(), list_pool_records(), _row_to_dict(), total_pages() (+1 more)
|
||||
|
||||
### Community 101 - "Community 101"
|
||||
Cohesion: 0.40
|
||||
Nodes (5): list_roles_for_designer(), 返回角色下拉选项(label=角色名,value=角色ID UUID),供流程设计器审批人选择使用。 与 /roles 不同,此端点返回角色 UUID, 返回角色下拉选项(label=角色名,value=角色ID UUID),供流程设计器审批人选择使用。 与 /roles 不同,此端点返回角色 UUID, 返回角色下拉选项(label=角色名,value=角色ID UUID),供流程设计器审批人选择使用。 与 /roles 不同,此端点返回角色 UUID, 返回角色下拉选项(label=角色名,value=角色ID UUID),供流程设计器审批人选择使用。 与 /roles 不同,此端点返回角色 UUID
|
||||
Cohesion: 0.18
|
||||
Nodes (15): Any, int, Session, str, Base, list_ethnics(), 民族码表 CRUD(全局 sys_ethnic), _row_to_dict() (+7 more)
|
||||
|
||||
### Community 102 - "Community 102"
|
||||
Cohesion: 0.22
|
||||
Nodes (9): Java: statisticsStatus, Java: statisticsStatus, Java: statisticsStatus, Java: statisticsStatus, Java: statisticsStatus, Java: statisticsStatus, Java: statisticsStatus, Java: statisticsStatus (+1 more)
|
||||
|
||||
### Community 103 - "Community 103"
|
||||
Cohesion: 0.67
|
||||
Nodes (3): Web 端登录用 RSA 公钥(PKCS#1 v1.5,与 JSEncrypt 一致), Web 端登录用 RSA 公钥(PKCS#1 v1.5,与 JSEncrypt 一致), web_login_rsa_public_key()
|
||||
Cohesion: 0.22
|
||||
Nodes (17): bool, int, Redis, Request, str, _claims_from_auth(), _coerce_post_method_override_to_get(), _get_redis_client() (+9 more)
|
||||
|
||||
### Community 104 - "Community 104"
|
||||
Cohesion: 0.14
|
||||
Nodes (25): Any, bool, BxUserContext, BxWorkflowNode, float, int, Session, str (+17 more)
|
||||
|
||||
### Community 105 - "Community 105"
|
||||
Cohesion: 0.32
|
||||
Nodes (10): datetime, int, str, 审批轮次过滤 — 驳回后重新提交时,进度接口仅展示当前轮次。, format_datetime(), generate_random_password(), get_current_time(), get_file_size_display() (+2 more)
|
||||
|
||||
### Community 106 - "Community 106"
|
||||
Cohesion: 0.29
|
||||
Nodes (10): datetime, int, Session, str, BizNoKind, allocate_next_biz_no(), _format_biz_no(), _prefix_for() (+2 more)
|
||||
|
||||
### Community 107 - "Community 107"
|
||||
Cohesion: 0.29
|
||||
Nodes (7): batch_submit_contract_approval(), Java: batchSubmitApproval, Java: batchSubmitApproval, Java: batchSubmitApproval, Java: batchSubmitApproval, Java: batchSubmitApproval, Java: batchSubmitApproval
|
||||
|
||||
### Community 108 - "Community 108"
|
||||
Cohesion: 0.18
|
||||
Nodes (11): batch_assign_owner(), download_contract_pdf(), Java: batchAssignOwner, Java: downloadContractPdf — 返回合同文件 URL/路径, Java: batchAssignOwner, Java: batchAssignOwner, Java: batchAssignOwner, Java: batchAssignOwner (+3 more)
|
||||
|
||||
### Community 109 - "Community 109"
|
||||
Cohesion: 0.40
|
||||
Nodes (4): str, 附件上传 bizType 与 MinIO 目录映射(对齐原 CRM oss 上传语义), 优先使用显式 folder;否则按 bizType 映射默认目录。, resolve_upload_folder()
|
||||
Cohesion: 0.33
|
||||
Nodes (5): str, 附件上传 bizType 与 MinIO 目录映射(对齐原 CRM oss 上传语义), 优先使用显式 folder;否则按 bizType 映射默认目录。, 优先使用显式 folder;否则按 bizType 映射默认目录。, resolve_upload_folder()
|
||||
|
||||
### Community 111 - "Community 111"
|
||||
Cohesion: 0.18
|
||||
Nodes (5): ContactByCustomerBody, ContactDetailBody, ContactSetPrimaryBody, CRM 联系人 Pydantic Schemas, SoftDeleteModel
|
||||
|
||||
### Community 112 - "Community 112"
|
||||
Cohesion: 0.29
|
||||
Nodes (7): create_from_opportunity(), _opportunity_products_to_contract_products(), Java: createFromOpportunity — 返回合同 id, Java: createFromOpportunity — 返回合同 id, Java: createFromOpportunity — 返回合同 id, Java: createFromOpportunity — 返回合同 id, Java: createFromOpportunity — 返回合同 id
|
||||
|
||||
### Community 113 - "Community 113"
|
||||
Cohesion: 0.18
|
||||
Nodes (10): Session, str, _auto_fill_create_dept_id(), get_db(), ORM before_insert 钩子:当 create_dept_id 为空时,自动从请求上下文填充当前用户部门 ID, get_user_menu_codes(), 菜单 code 权限守卫(V0.3:通过 sys_user_role → sys_role_menu → sys_menu.perms), 读取用户授权的菜单权限标识集合(与前端 meta.menuCode / perms 对齐)。 (+2 more)
|
||||
Cohesion: 0.35
|
||||
Nodes (9): check_customer_protect_time(), _execute_single_rule(), _get_all_tenant_nos(), pool_recovery_job(), 公海池自动回收任务(由 APScheduler 调度) 遍历所有租户的启用规则,执行自动回收。, 每天凌晨1点:检查保护期到期客户,跟进次数不足则退回公海, 每天早上9点:保护期到期提醒(3天内到期且跟进不足), remind_customer_recycle() (+1 more)
|
||||
|
||||
### Community 114 - "Community 114"
|
||||
Cohesion: 0.29
|
||||
Nodes (7): Java: withdrawApproval, Java: withdrawApproval, Java: withdrawApproval, Java: withdrawApproval, Java: withdrawApproval, Java: withdrawApproval, withdraw_contract_approval()
|
||||
|
||||
### Community 116 - "Community 116"
|
||||
Cohesion: 0.25
|
||||
Nodes (8): create_from_quote(), _quote_products_to_contract_products(), Java: createFromQuote — 返回合同 id, Java: createFromQuote — 返回合同 id, Java: createFromQuote — 返回合同 id, Java: createFromQuote — 返回合同 id, Java: createFromQuote — 返回合同 id, Java: createFromQuote — 返回合同 id
|
||||
|
||||
### Community 117 - "Community 117"
|
||||
Cohesion: 0.33
|
||||
Nodes (6): datetime, str, _dt_to_str(), PagedQuery, PagedResponse, bx 原系统 API 响应包装(code=0 / msg / data.rows),与门户 success_response 分离。
|
||||
|
||||
### Community 118 - "Community 118"
|
||||
Cohesion: 0.09
|
||||
Nodes (27): datetime, Decimal, calculate_quote_amount(), _decimal_value(), _parse_optional_datetime(), _period_key(), Java: statisticsOverview, Java: statisticsOverview (+19 more)
|
||||
|
||||
### Community 119 - "Community 119"
|
||||
Cohesion: 0.29
|
||||
Nodes (4): int, MinIOStorage, MinIO 预签名下载 URL,携带原始文件名。, 带下载文件名的访问 URL;默认实现为普通访问地址。
|
||||
|
||||
### Community 120 - "Community 120"
|
||||
Cohesion: 0.33
|
||||
Nodes (6): Java Controller TODO — 保持 pending,记录备注, Java Controller TODO — 保持 pending,记录备注, Java Controller TODO — 保持 pending,记录备注, Java Controller TODO — 保持 pending,记录备注, Java Controller TODO — 保持 pending,记录备注, submit_change_approval()
|
||||
|
||||
### Community 121 - "Community 121"
|
||||
Cohesion: 0.44
|
||||
Nodes (8): bool, int, Session, str, ApiRequestLogCRUD, SysApiRequestLog, SysApiRequestLogHis, SysApiRequestLog
|
||||
|
||||
### Community 122 - "Community 122"
|
||||
Cohesion: 0.38
|
||||
Nodes (11): Any, int, Session, str, _business_type_from_path(), get_oper_log(), list_oper_logs(), _oper_status() (+3 more)
|
||||
|
||||
### Community 123 - "Community 123"
|
||||
Cohesion: 0.20
|
||||
Nodes (10): 导出供方列表 — Java: CrmSupplierInfoController.export, 导出供方列表 — Java: CrmSupplierInfoController.export, 导出供方列表 — Java: CrmSupplierInfoController.export, 导出供方列表 — Java: CrmSupplierInfoController.export, 导出供方列表 — Java: CrmSupplierInfoController.export, 导出供方列表 — Java: CrmSupplierInfoController.export, 导出供方列表 — Java: CrmSupplierInfoController.export, 导出供方列表 — Java: CrmSupplierInfoController.export (+2 more)
|
||||
|
||||
### Community 124 - "Community 124"
|
||||
Cohesion: 0.29
|
||||
Nodes (6): _coerce_optional_id(), WorkflowDefCreate, WorkflowDefOut, WorkflowDefUpdate, WorkflowNodeCreate, WorkflowNodeOut
|
||||
|
||||
### Community 125 - "Community 125"
|
||||
Cohesion: 0.29
|
||||
Nodes (6): CustomerPoolDetailBody, CustomerPoolListBody, PoolCustomerListBody, PoolRecordDetailBody, PoolRecordListBody, CRM 客户公海池记录 Pydantic Schemas
|
||||
|
||||
### Community 127 - "Community 127"
|
||||
Cohesion: 0.50
|
||||
Nodes (3): Config, PageResult, ResponseModel
|
||||
|
||||
### Community 128 - "Community 128"
|
||||
Cohesion: 0.67
|
||||
Nodes (3): str, format_api_error_message(), 将 HTTP/SQLAlchemy 等异常转为可展示的错误文案(避免 str([]) 空列表)。
|
||||
|
||||
### Community 129 - "Community 129"
|
||||
Cohesion: 0.33
|
||||
Nodes (5): CRM 客户管理 Pydantic Schemas, CustomerAssignPoolBody, CustomerCheckDuplicateBody, CustomerDetailBody, CRM 客户管理 CRUD(客户 + 联系人 + 跟进记录)
|
||||
|
||||
## Knowledge Gaps
|
||||
- **42 isolated node(s):** `bool`, `bool`, `Config`, `bool`, `bool` (+37 more)
|
||||
- **52 isolated node(s):** `bool`, `bool`, `Config`, `bool`, `bool` (+47 more)
|
||||
These have ≤1 connection - possible missing edges or undocumented components.
|
||||
- **3 thin communities (<3 nodes) omitted from report** — run `graphify query` to explore isolated nodes.
|
||||
- **5 thin communities (<3 nodes) omitted from report** — run `graphify query` to explore isolated nodes.
|
||||
|
||||
## Suggested Questions
|
||||
_Questions this graph is uniquely positioned to answer:_
|
||||
|
||||
- **Why does `SysUser` connect `Community 1` to `Community 0`, `Community 2`, `Community 5`, `Community 6`, `Community 8`, `Community 10`, `Community 14`, `Community 17`, `Community 18`, `Community 36`, `Community 40`, `Community 45`, `Community 47`, `Community 57`, `Community 61`, `Community 63`, `Community 69`, `Community 70`, `Community 74`, `Community 78`, `Community 83`, `Community 96`?**
|
||||
_High betweenness centrality (0.148) - this node is a cross-community bridge._
|
||||
- **Why does `generate_uuid()` connect `Community 0` to `Community 1`, `Community 4`, `Community 5`, `Community 7`, `Community 8`, `Community 9`, `Community 10`, `Community 14`, `Community 17`, `Community 18`, `Community 19`, `Community 21`, `Community 22`, `Community 27`, `Community 28`, `Community 36`, `Community 39`, `Community 40`, `Community 42`, `Community 45`, `Community 54`, `Community 55`, `Community 57`, `Community 60`, `Community 62`, `Community 63`, `Community 68`, `Community 69`, `Community 70`, `Community 72`, `Community 74`, `Community 75`, `Community 76`, `Community 78`, `Community 82`, `Community 83`, `Community 93`, `Community 95`, `Community 96`?**
|
||||
_High betweenness centrality (0.113) - this node is a cross-community bridge._
|
||||
- **Why does `error_response()` connect `Community 11` to `Community 1`, `Community 5`, `Community 6`, `Community 10`, `Community 16`, `Community 22`, `Community 36`, `Community 38`, `Community 41`, `Community 43`, `Community 45`, `Community 47`, `Community 48`, `Community 50`, `Community 52`, `Community 57`, `Community 59`, `Community 61`, `Community 65`, `Community 70`, `Community 85`, `Community 86`, `Community 87`?**
|
||||
_High betweenness centrality (0.088) - this node is a cross-community bridge._
|
||||
- **Why does `generate_uuid()` connect `Community 0` to `Community 4`, `Community 6`, `Community 7`, `Community 8`, `Community 9`, `Community 10`, `Community 12`, `Community 14`, `Community 18`, `Community 19`, `Community 21`, `Community 27`, `Community 39`, `Community 40`, `Community 42`, `Community 43`, `Community 46`, `Community 47`, `Community 53`, `Community 54`, `Community 55`, `Community 60`, `Community 62`, `Community 63`, `Community 69`, `Community 70`, `Community 72`, `Community 74`, `Community 75`, `Community 76`, `Community 78`, `Community 82`, `Community 86`, `Community 93`, `Community 95`, `Community 97`, `Community 100`, `Community 104`, `Community 105`, `Community 106`, `Community 113`?**
|
||||
_High betweenness centrality (0.111) - this node is a cross-community bridge._
|
||||
- **Why does `SysUser` connect `Community 101` to `Community 1`, `Community 6`, `Community 8`, `Community 10`, `Community 12`, `Community 14`, `Community 18`, `Community 23`, `Community 38`, `Community 40`, `Community 44`, `Community 46`, `Community 49`, `Community 63`, `Community 69`, `Community 74`, `Community 93`, `Community 97`, `Community 100`, `Community 105`, `Community 118`?**
|
||||
_High betweenness centrality (0.101) - this node is a cross-community bridge._
|
||||
- **Why does `BaseModel` connect `Community 37` to `Community 129`, `Community 12`, `Community 13`, `Community 16`, `Community 17`, `Community 28`, `Community 41`, `Community 45`, `Community 47`, `Community 48`, `Community 49`, `Community 52`, `Community 61`, `Community 68`, `Community 101`, `Community 111`, `Community 117`, `Community 124`, `Community 125`, `Community 127`?**
|
||||
_High betweenness centrality (0.092) - this node is a cross-community bridge._
|
||||
- **Are the 28 inferred relationships involving `str` (e.g. with `CRUDBase` and `LeaveCreate`) actually correct?**
|
||||
_`str` has 28 INFERRED edges - model-reasoned connections that need verification._
|
||||
- **Are the 100 inferred relationships involving `Session` (e.g. with `ClueAssignBody` and `ClueConvertBody`) actually correct?**
|
||||
|
||||
backend/graphify-out/cache/ast/011868ea9a25a17816882b6bc0dc097eeca74adaf8c1a00943397a2a1bbdb389.json
Vendored
+1
@@ -0,0 +1 @@
|
||||
{"nodes": [{"id": "users_zlwu_work_00code_shanxia2_0_backend_app_services_bx_attachment_py", "label": "attachment.py", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/attachment.py", "source_location": "L1"}, {"id": "bx_attachment_attachmentservice", "label": "AttachmentService", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/attachment.py", "source_location": "L14"}, {"id": "bx_attachment_attachmentservice_tenant_no", "label": "._tenant_no()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/attachment.py", "source_location": "L16"}, {"id": "session", "label": "Session", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/attachment.py", "source_location": "L16"}, {"id": "bxusercontext", "label": "BxUserContext", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/attachment.py", "source_location": "L16"}, {"id": "str", "label": "str", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/attachment.py", "source_location": "L16"}, {"id": "bx_attachment_attachmentservice_get_by_id", "label": ".get_by_id()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/attachment.py", "source_location": "L20"}, {"id": "bxattachment", "label": "BxAttachment", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/attachment.py", "source_location": "L20"}, {"id": "bx_attachment_attachmentservice_create", "label": ".create()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/attachment.py", "source_location": "L24"}, {"id": "bx_attachment_attachmentservice_soft_delete", "label": ".soft_delete()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/attachment.py", "source_location": "L41"}, {"id": "bool", "label": "bool", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/attachment.py", "source_location": "L41"}, {"id": "bx_attachment_attachmentservice_get_by_biz", "label": ".get_by_biz()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/attachment.py", "source_location": "L48"}, {"id": "bx_attachment_attachmentservice_bind_biz", "label": ".bind_biz()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/attachment.py", "source_location": "L58"}, {"id": "int", "label": "int", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/attachment.py", "source_location": "L58"}, {"id": "bx_attachment_attachmentservice_count_invoice_attach_by_biz_ids", "label": ".count_invoice_attach_by_biz_ids()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/attachment.py", "source_location": "L89"}], "edges": [{"source": "users_zlwu_work_00code_shanxia2_0_backend_app_services_bx_attachment_py", "target": "typing", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/attachment.py", "source_location": "L3", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_services_bx_attachment_py", "target": "sqlalchemy", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/attachment.py", "source_location": "L5", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_services_bx_attachment_py", "target": "sqlalchemy_orm", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/attachment.py", "source_location": "L6", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_services_bx_attachment_py", "target": "app_core_bx_auth", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/attachment.py", "source_location": "L8", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_services_bx_attachment_py", "target": "app_core_tenant_context", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/attachment.py", "source_location": "L9", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_services_bx_attachment_py", "target": "app_models_bx_models", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/attachment.py", "sourceLine truncated
|
||||
backend/graphify-out/cache/ast/035a12f3afe54a283145453608bc65c3043f3a0557afd8b3d382dcbc6d86aa48.json
Vendored
+1
@@ -0,0 +1 @@
|
||||
{"nodes": [{"id": "users_zlwu_work_00code_shanxia2_0_backend_app_schemas_bx_advance_py", "label": "advance.py", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/bx/advance.py", "source_location": "L1"}, {"id": "bx_advance_coerce_optional_id", "label": "_coerce_optional_id()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/bx/advance.py", "source_location": "L9"}, {"id": "bx_advance_advanceapplycreate", "label": "AdvanceApplyCreate", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/bx/advance.py", "source_location": "L16"}, {"id": "basemodel", "label": "BaseModel", "file_type": "code", "source_file": "", "source_location": ""}, {"id": "bx_advance_advanceapplycreate_validate_expense_item_id", "label": ".validate_expense_item_id()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/bx/advance.py", "source_location": "L27"}, {"id": "bx_advance_advanceapplyupdate", "label": "AdvanceApplyUpdate", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/bx/advance.py", "source_location": "L31"}, {"id": "bx_advance_advanceapplyupdate_validate_expense_item_id", "label": ".validate_expense_item_id()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/bx/advance.py", "source_location": "L42"}, {"id": "bx_advance_advanceapplyout", "label": "AdvanceApplyOut", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/bx/advance.py", "source_location": "L46"}, {"id": "bx_advance_advanceapprovalcreate", "label": "AdvanceApprovalCreate", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/bx/advance.py", "source_location": "L69"}, {"id": "bx_advance_advanceapprovalout", "label": "AdvanceApprovalOut", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/bx/advance.py", "source_location": "L76"}, {"id": "bx_advance_advancemystatsout", "label": "AdvanceMyStatsOut", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/bx/advance.py", "source_location": "L89"}, {"id": "bx_advance_advanceapproverpendingstatsout", "label": "AdvanceApproverPendingStatsOut", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/bx/advance.py", "source_location": "L104"}], "edges": [{"source": "users_zlwu_work_00code_shanxia2_0_backend_app_schemas_bx_advance_py", "target": "typing", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/bx/advance.py", "source_location": "L1", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_schemas_bx_advance_py", "target": "pydantic", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/bx/advance.py", "source_location": "L3", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_schemas_bx_advance_py", "target": "pydantic_alias_generators", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/bx/advance.py", "source_location": "L4", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_schemas_bx_advance_py", "target": "app_schemas_bx_common", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/bx/advance.py", "source_location": "L6", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_schemas_bx_advance_py", "target": "bx_advance_coerce_optional_id", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/bx/advance.py", "source_location": "L9", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_schemas_bx_advance_py", "target": "bx_advance_advanceapplycreate", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/bx/advance.py", "source_location": "L16", "weight": 1.0}, {"source": "bx_advance_advanceapplycreate", "target": "basemodel", "relation": "inherits", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/bx/advance.py", "source_location": "L16", "weight": 1.0}, {"source": "bx_advance_advanceapplycreate", "target": "bx_advance_advanceapplycreate_validate_expense_item_id", "relation": "method", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/bx/advance.py", "source_location": "L27", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_schemas_bx_advance_Line truncated
|
||||
backend/graphify-out/cache/ast/0448e5ccd69b876402d03bb69647207497aef22b24f8686784bea2266c636607.json
Vendored
+1
@@ -0,0 +1 @@
|
||||
{"nodes": [{"id": "users_zlwu_work_00code_shanxia2_0_backend_app_api_bx_advance_py", "label": "advance.py", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/advance.py", "source_location": "L1"}, {"id": "bx_advance_tenant", "label": "_tenant()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/advance.py", "source_location": "L29"}, {"id": "session", "label": "Session", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/advance.py", "source_location": "L29"}, {"id": "bxusercontext", "label": "BxUserContext", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/advance.py", "source_location": "L29"}, {"id": "str", "label": "str", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/advance.py", "source_location": "L29"}, {"id": "bx_advance_fill_offset_amounts", "label": "_fill_offset_amounts()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/advance.py", "source_location": "L33"}, {"id": "advanceapplyout", "label": "AdvanceApplyOut", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/advance.py", "source_location": "L33"}, {"id": "bx_advance_list_advances", "label": "list_advances()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/advance.py", "source_location": "L42"}, {"id": "int", "label": "int", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/advance.py", "source_location": "L42"}, {"id": "bx_advance_my_advances", "label": "my_advances()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/advance.py", "source_location": "L77"}, {"id": "bx_advance_my_advance_stats", "label": "my_advance_stats()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/advance.py", "source_location": "L114"}, {"id": "bx_advance_advance_status_counts", "label": "advance_status_counts()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/advance.py", "source_location": "L124"}, {"id": "bx_advance_pending_approval", "label": "pending_approval()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/advance.py", "source_location": "L133"}, {"id": "bx_advance_advance_pending_approval_stats", "label": "advance_pending_approval_stats()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/advance.py", "source_location": "L159"}, {"id": "bx_advance_approved_by_me", "label": "approved_by_me()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/advance.py", "source_location": "L169"}, {"id": "bx_advance_get_advance", "label": "get_advance()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/advance.py", "source_location": "L195"}, {"id": "bx_advance_get_approvals", "label": "get_approvals()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/advance.py", "source_location": "L211"}, {"id": "bx_advance_get_approval_history", "label": "get_approval_history()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/advance.py", "source_location": "L224"}, {"id": "bx_advance_create_advance", "label": "create_advance()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/advance.py", "source_location": "L237"}, {"id": "advanceapplycreate", "label": "AdvanceApplyCreate", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/advance.py", "source_location": "L237"}, {"id": "bx_advance_update_advance", "label": "update_advance()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/advance.py", "source_location": "L270"}, {"id": "advanceapplyupdate", "label": "AdvanceApplyUpdate", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/advance.py", "source_location": "L270"}, {"id": "bx_advance_submit_advance", "label": "submit_advance()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/advance.py", "source_location": "L291"}, {"id": "bx_advance_approve_advance", "label": "approve_advance()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/advance.py", "source_location": "L305"}, {"id": "advanceapprovalcreate", "label": "AdvanceApprovalCreate", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/advance.py", "source_location": "L305"}, {"id": "bx_advance_reject_advance", "label": "reject_advance()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/Line truncated
|
||||
backend/graphify-out/cache/ast/07c3422f745afbff1c8162b3782fbb4b8de65084e7e9bbcf45abb9d433d65f98.json
Vendored
+1
@@ -0,0 +1 @@
|
||||
{"nodes": [{"id": "users_zlwu_work_00code_shanxia2_0_backend_app_schemas_bx_init_py", "label": "__init__.py", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/bx/__init__.py", "source_location": "L1"}, {"id": "bx_init_rationale_1", "label": "\u62a5\u9500\uff08bx\uff09Pydantic \u6a21\u578b \u2014 \u54cd\u5e94\u534f\u8bae\u4e0e bx \u539f\u7cfb\u7edf\u4fdd\u6301\u4e00\u81f4", "file_type": "rationale", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/bx/__init__.py", "source_location": "L1"}], "edges": [{"source": "bx_init_rationale_1", "target": "users_zlwu_work_00code_shanxia2_0_backend_app_schemas_bx_init_py", "relation": "rationale_for", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/bx/__init__.py", "source_location": "L1", "weight": 1.0}], "raw_calls": []}
|
||||
backend/graphify-out/cache/ast/0e08cd5582c49d14cac98dbaa4e719056d971f223c0cb9c694d1fa7d151b3e56.json
Vendored
+1
@@ -0,0 +1 @@
|
||||
{"nodes": [{"id": "users_zlwu_work_00code_shanxia2_0_backend_app_api_bx_reimburse_py", "label": "reimburse.py", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/reimburse.py", "source_location": "L1"}, {"id": "bx_reimburse_tenant", "label": "_tenant()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/reimburse.py", "source_location": "L29"}, {"id": "session", "label": "Session", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/reimburse.py", "source_location": "L29"}, {"id": "bxusercontext", "label": "BxUserContext", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/reimburse.py", "source_location": "L29"}, {"id": "str", "label": "str", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/reimburse.py", "source_location": "L29"}, {"id": "bx_reimburse_build_details_data", "label": "_build_details_data()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/reimburse.py", "source_location": "L33"}, {"id": "bx_reimburse_get_generated_title", "label": "get_generated_title()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/reimburse.py", "source_location": "L54"}, {"id": "bx_reimburse_list_reimburses", "label": "list_reimburses()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/reimburse.py", "source_location": "L64"}, {"id": "int", "label": "int", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/reimburse.py", "source_location": "L64"}, {"id": "bx_reimburse_my_reimburses", "label": "my_reimburses()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/reimburse.py", "source_location": "L101"}, {"id": "bx_reimburse_my_reimburse_stats", "label": "my_reimburse_stats()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/reimburse.py", "source_location": "L132"}, {"id": "bx_reimburse_reimburse_status_counts", "label": "reimburse_status_counts()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/reimburse.py", "source_location": "L142"}, {"id": "bx_reimburse_pending_approval", "label": "pending_approval()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/reimburse.py", "source_location": "L151"}, {"id": "bx_reimburse_pending_approval_stats", "label": "pending_approval_stats()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/reimburse.py", "source_location": "L177"}, {"id": "bx_reimburse_approved_by_me", "label": "approved_by_me()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/reimburse.py", "source_location": "L187"}, {"id": "bx_reimburse_get_reimburse", "label": "get_reimburse()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/reimburse.py", "source_location": "L213"}, {"id": "bx_reimburse_get_approvals", "label": "get_approvals()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/reimburse.py", "source_location": "L227"}, {"id": "bx_reimburse_get_approval_history", "label": "get_approval_history()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/reimburse.py", "source_location": "L240"}, {"id": "bx_reimburse_create_reimburse", "label": "create_reimburse()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/reimburse.py", "source_location": "L253"}, {"id": "reimburseapplycreate", "label": "ReimburseApplyCreate", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/reimburse.py", "source_location": "L253"}, {"id": "bx_reimburse_update_reimburse", "label": "update_reimburse()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/reimburse.py", "source_location": "L286"}, {"id": "reimburseapplyupdate", "label": "ReimburseApplyUpdate", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/reimburse.py", "source_location": "L286"}, {"id": "bx_reimburse_submit_reimburse", "label": "submit_reimburse()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/reimburse.py", "source_location": "L311"}, {"id": "bx_reimburse_approve_reimburse", "label": "approve_reimburse()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/reimburse.py", "source_location": "L326"}, {"id": "reimburseapprovalcreate", "label": "ReimburseApprovalCreate", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/reimburse.py", "source_locatiLine truncated
|
||||
backend/graphify-out/cache/ast/10ac1660a2a6d6daa4c313f57667df78b082c742e49780cec4270b1333b3cb1f.json
Vendored
+1
@@ -0,0 +1 @@
|
||||
{"nodes": [{"id": "users_zlwu_work_00code_shanxia2_0_backend_app_services_bx_workflow_py", "label": "workflow.py", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/workflow.py", "source_location": "L1"}, {"id": "bx_workflow_workflowservice", "label": "WorkflowService", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/workflow.py", "source_location": "L26"}, {"id": "bx_workflow_workflowservice_tenant_no", "label": "._tenant_no()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/workflow.py", "source_location": "L28"}, {"id": "session", "label": "Session", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/workflow.py", "source_location": "L28"}, {"id": "bxusercontext", "label": "BxUserContext", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/workflow.py", "source_location": "L28"}, {"id": "str", "label": "str", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/workflow.py", "source_location": "L28"}, {"id": "bx_workflow_workflowservice_get_by_id", "label": ".get_by_id()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/workflow.py", "source_location": "L32"}, {"id": "bxworkflowdef", "label": "BxWorkflowDef", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/workflow.py", "source_location": "L32"}, {"id": "bx_workflow_workflowservice_get_paged", "label": ".get_paged()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/workflow.py", "source_location": "L36"}, {"id": "int", "label": "int", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/workflow.py", "source_location": "L36"}, {"id": "bx_workflow_workflowservice_create", "label": ".create()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/workflow.py", "source_location": "L45"}, {"id": "bx_workflow_workflowservice_update", "label": ".update()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/workflow.py", "source_location": "L62"}, {"id": "bx_workflow_workflowservice_soft_delete", "label": ".soft_delete()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/workflow.py", "source_location": "L80"}, {"id": "bool", "label": "bool", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/workflow.py", "source_location": "L80"}, {"id": "bx_workflow_workflowservice_get_by_biz_type", "label": ".get_by_biz_type()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/workflow.py", "source_location": "L94"}, {"id": "bx_workflow_workflowservice_ensure_by_biz_type", "label": ".ensure_by_biz_type()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/workflow.py", "source_location": "L106"}, {"id": "bx_workflow_workflowservice_save_nodes", "label": ".save_nodes()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/workflow.py", "source_location": "L137"}, {"id": "bxworkflownode", "label": "BxWorkflowNode", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/workflow.py", "source_location": "L137"}, {"id": "bx_workflow_rationale_112", "label": "\u6309\u4e1a\u52a1\u7c7b\u578b\u83b7\u53d6\u5de5\u4f5c\u6d41\uff1b\u5df2\u77e5\u7c7b\u578b\u4e0d\u5b58\u5728\u65f6\u81ea\u52a8\u521b\u5efa\u7a7a\u5b9a\u4e49\uff08\u65e0\u8282\u70b9\uff09\u3002", "file_type": "rationale", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/workflow.py", "source_location": "L112"}], "edges": [{"source": "users_zlwu_work_00code_shanxia2_0_backend_app_services_bx_workflow_py", "target": "typing", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/workflow.py", "source_location": "L3", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_services_bx_workflow_py", "target": "sqlalchemy_orm", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/workflow.py", "source_location": "L5", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_services_bx_workflow_py", "target": "app_core_bx_auth", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/workflow.py", "source_location": "L7", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2Line truncated
|
||||
backend/graphify-out/cache/ast/1945115e6d9b96e3bcefc80950de87460edb2b89ee4f777c10715d5f4d2cf213.json
Vendored
+1
@@ -0,0 +1 @@
|
||||
{"nodes": [{"id": "users_zlwu_work_00code_shanxia2_0_backend_app_schemas_bx_advance_py", "label": "advance.py", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/bx/advance.py", "source_location": "L1"}, {"id": "bx_advance_coerce_optional_id", "label": "_coerce_optional_id()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/bx/advance.py", "source_location": "L9"}, {"id": "bx_advance_advanceapplycreate", "label": "AdvanceApplyCreate", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/bx/advance.py", "source_location": "L16"}, {"id": "basemodel", "label": "BaseModel", "file_type": "code", "source_file": "", "source_location": ""}, {"id": "bx_advance_advanceapplycreate_validate_expense_item_id", "label": ".validate_expense_item_id()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/bx/advance.py", "source_location": "L27"}, {"id": "bx_advance_advanceapplyupdate", "label": "AdvanceApplyUpdate", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/bx/advance.py", "source_location": "L31"}, {"id": "bx_advance_advanceapplyupdate_validate_expense_item_id", "label": ".validate_expense_item_id()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/bx/advance.py", "source_location": "L42"}, {"id": "bx_advance_advanceapplyout", "label": "AdvanceApplyOut", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/bx/advance.py", "source_location": "L46"}, {"id": "bx_advance_advanceapprovalcreate", "label": "AdvanceApprovalCreate", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/bx/advance.py", "source_location": "L69"}, {"id": "bx_advance_advanceapprovalout", "label": "AdvanceApprovalOut", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/bx/advance.py", "source_location": "L76"}, {"id": "bx_advance_advancemystatsout", "label": "AdvanceMyStatsOut", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/bx/advance.py", "source_location": "L89"}, {"id": "bx_advance_advanceapproverpendingstatsout", "label": "AdvanceApproverPendingStatsOut", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/bx/advance.py", "source_location": "L104"}, {"id": "bx_advance_advanceissueout", "label": "AdvanceIssueOut", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/bx/advance.py", "source_location": "L111"}, {"id": "bx_advance_advanceissuerequest", "label": "AdvanceIssueRequest", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/bx/advance.py", "source_location": "L129"}, {"id": "bx_advance_advanceoffsetrecordout", "label": "AdvanceOffsetRecordOut", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/bx/advance.py", "source_location": "L136"}, {"id": "bx_advance_advancefinanceissuestatsout", "label": "AdvanceFinanceIssueStatsOut", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/bx/advance.py", "source_location": "L149"}], "edges": [{"source": "users_zlwu_work_00code_shanxia2_0_backend_app_schemas_bx_advance_py", "target": "typing", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/bx/advance.py", "source_location": "L1", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_schemas_bx_advance_py", "target": "pydantic", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/bx/advance.py", "source_location": "L3", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_schemas_bx_advance_py", "target": "pydantic_alias_generators", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/bx/advance.py", "source_location": "L4", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_schemas_bx_advance_py", "target": "app_schemas_bx_common", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/bx/advance.py", "source_location": "L6", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_schemas_bx_advance_py", "target": "bx_advance_coerce_optional_id", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/bx/advance.py", "source_location": "L9", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_schemas_bx_Line truncated
|
||||
backend/graphify-out/cache/ast/1b8a1b82dcabdcb1a2957ac9c53d2ae128869a55439c77208ec3b0342380eeed.json
Vendored
+1
@@ -0,0 +1 @@
|
||||
{"nodes": [{"id": "users_zlwu_work_00code_shanxia2_0_backend_app_schemas_bx_common_py", "label": "common.py", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/bx/common.py", "source_location": "L1"}, {"id": "bx_common_dt_to_str", "label": "_dt_to_str()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/bx/common.py", "source_location": "L11"}, {"id": "datetime", "label": "datetime", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/bx/common.py", "source_location": "L11"}, {"id": "str", "label": "str", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/bx/common.py", "source_location": "L11"}, {"id": "bx_common_pagedquery", "label": "PagedQuery", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/bx/common.py", "source_location": "L21"}, {"id": "basemodel", "label": "BaseModel", "file_type": "code", "source_file": "", "source_location": ""}, {"id": "bx_common_apiresponse", "label": "ApiResponse", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/bx/common.py", "source_location": "L28"}, {"id": "bx_common_pageddata", "label": "PagedData", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/bx/common.py", "source_location": "L34"}, {"id": "bx_common_pagedresponse", "label": "PagedResponse", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/bx/common.py", "source_location": "L43"}, {"id": "bx_common_rationale_1", "label": "bx \u539f\u7cfb\u7edf API \u54cd\u5e94\u5305\u88c5\uff08code=0 / msg / data.rows\uff09\uff0c\u4e0e\u95e8\u6237 success_response \u5206\u79bb\u3002", "file_type": "rationale", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/bx/common.py", "source_location": "L1"}], "edges": [{"source": "users_zlwu_work_00code_shanxia2_0_backend_app_schemas_bx_common_py", "target": "datetime", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/bx/common.py", "source_location": "L2", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_schemas_bx_common_py", "target": "typing", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/bx/common.py", "source_location": "L3", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_schemas_bx_common_py", "target": "pydantic", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/bx/common.py", "source_location": "L5", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_schemas_bx_common_py", "target": "pydantic_alias_generators", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/bx/common.py", "source_location": "L6", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_schemas_bx_common_py", "target": "bx_common_dt_to_str", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/bx/common.py", "source_location": "L11", "weight": 1.0}, {"source": "bx_common_dt_to_str", "target": "datetime", "relation": "references", "context": "generic_arg", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/bx/common.py", "source_location": "L11", "weight": 1.0}, {"source": "bx_common_dt_to_str", "target": "str", "relation": "references", "context": "generic_arg", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/bx/common.py", "source_location": "L11", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_schemas_bx_common_py", "target": "bx_common_pagedquery", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/bx/common.py", "source_location": "L21", "weight": 1.0}, {"source": "bx_common_pagedquery", "target": "basemodel", "relation": "inherits", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/bx/common.py", "source_location": "L21", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_schemas_bx_common_py", "target": "bx_common_apiresponse", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/bx/common.py", "source_location": "L28", "weight": 1.0}, {"source": "bx_common_apiresponse", "target": "basemodel", "relation": "inherits", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00cLine truncated
|
||||
backend/graphify-out/cache/ast/1f1628e708c7779fa17dcb70b985815c363eb97fae2df1c82fdd685410690266.json
Vendored
+1
@@ -0,0 +1 @@
|
||||
{"nodes": [{"id": "users_zlwu_work_00code_shanxia2_0_backend_app_services_bx_advance_py", "label": "advance.py", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/advance.py", "source_location": "L1"}, {"id": "bx_advance_advanceservice", "label": "AdvanceService", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/advance.py", "source_location": "L25"}, {"id": "bx_advance_advanceservice_tenant_no", "label": "._tenant_no()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/advance.py", "source_location": "L27"}, {"id": "session", "label": "Session", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/advance.py", "source_location": "L27"}, {"id": "bxusercontext", "label": "BxUserContext", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/advance.py", "source_location": "L27"}, {"id": "str", "label": "str", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/advance.py", "source_location": "L27"}, {"id": "bx_advance_advanceservice_get_by_id", "label": ".get_by_id()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/advance.py", "source_location": "L31"}, {"id": "bxadvanceapply", "label": "BxAdvanceApply", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/advance.py", "source_location": "L31"}, {"id": "bx_advance_advanceservice_get_paged", "label": ".get_paged()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/advance.py", "source_location": "L35"}, {"id": "int", "label": "int", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/advance.py", "source_location": "L35"}, {"id": "any", "label": "Any", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/advance.py", "source_location": "L35"}, {"id": "bx_advance_advanceservice_create", "label": ".create()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/advance.py", "source_location": "L45"}, {"id": "bx_advance_advanceservice_update", "label": ".update()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/advance.py", "source_location": "L62"}, {"id": "bx_advance_advanceservice_soft_delete", "label": ".soft_delete()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/advance.py", "source_location": "L80"}, {"id": "bool", "label": "bool", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/advance.py", "source_location": "L80"}, {"id": "bx_advance_advanceservice_pending_approval", "label": ".pending_approval()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/advance.py", "source_location": "L87"}, {"id": "bx_advance_advanceservice_approved_by_me", "label": ".approved_by_me()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/advance.py", "source_location": "L143"}, {"id": "bx_advance_advanceservice_workflow_nodes", "label": "._workflow_nodes()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/advance.py", "source_location": "L191"}, {"id": "bxworkflownode", "label": "BxWorkflowNode", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/advance.py", "source_location": "L191"}, {"id": "bx_advance_advanceservice_submit", "label": ".submit()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/advance.py", "source_location": "L204"}, {"id": "bx_advance_advanceservice_approve", "label": ".approve()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/advance.py", "source_location": "L221"}, {"id": "bx_advance_advanceservice_reject", "label": ".reject()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/advance.py", "source_location": "L266"}, {"id": "bx_advance_advanceservice_approval_record_dict", "label": "._approval_record_dict()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/advance.py", "source_location": "L303"}, {"id": "bxadvanceapproval", "label": "BxAdvanceApproval", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/advance.py", "source_location": "L303"}, {"id": "bx_advance_advanceservice_latest_approval_per_node", "label": "._latest_approval_per_node()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/advance.py", "source_locLine truncated
|
||||
backend/graphify-out/cache/ast/2119cf43e553690f3e5a9d62870c025b01be03bd9e68711efe8b11fc975ea4b7.json
Vendored
+1
@@ -0,0 +1 @@
|
||||
{"nodes": [{"id": "users_zlwu_work_00code_shanxia2_0_backend_app_api_bx_init_py", "label": "__init__.py", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/__init__.py", "source_location": "L1"}, {"id": "bx_init_bx_health", "label": "bx_health()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/__init__.py", "source_location": "L10"}, {"id": "bx_init_rationale_1", "label": "\u62a5\u9500\uff08bx\uff09API \u8def\u7531\u805a\u5408 \u2014 REST \u98ce\u683c\uff0c\u534f\u8bae\u5bf9\u9f50 bx \u539f\u7cfb\u7edf\u3002", "file_type": "rationale", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/__init__.py", "source_location": "L1"}, {"id": "bx_init_rationale_11", "label": "P0 \u5065\u5eb7\u68c0\u67e5\uff1a\u9a8c\u8bc1 bx \u8def\u7531\u5df2\u6302\u8f7d\u4e14\u54cd\u5e94\u534f\u8bae\u4e3a code=0\u3002", "file_type": "rationale", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/__init__.py", "source_location": "L11"}], "edges": [{"source": "users_zlwu_work_00code_shanxia2_0_backend_app_api_bx_init_py", "target": "fastapi", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/__init__.py", "source_location": "L2", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_api_bx_init_py", "target": "app_schemas_bx_common", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/__init__.py", "source_location": "L4", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_api_bx_init_py", "target": "bx_init_bx_health", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/__init__.py", "source_location": "L10", "weight": 1.0}, {"source": "bx_init_rationale_1", "target": "users_zlwu_work_00code_shanxia2_0_backend_app_api_bx_init_py", "relation": "rationale_for", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/__init__.py", "source_location": "L1", "weight": 1.0}, {"source": "bx_init_rationale_11", "target": "bx_init_bx_health", "relation": "rationale_for", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/__init__.py", "source_location": "L11", "weight": 1.0}], "raw_calls": [{"caller_nid": "bx_init_bx_health", "callee": "ApiResponse", "is_member_call": false, "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/__init__.py", "source_location": "L12"}]}
|
||||
backend/graphify-out/cache/ast/284030ccb6a38b6753a4ad8fe1a79bfd6e82feb3ac9731e55a17c197686e7ae5.json
Vendored
+1
@@ -0,0 +1 @@
|
||||
{"nodes": [{"id": "users_zlwu_work_00code_shanxia2_0_backend_app_api_bx_init_py", "label": "__init__.py", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/__init__.py", "source_location": "L1"}, {"id": "bx_init_bx_health", "label": "bx_health()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/__init__.py", "source_location": "L13"}, {"id": "bx_init_rationale_1", "label": "\u62a5\u9500\uff08bx\uff09API \u8def\u7531\u805a\u5408 \u2014 REST \u98ce\u683c\uff0c\u534f\u8bae\u5bf9\u9f50 bx \u539f\u7cfb\u7edf\u3002", "file_type": "rationale", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/__init__.py", "source_location": "L1"}, {"id": "bx_init_rationale_14", "label": "P0 \u5065\u5eb7\u68c0\u67e5\uff1a\u9a8c\u8bc1 bx \u8def\u7531\u5df2\u6302\u8f7d\u4e14\u54cd\u5e94\u534f\u8bae\u4e3a code=0\u3002", "file_type": "rationale", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/__init__.py", "source_location": "L14"}], "edges": [{"source": "users_zlwu_work_00code_shanxia2_0_backend_app_api_bx_init_py", "target": "fastapi", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/__init__.py", "source_location": "L2", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_api_bx_init_py", "target": "app_api_bx", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/__init__.py", "source_location": "L4", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_api_bx_init_py", "target": "app_schemas_bx_common", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/__init__.py", "source_location": "L5", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_api_bx_init_py", "target": "bx_init_bx_health", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/__init__.py", "source_location": "L13", "weight": 1.0}, {"source": "bx_init_rationale_1", "target": "users_zlwu_work_00code_shanxia2_0_backend_app_api_bx_init_py", "relation": "rationale_for", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/__init__.py", "source_location": "L1", "weight": 1.0}, {"source": "bx_init_rationale_14", "target": "bx_init_bx_health", "relation": "rationale_for", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/__init__.py", "source_location": "L14", "weight": 1.0}], "raw_calls": [{"caller_nid": "bx_init_bx_health", "callee": "ApiResponse", "is_member_call": false, "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/__init__.py", "source_location": "L15"}]}
|
||||
backend/graphify-out/cache/ast/2bbe961ad71f0be530f10d515b69615dbf887257028e339d4252b9ff2a5aba2b.json
Vendored
+1
@@ -0,0 +1 @@
|
||||
{"nodes": [{"id": "users_zlwu_work_00code_shanxia2_0_backend_app_utils_bx_date_range_py", "label": "bx_date_range.py", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/utils/bx_date_range.py", "source_location": "L1"}, {"id": "utils_bx_date_range_current_month_bounds", "label": "current_month_bounds()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/utils/bx_date_range.py", "source_location": "L7"}, {"id": "datetime", "label": "datetime", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/utils/bx_date_range.py", "source_location": "L7"}, {"id": "utils_bx_date_range_parse_create_time_day_bounds", "label": "parse_create_time_day_bounds()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/utils/bx_date_range.py", "source_location": "L19"}, {"id": "str", "label": "str", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/utils/bx_date_range.py", "source_location": "L19"}, {"id": "utils_bx_date_range_rationale_1", "label": "\u62a5\u9500\u6a21\u5757\u65e5\u671f\u8303\u56f4\u5de5\u5177\uff08\u4ece bx-backend \u8fc1\u79fb\uff09\u3002", "file_type": "rationale", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/utils/bx_date_range.py", "source_location": "L1"}, {"id": "utils_bx_date_range_rationale_8", "label": "\u5f53\u524d\u81ea\u7136\u6708 [month_start, next_month_start)\u3002", "file_type": "rationale", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/utils/bx_date_range.py", "source_location": "L8"}], "edges": [{"source": "users_zlwu_work_00code_shanxia2_0_backend_app_utils_bx_date_range_py", "target": "datetime", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/utils/bx_date_range.py", "source_location": "L4", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_utils_bx_date_range_py", "target": "utils_bx_date_range_current_month_bounds", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/utils/bx_date_range.py", "source_location": "L7", "weight": 1.0}, {"source": "utils_bx_date_range_current_month_bounds", "target": "datetime", "relation": "references", "context": "parameter_type", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/utils/bx_date_range.py", "source_location": "L7", "weight": 1.0}, {"source": "utils_bx_date_range_current_month_bounds", "target": "datetime", "relation": "references", "context": "generic_arg", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/utils/bx_date_range.py", "source_location": "L7", "weight": 1.0}, {"source": "utils_bx_date_range_current_month_bounds", "target": "datetime", "relation": "references", "context": "generic_arg", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/utils/bx_date_range.py", "source_location": "L7", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_utils_bx_date_range_py", "target": "utils_bx_date_range_parse_create_time_day_bounds", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/utils/bx_date_range.py", "source_location": "L19", "weight": 1.0}, {"source": "utils_bx_date_range_parse_create_time_day_bounds", "target": "str", "relation": "references", "context": "parameter_type", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/utils/bx_date_range.py", "source_location": "L19", "weight": 1.0}, {"source": "utils_bx_date_range_parse_create_time_day_bounds", "target": "datetime", "relation": "references", "context": "generic_arg", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/utils/bx_date_range.py", "source_location": "L19", "weight": 1.0}, {"source": "utils_bx_date_range_parse_create_time_day_bounds", "target": "datetime", "relation": "references", "context": "generic_arg", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/utils/bx_date_range.py", "source_location": "L19", "weight": 1.0}, {"source": "utils_bx_date_range_current_month_bounds", "target": "datetime", "relation": "calls", "context": "call", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/utils/bx_date_range.py", "source_location": "L13", "weight": 1.0}, {"source": "utils_bx_date_range_rationale_1", "target": "users_zlwu_work_00code_shanxia2_0_backend_app_utils_bx_date_range_py", "relation": "rationale_for", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/utils/bx_date_range.py", "source_location": "L1", "weight": 1.0}, {"source": "utils_bx_date_range_rationale_8", "target": "utils_bx_date_range_current_monthLine truncated
|
||||
backend/graphify-out/cache/ast/308c087d94ac253bfc7e2d5455a06ae8ceac034adda41b5c61dd315dc167efaf.json
Vendored
+1
@@ -0,0 +1 @@
|
||||
{"nodes": [{"id": "users_zlwu_work_00code_shanxia2_0_backend_app_services_bx_approval_cycle_py", "label": "approval_cycle.py", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/approval_cycle.py", "source_location": "L1"}, {"id": "bx_approval_cycle_filter_current_cycle_approvals", "label": "filter_current_cycle_approvals()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/approval_cycle.py", "source_location": "L10"}, {"id": "t", "label": "T", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/approval_cycle.py", "source_location": "L10"}, {"id": "str", "label": "str", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/approval_cycle.py", "source_location": "L10"}, {"id": "bx_approval_cycle_rationale_1", "label": "\u5ba1\u6279\u8f6e\u6b21\u8fc7\u6ee4 \u2014 \u9a73\u56de\u540e\u91cd\u65b0\u63d0\u4ea4\u65f6\uff0c\u8fdb\u5ea6\u63a5\u53e3\u4ec5\u5c55\u793a\u5f53\u524d\u8f6e\u6b21\u3002", "file_type": "rationale", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/approval_cycle.py", "source_location": "L1"}, {"id": "bx_approval_cycle_rationale_17", "label": "\u5ba1\u6279\u8fdb\u5ea6\u4ec5\u5c55\u793a\u5f53\u524d\u8f6e\u6b21\uff1b\u5b8c\u6574\u5386\u53f2\u7531 get_approval_history \u8fd4\u56de\u3002", "file_type": "rationale", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/approval_cycle.py", "source_location": "L17"}], "edges": [{"source": "users_zlwu_work_00code_shanxia2_0_backend_app_services_bx_approval_cycle_py", "target": "datetime", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/approval_cycle.py", "source_location": "L4", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_services_bx_approval_cycle_py", "target": "typing", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/approval_cycle.py", "source_location": "L5", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_services_bx_approval_cycle_py", "target": "bx_approval_cycle_filter_current_cycle_approvals", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/approval_cycle.py", "source_location": "L10", "weight": 1.0}, {"source": "bx_approval_cycle_filter_current_cycle_approvals", "target": "t", "relation": "references", "context": "generic_arg", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/approval_cycle.py", "source_location": "L10", "weight": 1.0}, {"source": "bx_approval_cycle_filter_current_cycle_approvals", "target": "str", "relation": "references", "context": "parameter_type", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/approval_cycle.py", "source_location": "L10", "weight": 1.0}, {"source": "bx_approval_cycle_filter_current_cycle_approvals", "target": "str", "relation": "references", "context": "parameter_type", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/approval_cycle.py", "source_location": "L10", "weight": 1.0}, {"source": "bx_approval_cycle_filter_current_cycle_approvals", "target": "str", "relation": "references", "context": "parameter_type", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/approval_cycle.py", "source_location": "L10", "weight": 1.0}, {"source": "bx_approval_cycle_filter_current_cycle_approvals", "target": "t", "relation": "references", "context": "generic_arg", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/approval_cycle.py", "source_location": "L10", "weight": 1.0}, {"source": "bx_approval_cycle_rationale_1", "target": "users_zlwu_work_00code_shanxia2_0_backend_app_services_bx_approval_cycle_py", "relation": "rationale_for", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/approval_cycle.py", "source_location": "L1", "weight": 1.0}, {"source": "bx_approval_cycle_rationale_17", "target": "bx_approval_cycle_filter_current_cycle_approvals", "relation": "rationale_for", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/approval_cycle.py", "source_location": "L17", "weight": 1.0}], "raw_calls": []}
|
||||
backend/graphify-out/cache/ast/3525eb716c238682a07a116818d318b8a494fb24b9cefca5114d30bc50d095a5.json
Vendored
+1
@@ -0,0 +1 @@
|
||||
{"nodes": [{"id": "users_zlwu_work_00code_shanxia2_0_backend_app_api_bx_init_py", "label": "__init__.py", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/__init__.py", "source_location": "L1"}, {"id": "bx_init_bx_health", "label": "bx_health()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/__init__.py", "source_location": "L17"}, {"id": "bx_init_rationale_1", "label": "\u62a5\u9500\uff08bx\uff09API \u8def\u7531\u805a\u5408 \u2014 REST \u98ce\u683c\uff0c\u534f\u8bae\u5bf9\u9f50 bx \u539f\u7cfb\u7edf\u3002", "file_type": "rationale", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/__init__.py", "source_location": "L1"}, {"id": "bx_init_rationale_18", "label": "P0 \u5065\u5eb7\u68c0\u67e5\uff1a\u9a8c\u8bc1 bx \u8def\u7531\u5df2\u6302\u8f7d\u4e14\u54cd\u5e94\u534f\u8bae\u4e3a code=0\u3002", "file_type": "rationale", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/__init__.py", "source_location": "L18"}], "edges": [{"source": "users_zlwu_work_00code_shanxia2_0_backend_app_api_bx_init_py", "target": "fastapi", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/__init__.py", "source_location": "L2", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_api_bx_init_py", "target": "app_api_bx", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/__init__.py", "source_location": "L4", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_api_bx_init_py", "target": "app_schemas_bx_common", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/__init__.py", "source_location": "L5", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_api_bx_init_py", "target": "bx_init_bx_health", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/__init__.py", "source_location": "L17", "weight": 1.0}, {"source": "bx_init_rationale_1", "target": "users_zlwu_work_00code_shanxia2_0_backend_app_api_bx_init_py", "relation": "rationale_for", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/__init__.py", "source_location": "L1", "weight": 1.0}, {"source": "bx_init_rationale_18", "target": "bx_init_bx_health", "relation": "rationale_for", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/__init__.py", "source_location": "L18", "weight": 1.0}], "raw_calls": [{"caller_nid": "bx_init_bx_health", "callee": "ApiResponse", "is_member_call": false, "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/__init__.py", "source_location": "L19"}]}
|
||||
backend/graphify-out/cache/ast/3850bc36779f8ea27c7e43155735c7b0eeec5d0b543938bcf92d18cd6bc64763.json
Vendored
+1
@@ -0,0 +1 @@
|
||||
{"nodes": [{"id": "users_zlwu_work_00code_shanxia2_0_backend_app_services_bx_reimburse_py", "label": "reimburse.py", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/reimburse.py", "source_location": "L1"}, {"id": "bx_reimburse_reimburseservice", "label": "ReimburseService", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/reimburse.py", "source_location": "L30"}, {"id": "bx_reimburse_reimburseservice_tenant_no", "label": "._tenant_no()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/reimburse.py", "source_location": "L32"}, {"id": "session", "label": "Session", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/reimburse.py", "source_location": "L32"}, {"id": "bxusercontext", "label": "BxUserContext", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/reimburse.py", "source_location": "L32"}, {"id": "str", "label": "str", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/reimburse.py", "source_location": "L32"}, {"id": "bx_reimburse_reimburseservice_get_by_id", "label": ".get_by_id()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/reimburse.py", "source_location": "L36"}, {"id": "bxreimburseapply", "label": "BxReimburseApply", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/reimburse.py", "source_location": "L36"}, {"id": "bx_reimburse_reimburseservice_get_paged", "label": ".get_paged()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/reimburse.py", "source_location": "L40"}, {"id": "int", "label": "int", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/reimburse.py", "source_location": "L40"}, {"id": "any", "label": "Any", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/reimburse.py", "source_location": "L40"}, {"id": "bx_reimburse_reimburseservice_soft_delete", "label": ".soft_delete()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/reimburse.py", "source_location": "L50"}, {"id": "bool", "label": "bool", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/reimburse.py", "source_location": "L50"}, {"id": "bx_reimburse_reimburseservice_workflow_nodes", "label": "._workflow_nodes()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/reimburse.py", "source_location": "L57"}, {"id": "bxworkflownode", "label": "BxWorkflowNode", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/reimburse.py", "source_location": "L57"}, {"id": "bx_reimburse_reimburseservice_pending_approval", "label": ".pending_approval()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/reimburse.py", "source_location": "L70"}, {"id": "bx_reimburse_reimburseservice_approved_by_me", "label": ".approved_by_me()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/reimburse.py", "source_location": "L126"}, {"id": "bx_reimburse_reimburseservice_submit", "label": ".submit()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/reimburse.py", "source_location": "L174"}, {"id": "bx_reimburse_reimburseservice_approve", "label": ".approve()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/reimburse.py", "source_location": "L191"}, {"id": "bx_reimburse_reimburseservice_reject", "label": ".reject()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/reimburse.py", "source_location": "L236"}, {"id": "bx_reimburse_reimburseservice_get_approvals", "label": ".get_approvals()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/reimburse.py", "source_location": "L273"}, {"id": "bx_reimburse_reimburseservice_create_with_details", "label": ".create_with_details()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/reimburse.py", "source_location": "L325"}, {"id": "bx_reimburse_reimburseservice_update_with_details", "label": ".update_with_details()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/reimburse.py", "source_location": "L371"}, {"id": "bx_reimburse_reimburseservice_get_details", "label": ".get_details()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/reimburse.py", "source_location": "L424"}, {"id": "bxreimbursedetail", "label": "BxReimburseDLine truncated
|
||||
backend/graphify-out/cache/ast/38eb2cb16c0b187b946287ad8d6e0a2b5d008798cf3e99914ce29a6a3b3ab2ce.json
Vendored
+1
@@ -0,0 +1 @@
|
||||
{"nodes": [{"id": "users_zlwu_work_00code_shanxia2_0_backend_app_core_bx_auth_py", "label": "bx_auth.py", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/core/bx_auth.py", "source_location": "L1"}, {"id": "core_bx_auth_bxusercontext", "label": "BxUserContext", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/core/bx_auth.py", "source_location": "L13"}, {"id": "core_bx_auth_bxusercontext_to_tenant_user_dict", "label": ".to_tenant_user_dict()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/core/bx_auth.py", "source_location": "L22"}, {"id": "str", "label": "str", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/core/bx_auth.py", "source_location": "L22"}, {"id": "any", "label": "Any", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/core/bx_auth.py", "source_location": "L22"}, {"id": "core_bx_auth_get_bx_current_user", "label": "get_bx_current_user()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/core/bx_auth.py", "source_location": "L31"}, {"id": "core_bx_auth_rationale_1", "label": "\u62a5\u9500\u6a21\u5757\u8ba4\u8bc1\u9002\u914d\uff1a\u95e8\u6237 JWT \u7528\u6237 \u2192 bx \u4e1a\u52a1\u4e0a\u4e0b\u6587\u3002", "file_type": "rationale", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/core/bx_auth.py", "source_location": "L1"}, {"id": "core_bx_auth_rationale_14", "label": "bx Service/Router \u4f7f\u7528\u7684\u5f53\u524d\u7528\u6237\u4e0a\u4e0b\u6587\uff08sys_user.id \u4e3a UUID \u5b57\u7b26\u4e32\uff09\u3002", "file_type": "rationale", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/core/bx_auth.py", "source_location": "L14"}, {"id": "core_bx_auth_rationale_23", "label": "\u4f9b get_tenant_no \u7b49\u95e8\u6237\u5de5\u5177\u4f7f\u7528\u3002", "file_type": "rationale", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/core/bx_auth.py", "source_location": "L23"}], "edges": [{"source": "users_zlwu_work_00code_shanxia2_0_backend_app_core_bx_auth_py", "target": "dataclasses", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/core/bx_auth.py", "source_location": "L4", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_core_bx_auth_py", "target": "typing", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/core/bx_auth.py", "source_location": "L5", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_core_bx_auth_py", "target": "fastapi", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/core/bx_auth.py", "source_location": "L7", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_core_bx_auth_py", "target": "app_core_menu_guard", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/core/bx_auth.py", "source_location": "L9", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_core_bx_auth_py", "target": "core_bx_auth_bxusercontext", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/core/bx_auth.py", "source_location": "L13", "weight": 1.0}, {"source": "core_bx_auth_bxusercontext", "target": "core_bx_auth_bxusercontext_to_tenant_user_dict", "relation": "method", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/core/bx_auth.py", "source_location": "L22", "weight": 1.0}, {"source": "core_bx_auth_bxusercontext_to_tenant_user_dict", "target": "str", "relation": "references", "context": "generic_arg", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/core/bx_auth.py", "source_location": "L22", "weight": 1.0}, {"source": "core_bx_auth_bxusercontext_to_tenant_user_dict", "target": "any", "relation": "references", "context": "generic_arg", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/core/bx_auth.py", "source_location": "L22", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_core_bx_auth_py", "target": "core_bx_auth_get_bx_current_user", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/core/bx_auth.py", "source_location": "L31", "weight": 1.0}, {"source": "core_bx_auth_get_bx_current_user", "target": "core_bx_auth_bxusercontext", "relation": "references", "context": "return_type", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/core/bx_auth.py", "source_location": "L31", "weight": 1.0}, {"source": "core_bx_auth_get_bLine truncated
|
||||
backend/graphify-out/cache/ast/3d3ad114f06247fcff5e1a5c0d9467f4ecd507b3729c29d3bdeb3421300cca01.json
Vendored
+1
@@ -0,0 +1 @@
|
||||
{"nodes": [{"id": "users_zlwu_work_00code_shanxia2_0_backend_app_api_init_py", "label": "__init__.py", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/__init__.py", "source_location": "L1"}, {"id": "api_init_rationale_1", "label": "API \u8def\u7531\u5305 \u2014 \u5c71\u5ce1\u5316\u5de5\u751f\u4ea7\u4e00\u4f53\u5316\u95e8\u6237", "file_type": "rationale", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/__init__.py", "source_location": "L1"}], "edges": [{"source": "users_zlwu_work_00code_shanxia2_0_backend_app_api_init_py", "target": "app_api_public", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/__init__.py", "source_location": "L2", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_api_init_py", "target": "app_api_menu", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/__init__.py", "source_location": "L3", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_api_init_py", "target": "app_api_admin", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/__init__.py", "source_location": "L4", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_api_init_py", "target": "app_api_workflow", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/__init__.py", "source_location": "L5", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_api_init_py", "target": "app_api_leave", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/__init__.py", "source_location": "L6", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_api_init_py", "target": "app_api_crm", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/__init__.py", "source_location": "L7", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_api_init_py", "target": "app_api_monitor", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/__init__.py", "source_location": "L8", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_api_init_py", "target": "app_api_bx", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/__init__.py", "source_location": "L9", "weight": 1.0}, {"source": "api_init_rationale_1", "target": "users_zlwu_work_00code_shanxia2_0_backend_app_api_init_py", "relation": "rationale_for", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/__init__.py", "source_location": "L1", "weight": 1.0}], "raw_calls": []}
|
||||
backend/graphify-out/cache/ast/3e3dd6accae52b25415f68195e456f37248447fa2230ce18851aa24b6fc5ff80.json
Vendored
+1
@@ -0,0 +1 @@
|
||||
{"nodes": [{"id": "users_zlwu_work_00code_shanxia2_0_backend_app_services_bx_advance_py", "label": "advance.py", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/advance.py", "source_location": "L1"}, {"id": "bx_advance_advanceservice", "label": "AdvanceService", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/advance.py", "source_location": "L24"}, {"id": "bx_advance_advanceservice_tenant_no", "label": "._tenant_no()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/advance.py", "source_location": "L26"}, {"id": "session", "label": "Session", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/advance.py", "source_location": "L26"}, {"id": "bxusercontext", "label": "BxUserContext", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/advance.py", "source_location": "L26"}, {"id": "str", "label": "str", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/advance.py", "source_location": "L26"}, {"id": "bx_advance_advanceservice_get_by_id", "label": ".get_by_id()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/advance.py", "source_location": "L30"}, {"id": "bxadvanceapply", "label": "BxAdvanceApply", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/advance.py", "source_location": "L30"}, {"id": "bx_advance_advanceservice_get_paged", "label": ".get_paged()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/advance.py", "source_location": "L34"}, {"id": "int", "label": "int", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/advance.py", "source_location": "L34"}, {"id": "any", "label": "Any", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/advance.py", "source_location": "L34"}, {"id": "bx_advance_advanceservice_create", "label": ".create()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/advance.py", "source_location": "L44"}, {"id": "bx_advance_advanceservice_update", "label": ".update()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/advance.py", "source_location": "L61"}, {"id": "bx_advance_advanceservice_soft_delete", "label": ".soft_delete()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/advance.py", "source_location": "L79"}, {"id": "bool", "label": "bool", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/advance.py", "source_location": "L79"}, {"id": "bx_advance_advanceservice_pending_approval", "label": ".pending_approval()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/advance.py", "source_location": "L86"}, {"id": "bx_advance_advanceservice_approved_by_me", "label": ".approved_by_me()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/advance.py", "source_location": "L142"}, {"id": "bx_advance_advanceservice_workflow_nodes", "label": "._workflow_nodes()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/advance.py", "source_location": "L190"}, {"id": "bxworkflownode", "label": "BxWorkflowNode", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/advance.py", "source_location": "L190"}, {"id": "bx_advance_advanceservice_submit", "label": ".submit()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/advance.py", "source_location": "L203"}, {"id": "bx_advance_advanceservice_approve", "label": ".approve()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/advance.py", "source_location": "L220"}, {"id": "bx_advance_advanceservice_reject", "label": ".reject()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/advance.py", "source_location": "L265"}, {"id": "bx_advance_advanceservice_get_approvals", "label": ".get_approvals()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/advance.py", "source_location": "L302"}, {"id": "bx_advance_advanceservice_global_status_counts", "label": ".global_status_counts()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/advance.py", "source_location": "L354"}, {"id": "bx_advance_advanceservice_my_apply_stats", "label": ".my_apply_stats()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/advance.py", "source_locaLine truncated
|
||||
backend/graphify-out/cache/ast/3f2e8a41f3acc0832a6554dac6a1afc8a589a915c289679f1cc553504894f609.json
Vendored
+1
@@ -0,0 +1 @@
|
||||
{"nodes": [{"id": "users_zlwu_work_00code_shanxia2_0_backend_app_api_bx_init_py", "label": "__init__.py", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/__init__.py", "source_location": "L1"}, {"id": "bx_init_bx_health", "label": "bx_health()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/__init__.py", "source_location": "L15"}, {"id": "bx_init_rationale_1", "label": "\u62a5\u9500\uff08bx\uff09API \u8def\u7531\u805a\u5408 \u2014 REST \u98ce\u683c\uff0c\u534f\u8bae\u5bf9\u9f50 bx \u539f\u7cfb\u7edf\u3002", "file_type": "rationale", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/__init__.py", "source_location": "L1"}, {"id": "bx_init_rationale_16", "label": "P0 \u5065\u5eb7\u68c0\u67e5\uff1a\u9a8c\u8bc1 bx \u8def\u7531\u5df2\u6302\u8f7d\u4e14\u54cd\u5e94\u534f\u8bae\u4e3a code=0\u3002", "file_type": "rationale", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/__init__.py", "source_location": "L16"}], "edges": [{"source": "users_zlwu_work_00code_shanxia2_0_backend_app_api_bx_init_py", "target": "fastapi", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/__init__.py", "source_location": "L2", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_api_bx_init_py", "target": "app_api_bx", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/__init__.py", "source_location": "L4", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_api_bx_init_py", "target": "app_schemas_bx_common", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/__init__.py", "source_location": "L5", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_api_bx_init_py", "target": "bx_init_bx_health", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/__init__.py", "source_location": "L15", "weight": 1.0}, {"source": "bx_init_rationale_1", "target": "users_zlwu_work_00code_shanxia2_0_backend_app_api_bx_init_py", "relation": "rationale_for", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/__init__.py", "source_location": "L1", "weight": 1.0}, {"source": "bx_init_rationale_16", "target": "bx_init_bx_health", "relation": "rationale_for", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/__init__.py", "source_location": "L16", "weight": 1.0}], "raw_calls": [{"caller_nid": "bx_init_bx_health", "callee": "ApiResponse", "is_member_call": false, "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/__init__.py", "source_location": "L17"}]}
|
||||
backend/graphify-out/cache/ast/42a9f75f58ed58881c277f489764089d77a76117b63c3a64644efb082f8599fe.json
Vendored
+1
@@ -0,0 +1 @@
|
||||
{"nodes": [{"id": "users_zlwu_work_00code_shanxia2_0_backend_app_services_bx_reimburse_py", "label": "reimburse.py", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/reimburse.py", "source_location": "L1"}, {"id": "bx_reimburse_reimburseservice", "label": "ReimburseService", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/reimburse.py", "source_location": "L31"}, {"id": "bx_reimburse_reimburseservice_tenant_no", "label": "._tenant_no()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/reimburse.py", "source_location": "L33"}, {"id": "session", "label": "Session", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/reimburse.py", "source_location": "L33"}, {"id": "bxusercontext", "label": "BxUserContext", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/reimburse.py", "source_location": "L33"}, {"id": "str", "label": "str", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/reimburse.py", "source_location": "L33"}, {"id": "bx_reimburse_reimburseservice_get_by_id", "label": ".get_by_id()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/reimburse.py", "source_location": "L37"}, {"id": "bxreimburseapply", "label": "BxReimburseApply", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/reimburse.py", "source_location": "L37"}, {"id": "bx_reimburse_reimburseservice_get_paged", "label": ".get_paged()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/reimburse.py", "source_location": "L41"}, {"id": "int", "label": "int", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/reimburse.py", "source_location": "L41"}, {"id": "any", "label": "Any", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/reimburse.py", "source_location": "L41"}, {"id": "bx_reimburse_reimburseservice_soft_delete", "label": ".soft_delete()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/reimburse.py", "source_location": "L51"}, {"id": "bool", "label": "bool", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/reimburse.py", "source_location": "L51"}, {"id": "bx_reimburse_reimburseservice_workflow_nodes", "label": "._workflow_nodes()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/reimburse.py", "source_location": "L58"}, {"id": "bxworkflownode", "label": "BxWorkflowNode", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/reimburse.py", "source_location": "L58"}, {"id": "bx_reimburse_reimburseservice_pending_approval", "label": ".pending_approval()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/reimburse.py", "source_location": "L71"}, {"id": "bx_reimburse_reimburseservice_approved_by_me", "label": ".approved_by_me()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/reimburse.py", "source_location": "L127"}, {"id": "bx_reimburse_reimburseservice_submit", "label": ".submit()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/reimburse.py", "source_location": "L175"}, {"id": "bx_reimburse_reimburseservice_approve", "label": ".approve()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/reimburse.py", "source_location": "L192"}, {"id": "bx_reimburse_reimburseservice_reject", "label": ".reject()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/reimburse.py", "source_location": "L237"}, {"id": "bx_reimburse_reimburseservice_approval_record_dict", "label": "._approval_record_dict()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/reimburse.py", "source_location": "L274"}, {"id": "bxreimburseapproval", "label": "BxReimburseApproval", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/reimburse.py", "source_location": "L274"}, {"id": "bx_reimburse_reimburseservice_latest_approval_per_node", "label": "._latest_approval_per_node()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/reimburse.py", "source_location": "L287"}, {"id": "bx_reimburse_reimburseservice_query_approvals", "label": "._query_approvals()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/reimburse.py", "source_location": "L304"}, {"id": "bx_reimburse_reimburseservice_get_approvLine truncated
|
||||
backend/graphify-out/cache/ast/4b280dc87c34ea2fea473469ec47c4ac00e6ab9c89fb74ecdfb89a730dd40f0a.json
Vendored
+1
@@ -0,0 +1 @@
|
||||
{"nodes": [{"id": "users_zlwu_work_00code_shanxia2_0_backend_app_api_bx_reimburse_py", "label": "reimburse.py", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/reimburse.py", "source_location": "L1"}, {"id": "bx_reimburse_tenant", "label": "_tenant()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/reimburse.py", "source_location": "L29"}, {"id": "session", "label": "Session", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/reimburse.py", "source_location": "L29"}, {"id": "bxusercontext", "label": "BxUserContext", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/reimburse.py", "source_location": "L29"}, {"id": "str", "label": "str", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/reimburse.py", "source_location": "L29"}, {"id": "bx_reimburse_build_details_data", "label": "_build_details_data()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/reimburse.py", "source_location": "L33"}, {"id": "bx_reimburse_get_generated_title", "label": "get_generated_title()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/reimburse.py", "source_location": "L54"}, {"id": "bx_reimburse_list_reimburses", "label": "list_reimburses()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/reimburse.py", "source_location": "L64"}, {"id": "int", "label": "int", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/reimburse.py", "source_location": "L64"}, {"id": "bx_reimburse_my_reimburses", "label": "my_reimburses()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/reimburse.py", "source_location": "L101"}, {"id": "bx_reimburse_my_reimburse_stats", "label": "my_reimburse_stats()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/reimburse.py", "source_location": "L132"}, {"id": "bx_reimburse_reimburse_status_counts", "label": "reimburse_status_counts()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/reimburse.py", "source_location": "L142"}, {"id": "bx_reimburse_pending_approval", "label": "pending_approval()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/reimburse.py", "source_location": "L151"}, {"id": "bx_reimburse_pending_approval_stats", "label": "pending_approval_stats()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/reimburse.py", "source_location": "L177"}, {"id": "bx_reimburse_approved_by_me", "label": "approved_by_me()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/reimburse.py", "source_location": "L187"}, {"id": "bx_reimburse_get_reimburse", "label": "get_reimburse()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/reimburse.py", "source_location": "L213"}, {"id": "bx_reimburse_get_approvals", "label": "get_approvals()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/reimburse.py", "source_location": "L227"}, {"id": "bx_reimburse_create_reimburse", "label": "create_reimburse()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/reimburse.py", "source_location": "L240"}, {"id": "reimburseapplycreate", "label": "ReimburseApplyCreate", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/reimburse.py", "source_location": "L240"}, {"id": "bx_reimburse_update_reimburse", "label": "update_reimburse()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/reimburse.py", "source_location": "L273"}, {"id": "reimburseapplyupdate", "label": "ReimburseApplyUpdate", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/reimburse.py", "source_location": "L273"}, {"id": "bx_reimburse_submit_reimburse", "label": "submit_reimburse()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/reimburse.py", "source_location": "L298"}, {"id": "bx_reimburse_approve_reimburse", "label": "approve_reimburse()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/reimburse.py", "source_location": "L313"}, {"id": "reimburseapprovalcreate", "label": "ReimburseApprovalCreate", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/reimburse.py", "source_location": "L313"}, {"id": "bx_reimburse_reject_reimburse", "label": "reject_reimburse()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/reimburse.py", "source_location": "L3Line truncated
|
||||
backend/graphify-out/cache/ast/4ce019794ff4400778e2353be879bd40ed03ed91072c9b8521e9eeaddb272905.json
Vendored
+1
@@ -0,0 +1 @@
|
||||
{"nodes": [{"id": "users_zlwu_work_00code_shanxia2_0_backend_app_models_bx_models_py", "label": "bx_models.py", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/models/bx_models.py", "source_location": "L1"}, {"id": "models_bx_models_bxexpenseitem", "label": "BxExpenseItem", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/models/bx_models.py", "source_location": "L9"}, {"id": "base", "label": "Base", "file_type": "code", "source_file": "", "source_location": ""}, {"id": "models_bx_models_bxworkflowdef", "label": "BxWorkflowDef", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/models/bx_models.py", "source_location": "L32"}, {"id": "models_bx_models_bxworkflownode", "label": "BxWorkflowNode", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/models/bx_models.py", "source_location": "L52"}, {"id": "models_bx_models_bxadvanceapply", "label": "BxAdvanceApply", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/models/bx_models.py", "source_location": "L74"}, {"id": "models_bx_models_bxadvanceapproval", "label": "BxAdvanceApproval", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/models/bx_models.py", "source_location": "L107"}, {"id": "models_bx_models_bxreimburseapply", "label": "BxReimburseApply", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/models/bx_models.py", "source_location": "L130"}, {"id": "models_bx_models_bxreimbursedetail", "label": "BxReimburseDetail", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/models/bx_models.py", "source_location": "L166"}, {"id": "models_bx_models_bxreimburseapproval", "label": "BxReimburseApproval", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/models/bx_models.py", "source_location": "L187"}, {"id": "models_bx_models_bxreimburseoffset", "label": "BxReimburseOffset", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/models/bx_models.py", "source_location": "L210"}, {"id": "models_bx_models_bxattachment", "label": "BxAttachment", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/models/bx_models.py", "source_location": "L228"}, {"id": "models_bx_models_rationale_1", "label": "\u62a5\u9500\uff08bx\uff09\u6a21\u5757\u6570\u636e\u6a21\u578b \u2014 \u5bf9\u9f50 docs/sql/20260606_bx_tables.sql", "file_type": "rationale", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/models/bx_models.py", "source_location": "L1"}], "edges": [{"source": "users_zlwu_work_00code_shanxia2_0_backend_app_models_bx_models_py", "target": "datetime", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/models/bx_models.py", "source_location": "L2", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_models_bx_models_py", "target": "sqlalchemy", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/models/bx_models.py", "source_location": "L4", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_models_bx_models_py", "target": "app_core_database", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/models/bx_models.py", "source_location": "L6", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_models_bx_models_py", "target": "models_bx_models_bxexpenseitem", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/models/bx_models.py", "source_location": "L9", "weight": 1.0}, {"source": "models_bx_models_bxexpenseitem", "target": "base", "relation": "inherits", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/models/bx_models.py", "source_location": "L9", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_models_bx_models_py", "target": "models_bx_models_bxworkflowdef", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/models/bx_models.py", "source_location": "L32", "weight": 1.0}, {"source": "models_bx_models_bxworkflowdef", "target": "base", "relation": "inherits", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/models/bx_models.py", "source_location": "L32", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_models_bx_models_py", "target": "models_bx_models_bxworkflownode", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/models/bx_models.py", "source_location": "L52", "wLine truncated
|
||||
backend/graphify-out/cache/ast/4dcc1c902bd56c5ad6cc5144093afcf2e3776c1d4a0cd416d4186b9c35c49dae.json
Vendored
+1
@@ -0,0 +1 @@
|
||||
{"nodes": [{"id": "users_zlwu_work_00code_shanxia2_0_backend_app_api_bx_payment_py", "label": "payment.py", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/payment.py", "source_location": "L1"}, {"id": "bx_payment_tenant", "label": "_tenant()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/payment.py", "source_location": "L39"}, {"id": "session", "label": "Session", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/payment.py", "source_location": "L39"}, {"id": "bxusercontext", "label": "BxUserContext", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/payment.py", "source_location": "L39"}, {"id": "str", "label": "str", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/payment.py", "source_location": "L39"}, {"id": "bx_payment_wrap_reimburse_rows", "label": "_wrap_reimburse_rows()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/payment.py", "source_location": "L43"}, {"id": "reimburseapplyout", "label": "ReimburseApplyOut", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/payment.py", "source_location": "L43"}, {"id": "bx_payment_list_pending_payments", "label": "list_pending_payments()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/payment.py", "source_location": "L48"}, {"id": "int", "label": "int", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/payment.py", "source_location": "L48"}, {"id": "bx_payment_payment_finance_stats", "label": "payment_finance_stats()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/payment.py", "source_location": "L81"}, {"id": "bx_payment_list_processed_payments", "label": "list_processed_payments()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/payment.py", "source_location": "L91"}, {"id": "bx_payment_pay", "label": "pay()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/payment.py", "source_location": "L124"}, {"id": "payrequest", "label": "PayRequest", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/payment.py", "source_location": "L124"}, {"id": "bx_payment_offset", "label": "offset()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/payment.py", "source_location": "L144"}, {"id": "offsetrequest", "label": "OffsetRequest", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/payment.py", "source_location": "L144"}, {"id": "bx_payment_batch_offset", "label": "batch_offset()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/payment.py", "source_location": "L167"}, {"id": "batchoffsetrequest", "label": "BatchOffsetRequest", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/payment.py", "source_location": "L167"}, {"id": "bx_payment_list_advance_issues", "label": "list_advance_issues()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/payment.py", "source_location": "L190"}, {"id": "bx_payment_advance_issue_stats", "label": "advance_issue_stats()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/payment.py", "source_location": "L233"}, {"id": "bx_payment_export_advance_issues", "label": "export_advance_issues()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/payment.py", "source_location": "L243"}, {"id": "bx_payment_issue_advance", "label": "issue_advance()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/payment.py", "source_location": "L319"}, {"id": "advanceissuerequest", "label": "AdvanceIssueRequest", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/payment.py", "source_location": "L319"}, {"id": "bx_payment_list_advance_offset_records", "label": "list_advance_offset_records()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/payment.py", "source_location": "L343"}, {"id": "bx_payment_list_reimburse_offset_records", "label": "list_reimburse_offset_records()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/payment.py", "source_location": "L382"}], "edges": [{"source": "users_zlwu_work_00code_shanxia2_0_backend_app_api_bx_payment_py", "target": "csv", "relation": "imports", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/payment.py", "source_location": "L1", "weight": 1.0}, {"source": "usLine truncated
|
||||
backend/graphify-out/cache/ast/56cb093e7cb58d7cea68412eeccf619a3db93267e3d3e82f5da6db5fb12b0ede.json
Vendored
+1
@@ -0,0 +1 @@
|
||||
{"nodes": [{"id": "users_zlwu_work_00code_shanxia2_0_backend_app_api_bx_advance_py", "label": "advance.py", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/advance.py", "source_location": "L1"}, {"id": "bx_advance_tenant", "label": "_tenant()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/advance.py", "source_location": "L29"}, {"id": "session", "label": "Session", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/advance.py", "source_location": "L29"}, {"id": "bxusercontext", "label": "BxUserContext", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/advance.py", "source_location": "L29"}, {"id": "str", "label": "str", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/advance.py", "source_location": "L29"}, {"id": "bx_advance_fill_offset_amounts", "label": "_fill_offset_amounts()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/advance.py", "source_location": "L33"}, {"id": "advanceapplyout", "label": "AdvanceApplyOut", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/advance.py", "source_location": "L33"}, {"id": "bx_advance_list_advances", "label": "list_advances()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/advance.py", "source_location": "L42"}, {"id": "int", "label": "int", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/advance.py", "source_location": "L42"}, {"id": "bx_advance_my_advances", "label": "my_advances()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/advance.py", "source_location": "L77"}, {"id": "bx_advance_my_advance_stats", "label": "my_advance_stats()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/advance.py", "source_location": "L109"}, {"id": "bx_advance_advance_status_counts", "label": "advance_status_counts()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/advance.py", "source_location": "L119"}, {"id": "bx_advance_pending_approval", "label": "pending_approval()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/advance.py", "source_location": "L128"}, {"id": "bx_advance_advance_pending_approval_stats", "label": "advance_pending_approval_stats()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/advance.py", "source_location": "L154"}, {"id": "bx_advance_approved_by_me", "label": "approved_by_me()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/advance.py", "source_location": "L164"}, {"id": "bx_advance_get_advance", "label": "get_advance()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/advance.py", "source_location": "L190"}, {"id": "bx_advance_get_approvals", "label": "get_approvals()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/advance.py", "source_location": "L206"}, {"id": "bx_advance_create_advance", "label": "create_advance()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/advance.py", "source_location": "L219"}, {"id": "advanceapplycreate", "label": "AdvanceApplyCreate", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/advance.py", "source_location": "L219"}, {"id": "bx_advance_update_advance", "label": "update_advance()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/advance.py", "source_location": "L252"}, {"id": "advanceapplyupdate", "label": "AdvanceApplyUpdate", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/advance.py", "source_location": "L252"}, {"id": "bx_advance_submit_advance", "label": "submit_advance()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/advance.py", "source_location": "L273"}, {"id": "bx_advance_approve_advance", "label": "approve_advance()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/advance.py", "source_location": "L287"}, {"id": "advanceapprovalcreate", "label": "AdvanceApprovalCreate", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/advance.py", "source_location": "L287"}, {"id": "bx_advance_reject_advance", "label": "reject_advance()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/advance.py", "source_location": "L302"}, {"id": "bx_advance_delete_advance", "label": "delete_advance()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/bLine truncated
|
||||
backend/graphify-out/cache/ast/583b12a6d2c9fd4411b652741e73324df9256138946ee873a0ed03169f8dae2a.json
Vendored
+1
@@ -0,0 +1 @@
|
||||
{"nodes": [{"id": "users_zlwu_work_00code_shanxia2_0_backend_app_services_bx_init_py", "label": "__init__.py", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/__init__.py", "source_location": "L1"}], "edges": [], "raw_calls": []}
|
||||
backend/graphify-out/cache/ast/5906745ed3a9a4a62ccfec436a8fac62e8c6cb5c5a61715bb1979a7e5bef804a.json
Vendored
+1
@@ -0,0 +1 @@
|
||||
{"nodes": [{"id": "users_zlwu_work_00code_shanxia2_0_backend_app_main_py", "label": "main.py", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/main.py", "source_location": "L1"}, {"id": "app_main_lifespan", "label": "lifespan()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/main.py", "source_location": "L30"}, {"id": "fastapi", "label": "FastAPI", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/main.py", "source_location": "L30"}, {"id": "app_main_error_json", "label": "_error_json()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/main.py", "source_location": "L77"}, {"id": "int", "label": "int", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/main.py", "source_location": "L77"}, {"id": "str", "label": "str", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/main.py", "source_location": "L77"}, {"id": "jsonresponse", "label": "JSONResponse", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/main.py", "source_location": "L77"}, {"id": "app_main_sqlalchemy_exception_handler", "label": "sqlalchemy_exception_handler()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/main.py", "source_location": "L90"}, {"id": "request", "label": "Request", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/main.py", "source_location": "L90"}, {"id": "sqlalchemyerror", "label": "SQLAlchemyError", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/main.py", "source_location": "L90"}, {"id": "app_main_unhandled_exception_handler", "label": "unhandled_exception_handler()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/main.py", "source_location": "L101"}, {"id": "exception", "label": "Exception", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/main.py", "source_location": "L101"}, {"id": "app_main_mask_secret", "label": "_mask_secret()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/main.py", "source_location": "L121"}, {"id": "app_main_root", "label": "root()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/main.py", "source_location": "L143"}, {"id": "app_main_health_check", "label": "health_check()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/main.py", "source_location": "L148"}, {"id": "app_main_rationale_91", "label": "\u6570\u636e\u5e93\u5f02\u5e38\uff1a\u8fd4\u56de JSON \u5e76\u4fdd\u7559 CORS \u5934\uff0c\u907f\u514d\u6d4f\u89c8\u5668\u53ea\u62a5\u8de8\u57df\u9519\u8bef", "file_type": "rationale", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/main.py", "source_location": "L91"}, {"id": "app_main_rationale_102", "label": "\u672a\u6355\u83b7\u5f02\u5e38\uff1a\u7edf\u4e00 JSON 500\uff0c\u786e\u4fdd\u8de8\u57df\u573a\u666f\u4e0b\u4ecd\u6709 Access-Control-Allow-Origin", "file_type": "rationale", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/main.py", "source_location": "L102"}], "edges": [{"source": "users_zlwu_work_00code_shanxia2_0_backend_app_main_py", "target": "contextlib", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/main.py", "source_location": "L2", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_main_py", "target": "logging", "relation": "imports", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/main.py", "source_location": "L3", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_main_py", "target": "datetime", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/main.py", "source_location": "L4", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_main_py", "target": "fastapi", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/main.py", "source_location": "L6", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_main_py", "target": "fastapi_middleware_cors", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/main.py", "source_location": "L7", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_main_py", "target": "fastapi_responses", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/main.py", "source_location": "L8", "weight": 1.0}, {"sLine truncated
|
||||
backend/graphify-out/cache/ast/59572b469529962b623accad7a5e21f5a5299a69285977acfa93af8c12ec7703.json
Vendored
+1
@@ -0,0 +1 @@
|
||||
{"nodes": [{"id": "users_zlwu_work_00code_shanxia2_0_backend_app_api_bx_attachment_py", "label": "attachment.py", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/attachment.py", "source_location": "L1"}, {"id": "bx_attachment_tenant", "label": "_tenant()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/attachment.py", "source_location": "L24"}, {"id": "session", "label": "Session", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/attachment.py", "source_location": "L24"}, {"id": "bxusercontext", "label": "BxUserContext", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/attachment.py", "source_location": "L24"}, {"id": "str", "label": "str", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/attachment.py", "source_location": "L24"}, {"id": "bx_attachment_parse_id_list", "label": "_parse_id_list()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/attachment.py", "source_location": "L28"}, {"id": "bx_attachment_upload_file", "label": "upload_file()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/attachment.py", "source_location": "L33"}, {"id": "uploadfile", "label": "UploadFile", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/attachment.py", "source_location": "L33"}, {"id": "bx_attachment_download_file", "label": "download_file()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/attachment.py", "source_location": "L67"}, {"id": "bx_attachment_delete_attachment", "label": "delete_attachment()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/attachment.py", "source_location": "L89"}, {"id": "bx_attachment_preview_attachment", "label": "preview_attachment()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/attachment.py", "source_location": "L103"}, {"id": "bx_attachment_list_by_biz", "label": "list_by_biz()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/attachment.py", "source_location": "L127"}, {"id": "bx_attachment_bind_biz", "label": "bind_biz()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/attachment.py", "source_location": "L140"}, {"id": "bx_attachment_rationale_108", "label": "\u8fd4\u56de\u56fe\u7247/\u9644\u4ef6\u9884\u89c8 URL\uff08MinIO \u9884\u7b7e\u540d\u6216\u672c\u5730\u516c\u5f00\u5730\u5740\uff0c\u5bf9\u9f50\u95e8\u6237 storage \u80fd\u529b\uff09\u3002", "file_type": "rationale", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/attachment.py", "source_location": "L108"}], "edges": [{"source": "users_zlwu_work_00code_shanxia2_0_backend_app_api_bx_attachment_py", "target": "mimetypes", "relation": "imports", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/attachment.py", "source_location": "L1", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_api_bx_attachment_py", "target": "typing", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/attachment.py", "source_location": "L2", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_api_bx_attachment_py", "target": "urllib_parse", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/attachment.py", "source_location": "L3", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_api_bx_attachment_py", "target": "fastapi", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/attachment.py", "source_location": "L5", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_api_bx_attachment_py", "target": "fastapi_responses", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/attachment.py", "source_location": "L6", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_api_bx_attachment_py", "target": "sqlalchemy_orm", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/attachment.py", "source_location": "L7", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_api_bx_attachment_py", "target": "app_core_bx_auth", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00codLine truncated
|
||||
backend/graphify-out/cache/ast/5cbe170d19fdb5f5abf34d2e87709430e9dd89f2fd5cb13314af556dd0867582.json
Vendored
+1
@@ -0,0 +1 @@
|
||||
{"nodes": [{"id": "users_zlwu_work_00code_shanxia2_0_backend_app_models_bx_models_py", "label": "bx_models.py", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/models/bx_models.py", "source_location": "L1"}, {"id": "models_bx_models_bxexpenseitem", "label": "BxExpenseItem", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/models/bx_models.py", "source_location": "L10"}, {"id": "base", "label": "Base", "file_type": "code", "source_file": "", "source_location": ""}, {"id": "models_bx_models_bxworkflowdef", "label": "BxWorkflowDef", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/models/bx_models.py", "source_location": "L33"}, {"id": "models_bx_models_bxworkflownode", "label": "BxWorkflowNode", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/models/bx_models.py", "source_location": "L62"}, {"id": "models_bx_models_bxadvanceapply", "label": "BxAdvanceApply", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/models/bx_models.py", "source_location": "L95"}, {"id": "models_bx_models_bxadvanceapproval", "label": "BxAdvanceApproval", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/models/bx_models.py", "source_location": "L128"}, {"id": "models_bx_models_bxreimburseapply", "label": "BxReimburseApply", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/models/bx_models.py", "source_location": "L151"}, {"id": "models_bx_models_bxreimbursedetail", "label": "BxReimburseDetail", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/models/bx_models.py", "source_location": "L187"}, {"id": "models_bx_models_bxreimburseapproval", "label": "BxReimburseApproval", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/models/bx_models.py", "source_location": "L208"}, {"id": "models_bx_models_bxreimburseoffset", "label": "BxReimburseOffset", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/models/bx_models.py", "source_location": "L231"}, {"id": "models_bx_models_bxattachment", "label": "BxAttachment", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/models/bx_models.py", "source_location": "L249"}, {"id": "models_bx_models_rationale_1", "label": "\u62a5\u9500\uff08bx\uff09\u6a21\u5757\u6570\u636e\u6a21\u578b \u2014 \u5bf9\u9f50 docs/sql/20260606_bx_tables.sql", "file_type": "rationale", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/models/bx_models.py", "source_location": "L1"}], "edges": [{"source": "users_zlwu_work_00code_shanxia2_0_backend_app_models_bx_models_py", "target": "datetime", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/models/bx_models.py", "source_location": "L2", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_models_bx_models_py", "target": "sqlalchemy", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/models/bx_models.py", "source_location": "L4", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_models_bx_models_py", "target": "sqlalchemy_orm", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/models/bx_models.py", "source_location": "L5", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_models_bx_models_py", "target": "app_core_database", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/models/bx_models.py", "source_location": "L7", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_models_bx_models_py", "target": "models_bx_models_bxexpenseitem", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/models/bx_models.py", "source_location": "L10", "weight": 1.0}, {"source": "models_bx_models_bxexpenseitem", "target": "base", "relation": "inherits", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/models/bx_models.py", "source_location": "L10", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_models_bx_models_py", "target": "models_bx_models_bxworkflowdef", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/models/bx_models.py", "source_location": "L33", "weight": 1.0}, {"source": "models_bx_models_bxworkflowdef", "target": "base", "relation": "inherits", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/models/bx_models.py", "source_location":Line truncated
|
||||
backend/graphify-out/cache/ast/5cc369f743c5955e362553c65866cacfb9c8f33a4c4d293d9f74a35b1950867f.json
Vendored
+1
@@ -0,0 +1 @@
|
||||
{"nodes": [{"id": "users_zlwu_work_00code_shanxia2_0_backend_app_schemas_bx_reimburse_py", "label": "reimburse.py", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/bx/reimburse.py", "source_location": "L1"}, {"id": "bx_reimburse_coerce_id", "label": "_coerce_id()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/bx/reimburse.py", "source_location": "L9"}, {"id": "bx_reimburse_reimbursedetailcreate", "label": "ReimburseDetailCreate", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/bx/reimburse.py", "source_location": "L15"}, {"id": "basemodel", "label": "BaseModel", "file_type": "code", "source_file": "", "source_location": ""}, {"id": "bx_reimburse_reimbursedetailcreate_validate_expense_item_id", "label": ".validate_expense_item_id()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/bx/reimburse.py", "source_location": "L24"}, {"id": "bx_reimburse_reimbursedetailout", "label": "ReimburseDetailOut", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/bx/reimburse.py", "source_location": "L31"}, {"id": "bx_reimburse_reimburseapplycreate", "label": "ReimburseApplyCreate", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/bx/reimburse.py", "source_location": "L41"}, {"id": "bx_reimburse_reimburseapplycreate_details_must_not_be_empty", "label": ".details_must_not_be_empty()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/bx/reimburse.py", "source_location": "L50"}, {"id": "bx_reimburse_reimburseapplyupdate", "label": "ReimburseApplyUpdate", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/bx/reimburse.py", "source_location": "L56"}, {"id": "bx_reimburse_reimburseapplyout", "label": "ReimburseApplyOut", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/bx/reimburse.py", "source_location": "L63"}, {"id": "bx_reimburse_reimburseapprovalcreate", "label": "ReimburseApprovalCreate", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/bx/reimburse.py", "source_location": "L89"}, {"id": "bx_reimburse_reimburseapprovalout", "label": "ReimburseApprovalOut", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/bx/reimburse.py", "source_location": "L96"}, {"id": "bx_reimburse_reimbursemystatsout", "label": "ReimburseMyStatsOut", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/bx/reimburse.py", "source_location": "L109"}, {"id": "bx_reimburse_reimburseapproverpendingstatsout", "label": "ReimburseApproverPendingStatsOut", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/bx/reimburse.py", "source_location": "L121"}], "edges": [{"source": "users_zlwu_work_00code_shanxia2_0_backend_app_schemas_bx_reimburse_py", "target": "typing", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/bx/reimburse.py", "source_location": "L1", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_schemas_bx_reimburse_py", "target": "pydantic", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/bx/reimburse.py", "source_location": "L3", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_schemas_bx_reimburse_py", "target": "pydantic_alias_generators", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/bx/reimburse.py", "source_location": "L4", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_schemas_bx_reimburse_py", "target": "app_schemas_bx_common", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/bx/reimburse.py", "source_location": "L6", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_schemas_bx_reimburse_py", "target": "bx_reimburse_coerce_id", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/bx/reimburse.py", "source_location": "L9", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_schemas_bx_reimburse_py", "target": "bx_reimburse_reimbursedetailcreate", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/bx/reimburse.py", "source_location": "L15", "weight": 1.0}, {"source": "bx_reimburse_reimbursedetailcreate", "target": "basemodel", "relation": "inherits", "confiLine truncated
|
||||
backend/graphify-out/cache/ast/6705c068242c66ac0ad917e925935ee615e87ecccddcc948c4a4bfc87e90eb28.json
Vendored
+1
@@ -0,0 +1 @@
|
||||
{"nodes": [{"id": "users_zlwu_work_00code_shanxia2_0_backend_app_services_bx_advance_py", "label": "advance.py", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/advance.py", "source_location": "L1"}, {"id": "bx_advance_advanceservice", "label": "AdvanceService", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/advance.py", "source_location": "L25"}, {"id": "bx_advance_advanceservice_tenant_no", "label": "._tenant_no()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/advance.py", "source_location": "L27"}, {"id": "session", "label": "Session", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/advance.py", "source_location": "L27"}, {"id": "bxusercontext", "label": "BxUserContext", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/advance.py", "source_location": "L27"}, {"id": "str", "label": "str", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/advance.py", "source_location": "L27"}, {"id": "bx_advance_advanceservice_get_by_id", "label": ".get_by_id()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/advance.py", "source_location": "L31"}, {"id": "bxadvanceapply", "label": "BxAdvanceApply", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/advance.py", "source_location": "L31"}, {"id": "bx_advance_advanceservice_get_paged", "label": ".get_paged()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/advance.py", "source_location": "L35"}, {"id": "int", "label": "int", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/advance.py", "source_location": "L35"}, {"id": "any", "label": "Any", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/advance.py", "source_location": "L35"}, {"id": "bx_advance_advanceservice_create", "label": ".create()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/advance.py", "source_location": "L45"}, {"id": "bx_advance_advanceservice_update", "label": ".update()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/advance.py", "source_location": "L62"}, {"id": "bx_advance_advanceservice_soft_delete", "label": ".soft_delete()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/advance.py", "source_location": "L80"}, {"id": "bool", "label": "bool", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/advance.py", "source_location": "L80"}, {"id": "bx_advance_advanceservice_pending_approval", "label": ".pending_approval()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/advance.py", "source_location": "L87"}, {"id": "bx_advance_advanceservice_approved_by_me", "label": ".approved_by_me()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/advance.py", "source_location": "L143"}, {"id": "bx_advance_advanceservice_workflow_nodes", "label": "._workflow_nodes()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/advance.py", "source_location": "L191"}, {"id": "bxworkflownode", "label": "BxWorkflowNode", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/advance.py", "source_location": "L191"}, {"id": "bx_advance_advanceservice_submit", "label": ".submit()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/advance.py", "source_location": "L204"}, {"id": "bx_advance_advanceservice_approve", "label": ".approve()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/advance.py", "source_location": "L221"}, {"id": "bx_advance_advanceservice_reject", "label": ".reject()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/advance.py", "source_location": "L266"}, {"id": "bx_advance_advanceservice_approval_record_dict", "label": "._approval_record_dict()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/advance.py", "source_location": "L303"}, {"id": "bxadvanceapproval", "label": "BxAdvanceApproval", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/advance.py", "source_location": "L303"}, {"id": "bx_advance_advanceservice_latest_approval_per_node", "label": "._latest_approval_per_node()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/advance.py", "source_locLine truncated
|
||||
backend/graphify-out/cache/ast/680cf05a952f4069441e8fe432c96d2feb6cb9e8cddd24ca1109d5f89f5fb06c.json
Vendored
+1
@@ -0,0 +1 @@
|
||||
{"nodes": [{"id": "users_zlwu_work_00code_shanxia2_0_backend_app_schemas_bx_advance_py", "label": "advance.py", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/bx/advance.py", "source_location": "L1"}, {"id": "bx_advance_coerce_optional_id", "label": "_coerce_optional_id()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/bx/advance.py", "source_location": "L9"}, {"id": "bx_advance_advanceapplycreate", "label": "AdvanceApplyCreate", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/bx/advance.py", "source_location": "L16"}, {"id": "basemodel", "label": "BaseModel", "file_type": "code", "source_file": "", "source_location": ""}, {"id": "bx_advance_advanceapplycreate_validate_expense_item_id", "label": ".validate_expense_item_id()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/bx/advance.py", "source_location": "L27"}, {"id": "bx_advance_advanceapplyupdate", "label": "AdvanceApplyUpdate", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/bx/advance.py", "source_location": "L31"}, {"id": "bx_advance_advanceapplyupdate_validate_expense_item_id", "label": ".validate_expense_item_id()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/bx/advance.py", "source_location": "L42"}, {"id": "bx_advance_advanceapplyout", "label": "AdvanceApplyOut", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/bx/advance.py", "source_location": "L46"}, {"id": "bx_advance_advanceapprovalcreate", "label": "AdvanceApprovalCreate", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/bx/advance.py", "source_location": "L69"}, {"id": "bx_advance_advanceapprovalout", "label": "AdvanceApprovalOut", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/bx/advance.py", "source_location": "L76"}, {"id": "bx_advance_advancemystatsout", "label": "AdvanceMyStatsOut", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/bx/advance.py", "source_location": "L89"}, {"id": "bx_advance_advanceapproverpendingstatsout", "label": "AdvanceApproverPendingStatsOut", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/bx/advance.py", "source_location": "L104"}, {"id": "bx_advance_advanceissueout", "label": "AdvanceIssueOut", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/bx/advance.py", "source_location": "L111"}, {"id": "bx_advance_advanceissuerequest", "label": "AdvanceIssueRequest", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/bx/advance.py", "source_location": "L130"}, {"id": "bx_advance_advanceoffsetrecordout", "label": "AdvanceOffsetRecordOut", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/bx/advance.py", "source_location": "L137"}, {"id": "bx_advance_advancefinanceissuestatsout", "label": "AdvanceFinanceIssueStatsOut", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/bx/advance.py", "source_location": "L150"}], "edges": [{"source": "users_zlwu_work_00code_shanxia2_0_backend_app_schemas_bx_advance_py", "target": "typing", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/bx/advance.py", "source_location": "L1", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_schemas_bx_advance_py", "target": "pydantic", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/bx/advance.py", "source_location": "L3", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_schemas_bx_advance_py", "target": "pydantic_alias_generators", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/bx/advance.py", "source_location": "L4", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_schemas_bx_advance_py", "target": "app_schemas_bx_common", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/bx/advance.py", "source_location": "L6", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_schemas_bx_advance_py", "target": "bx_advance_coerce_optional_id", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/bx/advance.py", "source_location": "L9", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_schemas_bx_Line truncated
|
||||
backend/graphify-out/cache/ast/69d1ff449abb1e0430ec94d8a710cf44259a5940dd9ae062d22f1579bb6dfcba.json
Vendored
+1
@@ -0,0 +1 @@
|
||||
{"nodes": [{"id": "users_zlwu_work_00code_shanxia2_0_backend_app_services_bx_advance_py", "label": "advance.py", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/advance.py", "source_location": "L1"}, {"id": "bx_advance_advanceservice", "label": "AdvanceService", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/advance.py", "source_location": "L24"}, {"id": "bx_advance_advanceservice_tenant_no", "label": "._tenant_no()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/advance.py", "source_location": "L26"}, {"id": "session", "label": "Session", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/advance.py", "source_location": "L26"}, {"id": "bxusercontext", "label": "BxUserContext", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/advance.py", "source_location": "L26"}, {"id": "str", "label": "str", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/advance.py", "source_location": "L26"}, {"id": "bx_advance_advanceservice_get_by_id", "label": ".get_by_id()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/advance.py", "source_location": "L30"}, {"id": "bxadvanceapply", "label": "BxAdvanceApply", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/advance.py", "source_location": "L30"}, {"id": "bx_advance_advanceservice_get_paged", "label": ".get_paged()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/advance.py", "source_location": "L34"}, {"id": "int", "label": "int", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/advance.py", "source_location": "L34"}, {"id": "any", "label": "Any", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/advance.py", "source_location": "L34"}, {"id": "bx_advance_advanceservice_create", "label": ".create()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/advance.py", "source_location": "L44"}, {"id": "bx_advance_advanceservice_update", "label": ".update()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/advance.py", "source_location": "L61"}, {"id": "bx_advance_advanceservice_soft_delete", "label": ".soft_delete()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/advance.py", "source_location": "L79"}, {"id": "bool", "label": "bool", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/advance.py", "source_location": "L79"}, {"id": "bx_advance_advanceservice_pending_approval", "label": ".pending_approval()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/advance.py", "source_location": "L86"}, {"id": "bx_advance_advanceservice_approved_by_me", "label": ".approved_by_me()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/advance.py", "source_location": "L142"}, {"id": "bx_advance_advanceservice_workflow_nodes", "label": "._workflow_nodes()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/advance.py", "source_location": "L190"}, {"id": "bxworkflownode", "label": "BxWorkflowNode", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/advance.py", "source_location": "L190"}, {"id": "bx_advance_advanceservice_submit", "label": ".submit()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/advance.py", "source_location": "L203"}, {"id": "bx_advance_advanceservice_approve", "label": ".approve()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/advance.py", "source_location": "L220"}, {"id": "bx_advance_advanceservice_reject", "label": ".reject()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/advance.py", "source_location": "L265"}, {"id": "bx_advance_advanceservice_approval_record_dict", "label": "._approval_record_dict()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/advance.py", "source_location": "L302"}, {"id": "bxadvanceapproval", "label": "BxAdvanceApproval", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/advance.py", "source_location": "L302"}, {"id": "bx_advance_advanceservice_latest_approval_per_node", "label": "._latest_approval_per_node()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/advance.py", "source_locLine truncated
|
||||
backend/graphify-out/cache/ast/718cda4882de824f750f0d99bcc12c3240f29acb7979f1a6e04d903feb1f434c.json
Vendored
+1
@@ -0,0 +1 @@
|
||||
{"nodes": [{"id": "users_zlwu_work_00code_shanxia2_0_backend_app_schemas_bx_expense_item_py", "label": "expense_item.py", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/bx/expense_item.py", "source_location": "L1"}, {"id": "bx_expense_item_coerce_id", "label": "_coerce_id()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/bx/expense_item.py", "source_location": "L7"}, {"id": "str", "label": "str", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/bx/expense_item.py", "source_location": "L7"}, {"id": "bx_expense_item_expenseitemcreate", "label": "ExpenseItemCreate", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/bx/expense_item.py", "source_location": "L13"}, {"id": "basemodel", "label": "BaseModel", "file_type": "code", "source_file": "", "source_location": ""}, {"id": "bx_expense_item_expenseitemcreate_validate_parent_id", "label": ".validate_parent_id()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/bx/expense_item.py", "source_location": "L26"}, {"id": "bx_expense_item_expenseitemupdate", "label": "ExpenseItemUpdate", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/bx/expense_item.py", "source_location": "L30"}, {"id": "bx_expense_item_expenseitemupdate_validate_parent_id", "label": ".validate_parent_id()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/bx/expense_item.py", "source_location": "L43"}, {"id": "bx_expense_item_expenseitemout", "label": "ExpenseItemOut", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/bx/expense_item.py", "source_location": "L49"}], "edges": [{"source": "users_zlwu_work_00code_shanxia2_0_backend_app_schemas_bx_expense_item_py", "target": "typing", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/bx/expense_item.py", "source_location": "L1", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_schemas_bx_expense_item_py", "target": "pydantic", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/bx/expense_item.py", "source_location": "L3", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_schemas_bx_expense_item_py", "target": "pydantic_alias_generators", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/bx/expense_item.py", "source_location": "L4", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_schemas_bx_expense_item_py", "target": "bx_expense_item_coerce_id", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/bx/expense_item.py", "source_location": "L7", "weight": 1.0}, {"source": "bx_expense_item_coerce_id", "target": "str", "relation": "references", "context": "return_type", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/bx/expense_item.py", "source_location": "L7", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_schemas_bx_expense_item_py", "target": "bx_expense_item_expenseitemcreate", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/bx/expense_item.py", "source_location": "L13", "weight": 1.0}, {"source": "bx_expense_item_expenseitemcreate", "target": "basemodel", "relation": "inherits", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/bx/expense_item.py", "source_location": "L13", "weight": 1.0}, {"source": "bx_expense_item_expenseitemcreate", "target": "bx_expense_item_expenseitemcreate_validate_parent_id", "relation": "method", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/bx/expense_item.py", "source_location": "L26", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_schemas_bx_expense_item_py", "target": "bx_expense_item_expenseitemupdate", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/bx/expense_item.py", "source_location": "L30", "weight": 1.0}, {"source": "bx_expense_item_expenseitemupdate", "target": "basemodel", "relation": "inherits", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/bx/expense_item.py", "source_location": "L30", "weight": 1.0}, {"source": "bx_expense_item_expenseitemupdate", "target": "bx_expense_item_expenseitemupdate_validate_parent_id", "relation": "method", "confidenceLine truncated
|
||||
backend/graphify-out/cache/ast/85fccc96d4c64be381f417edd2d0e112338138807589de7dd697e8f9602f868b.json
Vendored
+1
@@ -0,0 +1 @@
|
||||
{"nodes": [{"id": "users_zlwu_work_00code_shanxia2_0_backend_app_api_bx_expense_item_py", "label": "expense_item.py", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/expense_item.py", "source_location": "L1"}, {"id": "bx_expense_item_get_expense_item_tree", "label": "get_expense_item_tree()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/expense_item.py", "source_location": "L17"}, {"id": "session", "label": "Session", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/expense_item.py", "source_location": "L17"}, {"id": "bxusercontext", "label": "BxUserContext", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/expense_item.py", "source_location": "L17"}, {"id": "bx_expense_item_get_expense_item", "label": "get_expense_item()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/expense_item.py", "source_location": "L27"}, {"id": "str", "label": "str", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/expense_item.py", "source_location": "L27"}, {"id": "bx_expense_item_create_expense_item", "label": "create_expense_item()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/expense_item.py", "source_location": "L40"}, {"id": "expenseitemcreate", "label": "ExpenseItemCreate", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/expense_item.py", "source_location": "L40"}, {"id": "bx_expense_item_update_expense_item", "label": "update_expense_item()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/expense_item.py", "source_location": "L56"}, {"id": "expenseitemupdate", "label": "ExpenseItemUpdate", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/expense_item.py", "source_location": "L56"}, {"id": "bx_expense_item_delete_expense_item", "label": "delete_expense_item()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/expense_item.py", "source_location": "L78"}], "edges": [{"source": "users_zlwu_work_00code_shanxia2_0_backend_app_api_bx_expense_item_py", "target": "typing", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/expense_item.py", "source_location": "L1", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_api_bx_expense_item_py", "target": "fastapi", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/expense_item.py", "source_location": "L3", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_api_bx_expense_item_py", "target": "sqlalchemy_orm", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/expense_item.py", "source_location": "L4", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_api_bx_expense_item_py", "target": "app_core_bx_auth", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/expense_item.py", "source_location": "L6", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_api_bx_expense_item_py", "target": "app_core_database", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/expense_item.py", "source_location": "L7", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_api_bx_expense_item_py", "target": "app_core_tenant_context", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/expense_item.py", "source_location": "L8", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_api_bx_expense_item_py", "target": "app_schemas_bx_common", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/expense_item.py", "source_location": "L9", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_api_bx_expense_item_py", "target": "app_schemas_bx_expense_item", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/expense_item.py", "source_location": "L10", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_api_bx_expense_item_py", "target": "app_services_bx_expense_item", "relation": "imports_from", "context": "import", "confidence": "EXTRACLine truncated
|
||||
backend/graphify-out/cache/ast/901aa660dd28cf21f1fa2f8ed3de45eca98a8152aac0f17b7dcd9ae00de0c4e7.json
Vendored
+1
@@ -0,0 +1 @@
|
||||
{"nodes": [{"id": "users_zlwu_work_00code_shanxia2_0_backend_app_api_bx_advance_py", "label": "advance.py", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/advance.py", "source_location": "L1"}, {"id": "bx_advance_tenant", "label": "_tenant()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/advance.py", "source_location": "L29"}, {"id": "session", "label": "Session", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/advance.py", "source_location": "L29"}, {"id": "bxusercontext", "label": "BxUserContext", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/advance.py", "source_location": "L29"}, {"id": "str", "label": "str", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/advance.py", "source_location": "L29"}, {"id": "bx_advance_fill_offset_amounts", "label": "_fill_offset_amounts()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/advance.py", "source_location": "L33"}, {"id": "advanceapplyout", "label": "AdvanceApplyOut", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/advance.py", "source_location": "L33"}, {"id": "bx_advance_list_advances", "label": "list_advances()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/advance.py", "source_location": "L42"}, {"id": "int", "label": "int", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/advance.py", "source_location": "L42"}, {"id": "bx_advance_my_advances", "label": "my_advances()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/advance.py", "source_location": "L77"}, {"id": "bx_advance_my_advance_stats", "label": "my_advance_stats()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/advance.py", "source_location": "L109"}, {"id": "bx_advance_advance_status_counts", "label": "advance_status_counts()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/advance.py", "source_location": "L119"}, {"id": "bx_advance_pending_approval", "label": "pending_approval()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/advance.py", "source_location": "L128"}, {"id": "bx_advance_advance_pending_approval_stats", "label": "advance_pending_approval_stats()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/advance.py", "source_location": "L154"}, {"id": "bx_advance_approved_by_me", "label": "approved_by_me()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/advance.py", "source_location": "L164"}, {"id": "bx_advance_get_advance", "label": "get_advance()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/advance.py", "source_location": "L190"}, {"id": "bx_advance_get_approvals", "label": "get_approvals()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/advance.py", "source_location": "L206"}, {"id": "bx_advance_get_approval_history", "label": "get_approval_history()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/advance.py", "source_location": "L219"}, {"id": "bx_advance_create_advance", "label": "create_advance()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/advance.py", "source_location": "L232"}, {"id": "advanceapplycreate", "label": "AdvanceApplyCreate", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/advance.py", "source_location": "L232"}, {"id": "bx_advance_update_advance", "label": "update_advance()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/advance.py", "source_location": "L265"}, {"id": "advanceapplyupdate", "label": "AdvanceApplyUpdate", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/advance.py", "source_location": "L265"}, {"id": "bx_advance_submit_advance", "label": "submit_advance()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/advance.py", "source_location": "L286"}, {"id": "bx_advance_approve_advance", "label": "approve_advance()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/advance.py", "source_location": "L300"}, {"id": "advanceapprovalcreate", "label": "AdvanceApprovalCreate", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/advance.py", "source_location": "L300"}, {"id": "bx_advance_reject_advance", "label": "reject_advance()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/Line truncated
|
||||
backend/graphify-out/cache/ast/954b95ec688f8c0274cf2e46c5891fc660af9c1812ed282b1b39ebccb87efea6.json
Vendored
+1
@@ -0,0 +1 @@
|
||||
{"nodes": [{"id": "users_zlwu_work_00code_shanxia2_0_backend_app_services_bx_reimburse_py", "label": "reimburse.py", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/reimburse.py", "source_location": "L1"}, {"id": "bx_reimburse_reimburseservice", "label": "ReimburseService", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/reimburse.py", "source_location": "L30"}, {"id": "bx_reimburse_reimburseservice_tenant_no", "label": "._tenant_no()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/reimburse.py", "source_location": "L32"}, {"id": "session", "label": "Session", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/reimburse.py", "source_location": "L32"}, {"id": "bxusercontext", "label": "BxUserContext", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/reimburse.py", "source_location": "L32"}, {"id": "str", "label": "str", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/reimburse.py", "source_location": "L32"}, {"id": "bx_reimburse_reimburseservice_get_by_id", "label": ".get_by_id()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/reimburse.py", "source_location": "L36"}, {"id": "bxreimburseapply", "label": "BxReimburseApply", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/reimburse.py", "source_location": "L36"}, {"id": "bx_reimburse_reimburseservice_get_paged", "label": ".get_paged()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/reimburse.py", "source_location": "L40"}, {"id": "int", "label": "int", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/reimburse.py", "source_location": "L40"}, {"id": "any", "label": "Any", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/reimburse.py", "source_location": "L40"}, {"id": "bx_reimburse_reimburseservice_soft_delete", "label": ".soft_delete()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/reimburse.py", "source_location": "L50"}, {"id": "bool", "label": "bool", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/reimburse.py", "source_location": "L50"}, {"id": "bx_reimburse_reimburseservice_workflow_nodes", "label": "._workflow_nodes()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/reimburse.py", "source_location": "L57"}, {"id": "bxworkflownode", "label": "BxWorkflowNode", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/reimburse.py", "source_location": "L57"}, {"id": "bx_reimburse_reimburseservice_pending_approval", "label": ".pending_approval()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/reimburse.py", "source_location": "L70"}, {"id": "bx_reimburse_reimburseservice_approved_by_me", "label": ".approved_by_me()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/reimburse.py", "source_location": "L126"}, {"id": "bx_reimburse_reimburseservice_submit", "label": ".submit()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/reimburse.py", "source_location": "L174"}, {"id": "bx_reimburse_reimburseservice_approve", "label": ".approve()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/reimburse.py", "source_location": "L191"}, {"id": "bx_reimburse_reimburseservice_reject", "label": ".reject()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/reimburse.py", "source_location": "L236"}, {"id": "bx_reimburse_reimburseservice_approval_record_dict", "label": "._approval_record_dict()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/reimburse.py", "source_location": "L273"}, {"id": "bxreimburseapproval", "label": "BxReimburseApproval", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/reimburse.py", "source_location": "L273"}, {"id": "bx_reimburse_reimburseservice_latest_approval_per_node", "label": "._latest_approval_per_node()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/reimburse.py", "source_location": "L286"}, {"id": "bx_reimburse_reimburseservice_query_approvals", "label": "._query_approvals()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/reimburse.py", "source_location": "L303"}, {"id": "bx_reimburse_reimburseservice_get_approvLine truncated
|
||||
backend/graphify-out/cache/ast/a1404064f42d27efcdf287062da76d4cc863112aa1f2ace1bf86c2f72e8faef9.json
Vendored
+1
@@ -0,0 +1 @@
|
||||
{"nodes": [{"id": "users_zlwu_work_00code_shanxia2_0_backend_app_core_config_py", "label": "config.py", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/core/config.py", "source_location": "L1"}, {"id": "core_config_settings", "label": "Settings", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/core/config.py", "source_location": "L7"}, {"id": "basesettings", "label": "BaseSettings", "file_type": "code", "source_file": "", "source_location": ""}, {"id": "core_config_config", "label": "Config", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/core/config.py", "source_location": "L151"}], "edges": [{"source": "users_zlwu_work_00code_shanxia2_0_backend_app_core_config_py", "target": "pydantic_settings", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/core/config.py", "source_location": "L1", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_core_config_py", "target": "typing", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/core/config.py", "source_location": "L2", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_core_config_py", "target": "pathlib", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/core/config.py", "source_location": "L3", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_core_config_py", "target": "os", "relation": "imports", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/core/config.py", "source_location": "L4", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_core_config_py", "target": "core_config_settings", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/core/config.py", "source_location": "L7", "weight": 1.0}, {"source": "core_config_settings", "target": "basesettings", "relation": "inherits", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/core/config.py", "source_location": "L7", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_core_config_py", "target": "core_config_config", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/core/config.py", "source_location": "L151", "weight": 1.0}], "raw_calls": []}
|
||||
backend/graphify-out/cache/ast/a69603083acd513274bec92f033d2d496f175b17de6aec59d8d2b6f63391abac.json
Vendored
+1
@@ -0,0 +1 @@
|
||||
{"nodes": [{"id": "users_zlwu_work_00code_shanxia2_0_backend_app_services_bx_base_py", "label": "base.py", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/base.py", "source_location": "L1"}, {"id": "bx_base_bxcrudservice", "label": "BxCrudService", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/base.py", "source_location": "L13"}, {"id": "bx_base_bxcrudservice_get_by_id", "label": ".get_by_id()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/base.py", "source_location": "L15"}, {"id": "m", "label": "M", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/base.py", "source_location": "L15"}, {"id": "session", "label": "Session", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/base.py", "source_location": "L15"}, {"id": "str", "label": "str", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/base.py", "source_location": "L15"}, {"id": "bx_base_bxcrudservice_get_paged", "label": ".get_paged()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/base.py", "source_location": "L22"}, {"id": "int", "label": "int", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/base.py", "source_location": "L22"}, {"id": "any", "label": "Any", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/base.py", "source_location": "L22"}, {"id": "bx_base_bxcrudservice_create", "label": ".create()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/base.py", "source_location": "L44"}, {"id": "bx_base_bxcrudservice_update", "label": ".update()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/base.py", "source_location": "L64"}, {"id": "bx_base_bxcrudservice_soft_delete", "label": ".soft_delete()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/base.py", "source_location": "L84"}, {"id": "bool", "label": "bool", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/base.py", "source_location": "L84"}, {"id": "bx_base_rationale_1", "label": "\u62a5\u9500\u6a21\u5757 Service \u57fa\u7c7b \u2014 \u79df\u6237\u9694\u79bb + UUID + \u8f6f\u5220\u9664\u3002", "file_type": "rationale", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/base.py", "source_location": "L1"}], "edges": [{"source": "users_zlwu_work_00code_shanxia2_0_backend_app_services_bx_base_py", "target": "typing", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/base.py", "source_location": "L4", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_services_bx_base_py", "target": "sqlalchemy_orm", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/base.py", "source_location": "L6", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_services_bx_base_py", "target": "app_core_utils", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/base.py", "source_location": "L8", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_services_bx_base_py", "target": "bx_base_bxcrudservice", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/base.py", "source_location": "L13", "weight": 1.0}, {"source": "bx_base_bxcrudservice", "target": "bx_base_bxcrudservice_get_by_id", "relation": "method", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/base.py", "source_location": "L15", "weight": 1.0}, {"source": "bx_base_bxcrudservice_get_by_id", "target": "m", "relation": "references", "context": "generic_arg", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/base.py", "source_location": "L15", "weight": 1.0}, {"source": "bx_base_bxcrudservice_get_by_id", "target": "session", "relation": "references", "context": "parameter_type", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/base.py", "source_location": "L15", "weight": 1.0}, {"source": "bx_base_bxcrudservice_get_by_id", "target": "str", "relation": "references", "context": "parameter_type", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/base.py", "source_location": "L15", "weight": 1.0}, {"soLine truncated
|
||||
backend/graphify-out/cache/ast/ac31c58cf246f27a3f875920f583dd42af66a09f09dc879a215ce05a056d450f.json
Vendored
+1
@@ -0,0 +1 @@
|
||||
{"nodes": [{"id": "users_zlwu_work_00code_shanxia2_0_backend_app_services_bx_expense_item_py", "label": "expense_item.py", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/expense_item.py", "source_location": "L1"}, {"id": "bx_expense_item_expenseitemservice", "label": "ExpenseItemService", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/expense_item.py", "source_location": "L13"}, {"id": "bx_expense_item_expenseitemservice_tenant_no", "label": "._tenant_no()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/expense_item.py", "source_location": "L15"}, {"id": "session", "label": "Session", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/expense_item.py", "source_location": "L15"}, {"id": "bxusercontext", "label": "BxUserContext", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/expense_item.py", "source_location": "L15"}, {"id": "str", "label": "str", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/expense_item.py", "source_location": "L15"}, {"id": "bx_expense_item_expenseitemservice_get_by_id", "label": ".get_by_id()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/expense_item.py", "source_location": "L19"}, {"id": "bxexpenseitem", "label": "BxExpenseItem", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/expense_item.py", "source_location": "L19"}, {"id": "bx_expense_item_expenseitemservice_create", "label": ".create()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/expense_item.py", "source_location": "L23"}, {"id": "bx_expense_item_expenseitemservice_update", "label": ".update()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/expense_item.py", "source_location": "L51"}, {"id": "bx_expense_item_expenseitemservice_soft_delete", "label": ".soft_delete()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/expense_item.py", "source_location": "L79"}, {"id": "bool", "label": "bool", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/expense_item.py", "source_location": "L79"}, {"id": "bx_expense_item_expenseitemservice_get_item_tree", "label": ".get_item_tree()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/expense_item.py", "source_location": "L86"}, {"id": "bx_expense_item_expenseitemservice_build_tree", "label": "._build_tree()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/expense_item.py", "source_location": "L96"}], "edges": [{"source": "users_zlwu_work_00code_shanxia2_0_backend_app_services_bx_expense_item_py", "target": "typing", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/expense_item.py", "source_location": "L3", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_services_bx_expense_item_py", "target": "sqlalchemy_orm", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/expense_item.py", "source_location": "L5", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_services_bx_expense_item_py", "target": "app_core_bx_auth", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/expense_item.py", "source_location": "L7", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_services_bx_expense_item_py", "target": "app_core_tenant_context", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/expense_item.py", "source_location": "L8", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_services_bx_expense_item_py", "target": "app_models_bx_models", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/expense_item.py", "source_location": "L9", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_services_bx_expense_item_py", "target": "app_services_bx_base", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/expense_item.py", "source_location": "L10", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_services_bx_expense_itLine truncated
|
||||
backend/graphify-out/cache/ast/ac98980bd5b6cbab6a9394b6debc678b050cf4df969eccbc5f2d419b615937cd.json
Vendored
+1
@@ -0,0 +1 @@
|
||||
{"nodes": [{"id": "users_zlwu_work_00code_shanxia2_0_backend_app_services_bx_storage_py", "label": "storage.py", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/storage.py", "source_location": "L1"}, {"id": "bx_storage_normalize_storage_path", "label": "normalize_storage_path()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/storage.py", "source_location": "L12"}, {"id": "str", "label": "str", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/storage.py", "source_location": "L12"}, {"id": "bx_storage_upload_bx_file", "label": "upload_bx_file()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/storage.py", "source_location": "L32"}, {"id": "bytes", "label": "bytes", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/storage.py", "source_location": "L32"}, {"id": "bx_storage_get_access_url", "label": "get_access_url()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/storage.py", "source_location": "L45"}, {"id": "bx_storage_get_preview_url", "label": "get_preview_url()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/storage.py", "source_location": "L54"}, {"id": "int", "label": "int", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/storage.py", "source_location": "L54"}, {"id": "bx_storage_get_download_url", "label": "get_download_url()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/storage.py", "source_location": "L69"}, {"id": "bx_storage_download_file_bytes", "label": "download_file_bytes()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/storage.py", "source_location": "L76"}, {"id": "bx_storage_file_stream", "label": "file_stream()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/storage.py", "source_location": "L102"}, {"id": "bytesio", "label": "BytesIO", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/storage.py", "source_location": "L102"}, {"id": "bx_storage_rationale_1", "label": "\u62a5\u9500\u9644\u4ef6\u5b58\u50a8\u9002\u914d \u2014 \u590d\u7528\u95e8\u6237 app.core.storage\uff0c\u5bf9\u5916\u4fdd\u6301 bx \u534f\u8bae\u3002", "file_type": "rationale", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/storage.py", "source_location": "L1"}, {"id": "bx_storage_rationale_13", "label": "\u5c06 upload \u8fd4\u56de\u7684\u5b8c\u6574 URL \u5f52\u4e00\u5316\u4e3a\u5b58\u50a8\u76f8\u5bf9\u8def\u5f84\uff08\u4e0e admin \u9644\u4ef6 upload \u4e00\u81f4\uff09\u3002", "file_type": "rationale", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/storage.py", "source_location": "L13"}, {"id": "bx_storage_rationale_33", "label": "\u4e0a\u4f20\u6587\u4ef6\u5230\u5bf9\u8c61\u5b58\u50a8\u3002 \u8fd4\u56de (relative_path, access_url)\u3002", "file_type": "rationale", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/storage.py", "source_location": "L33"}, {"id": "bx_storage_rationale_46", "label": "\u83b7\u53d6\u53ef\u8bbf\u95ee URL\uff08\u672c\u5730/MinIO \u516c\u5f00\u5730\u5740\uff09\u3002", "file_type": "rationale", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/storage.py", "source_location": "L46"}, {"id": "bx_storage_rationale_55", "label": "\u56fe\u7247/\u9644\u4ef6\u9884\u89c8 URL\uff1aMinIO \u9884\u7b7e\u540d inline\uff0c\u672c\u5730/\u5176\u4ed6\u5b58\u50a8\u7528 get_url\u3002", "file_type": "rationale", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/storage.py", "source_location": "L55"}, {"id": "bx_storage_rationale_70", "label": "\u5e26\u6587\u4ef6\u540d\u7684\u4e0b\u8f7d URL\uff08\u5bf9\u9f50\u95e8\u6237 attachment/download-url\uff09\u3002", "file_type": "rationale", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/storage.py", "source_location": "L70"}, {"id": "bx_storage_rationale_77", "label": "\u8bfb\u53d6\u6587\u4ef6\u4e8c\u8fdb\u5236\uff0c\u4f9b StreamingResponse \u4e0b\u8f7d\u3002", "file_type": "rationale", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/storage.py", "source_location": "L77"}], "edges": [{"source": "users_zlwu_work_00code_shanxia2_0_backend_app_services_bx_storage_py", "target": "datetime", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/storage.py", "source_location": "L4", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_services_bx_storage_py", "target": "io", "relation": "imports_from", "contexLine truncated
|
||||
backend/graphify-out/cache/ast/b30a46c6fab214ca58787ff4e42a9ab2fdf933f1c4b6ee224d1799d9dd8918a6.json
Vendored
+1
@@ -0,0 +1 @@
|
||||
{"nodes": [{"id": "users_zlwu_work_00code_shanxia2_0_backend_app_core_attachment_biz_py", "label": "attachment_biz.py", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/core/attachment_biz.py", "source_location": "L1"}, {"id": "core_attachment_biz_resolve_upload_folder", "label": "resolve_upload_folder()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/core/attachment_biz.py", "source_location": "L19"}, {"id": "str", "label": "str", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/core/attachment_biz.py", "source_location": "L19"}, {"id": "core_attachment_biz_rationale_1", "label": "\u9644\u4ef6\u4e0a\u4f20 bizType \u4e0e MinIO \u76ee\u5f55\u6620\u5c04\uff08\u5bf9\u9f50\u539f CRM oss \u4e0a\u4f20\u8bed\u4e49\uff09", "file_type": "rationale", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/core/attachment_biz.py", "source_location": "L1"}, {"id": "core_attachment_biz_rationale_20", "label": "\u4f18\u5148\u4f7f\u7528\u663e\u5f0f folder\uff1b\u5426\u5219\u6309 bizType \u6620\u5c04\u9ed8\u8ba4\u76ee\u5f55\u3002", "file_type": "rationale", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/core/attachment_biz.py", "source_location": "L20"}], "edges": [{"source": "users_zlwu_work_00code_shanxia2_0_backend_app_core_attachment_biz_py", "target": "core_attachment_biz_resolve_upload_folder", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/core/attachment_biz.py", "source_location": "L19", "weight": 1.0}, {"source": "core_attachment_biz_resolve_upload_folder", "target": "str", "relation": "references", "context": "parameter_type", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/core/attachment_biz.py", "source_location": "L19", "weight": 1.0}, {"source": "core_attachment_biz_resolve_upload_folder", "target": "str", "relation": "references", "context": "parameter_type", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/core/attachment_biz.py", "source_location": "L19", "weight": 1.0}, {"source": "core_attachment_biz_resolve_upload_folder", "target": "str", "relation": "references", "context": "return_type", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/core/attachment_biz.py", "source_location": "L19", "weight": 1.0}, {"source": "core_attachment_biz_rationale_1", "target": "users_zlwu_work_00code_shanxia2_0_backend_app_core_attachment_biz_py", "relation": "rationale_for", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/core/attachment_biz.py", "source_location": "L1", "weight": 1.0}, {"source": "core_attachment_biz_rationale_20", "target": "core_attachment_biz_resolve_upload_folder", "relation": "rationale_for", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/core/attachment_biz.py", "source_location": "L20", "weight": 1.0}], "raw_calls": [{"caller_nid": "core_attachment_biz_resolve_upload_folder", "callee": "strip", "is_member_call": true, "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/core/attachment_biz.py", "source_location": "L21"}, {"caller_nid": "core_attachment_biz_resolve_upload_folder", "callee": "get", "is_member_call": true, "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/core/attachment_biz.py", "source_location": "L24"}, {"caller_nid": "core_attachment_biz_resolve_upload_folder", "callee": "strip", "is_member_call": true, "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/core/attachment_biz.py", "source_location": "L24"}]}
|
||||
backend/graphify-out/cache/ast/b3ed266cefdfc1511b94650b5a8615962585965fd93693d53a04c0e104c8fcf1.json
Vendored
+1
@@ -0,0 +1 @@
|
||||
{"nodes": [{"id": "users_zlwu_work_00code_shanxia2_0_backend_app_api_bx_init_py", "label": "__init__.py", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/__init__.py", "source_location": "L1"}, {"id": "bx_init_bx_health", "label": "bx_health()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/__init__.py", "source_location": "L16"}, {"id": "bx_init_rationale_1", "label": "\u62a5\u9500\uff08bx\uff09API \u8def\u7531\u805a\u5408 \u2014 REST \u98ce\u683c\uff0c\u534f\u8bae\u5bf9\u9f50 bx \u539f\u7cfb\u7edf\u3002", "file_type": "rationale", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/__init__.py", "source_location": "L1"}, {"id": "bx_init_rationale_17", "label": "P0 \u5065\u5eb7\u68c0\u67e5\uff1a\u9a8c\u8bc1 bx \u8def\u7531\u5df2\u6302\u8f7d\u4e14\u54cd\u5e94\u534f\u8bae\u4e3a code=0\u3002", "file_type": "rationale", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/__init__.py", "source_location": "L17"}], "edges": [{"source": "users_zlwu_work_00code_shanxia2_0_backend_app_api_bx_init_py", "target": "fastapi", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/__init__.py", "source_location": "L2", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_api_bx_init_py", "target": "app_api_bx", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/__init__.py", "source_location": "L4", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_api_bx_init_py", "target": "app_schemas_bx_common", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/__init__.py", "source_location": "L5", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_api_bx_init_py", "target": "bx_init_bx_health", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/__init__.py", "source_location": "L16", "weight": 1.0}, {"source": "bx_init_rationale_1", "target": "users_zlwu_work_00code_shanxia2_0_backend_app_api_bx_init_py", "relation": "rationale_for", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/__init__.py", "source_location": "L1", "weight": 1.0}, {"source": "bx_init_rationale_17", "target": "bx_init_bx_health", "relation": "rationale_for", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/__init__.py", "source_location": "L17", "weight": 1.0}], "raw_calls": [{"caller_nid": "bx_init_bx_health", "callee": "ApiResponse", "is_member_call": false, "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/__init__.py", "source_location": "L18"}]}
|
||||
backend/graphify-out/cache/ast/bae2905134b274c819ac7e262771f02012fdd240730c7f78f6694b57b6f35da7.json
Vendored
+1
@@ -0,0 +1 @@
|
||||
{"nodes": [{"id": "users_zlwu_work_00code_shanxia2_0_backend_app_api_bx_workflow_py", "label": "workflow.py", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/workflow.py", "source_location": "L1"}, {"id": "bx_workflow_list_workflows", "label": "list_workflows()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/workflow.py", "source_location": "L22"}, {"id": "int", "label": "int", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/workflow.py", "source_location": "L22"}, {"id": "session", "label": "Session", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/workflow.py", "source_location": "L22"}, {"id": "bxusercontext", "label": "BxUserContext", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/workflow.py", "source_location": "L22"}, {"id": "bx_workflow_get_workflow_by_biz_type", "label": "get_workflow_by_biz_type()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/workflow.py", "source_location": "L36"}, {"id": "str", "label": "str", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/workflow.py", "source_location": "L36"}, {"id": "bx_workflow_get_workflow", "label": "get_workflow()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/workflow.py", "source_location": "L49"}, {"id": "bx_workflow_create_workflow", "label": "create_workflow()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/workflow.py", "source_location": "L62"}, {"id": "workflowdefcreate", "label": "WorkflowDefCreate", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/workflow.py", "source_location": "L62"}, {"id": "bx_workflow_update_workflow", "label": "update_workflow()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/workflow.py", "source_location": "L78"}, {"id": "workflowdefupdate", "label": "WorkflowDefUpdate", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/workflow.py", "source_location": "L78"}, {"id": "bx_workflow_save_workflow_nodes", "label": "save_workflow_nodes()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/workflow.py", "source_location": "L98"}, {"id": "workflownodecreate", "label": "WorkflowNodeCreate", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/workflow.py", "source_location": "L98"}, {"id": "bx_workflow_delete_workflow", "label": "delete_workflow()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/workflow.py", "source_location": "L120"}], "edges": [{"source": "users_zlwu_work_00code_shanxia2_0_backend_app_api_bx_workflow_py", "target": "typing", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/workflow.py", "source_location": "L1", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_api_bx_workflow_py", "target": "fastapi", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/workflow.py", "source_location": "L3", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_api_bx_workflow_py", "target": "sqlalchemy_orm", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/workflow.py", "source_location": "L4", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_api_bx_workflow_py", "target": "app_core_bx_auth", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/workflow.py", "source_location": "L6", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_api_bx_workflow_py", "target": "app_core_database", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/workflow.py", "source_location": "L7", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_api_bx_workflow_py", "target": "app_core_tenant_context", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/workflow.py", "source_location": "L8", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_api_bx_workflow_py", "target": "app_schemas_bx_common", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shaLine truncated
|
||||
backend/graphify-out/cache/ast/c38fd9400bf1c8d181b084347f47bb02e67a6d2ce14a0556284372e4bf044560.json
Vendored
+1
@@ -0,0 +1 @@
|
||||
{"nodes": [{"id": "users_zlwu_work_00code_shanxia2_0_backend_app_schemas_bx_workflow_py", "label": "workflow.py", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/bx/workflow.py", "source_location": "L1"}, {"id": "bx_workflow_coerce_optional_id", "label": "_coerce_optional_id()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/bx/workflow.py", "source_location": "L7"}, {"id": "bx_workflow_workflownodecreate", "label": "WorkflowNodeCreate", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/bx/workflow.py", "source_location": "L13"}, {"id": "basemodel", "label": "BaseModel", "file_type": "code", "source_file": "", "source_location": ""}, {"id": "bx_workflow_workflownodecreate_validate_approver_id", "label": ".validate_approver_id()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/bx/workflow.py", "source_location": "L23"}, {"id": "bx_workflow_workflownodeout", "label": "WorkflowNodeOut", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/bx/workflow.py", "source_location": "L27"}, {"id": "bx_workflow_workflowdefcreate", "label": "WorkflowDefCreate", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/bx/workflow.py", "source_location": "L37"}, {"id": "bx_workflow_workflowdefupdate", "label": "WorkflowDefUpdate", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/bx/workflow.py", "source_location": "L46"}, {"id": "bx_workflow_workflowdefout", "label": "WorkflowDefOut", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/bx/workflow.py", "source_location": "L55"}], "edges": [{"source": "users_zlwu_work_00code_shanxia2_0_backend_app_schemas_bx_workflow_py", "target": "typing", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/bx/workflow.py", "source_location": "L1", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_schemas_bx_workflow_py", "target": "pydantic", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/bx/workflow.py", "source_location": "L3", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_schemas_bx_workflow_py", "target": "pydantic_alias_generators", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/bx/workflow.py", "source_location": "L4", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_schemas_bx_workflow_py", "target": "bx_workflow_coerce_optional_id", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/bx/workflow.py", "source_location": "L7", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_schemas_bx_workflow_py", "target": "bx_workflow_workflownodecreate", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/bx/workflow.py", "source_location": "L13", "weight": 1.0}, {"source": "bx_workflow_workflownodecreate", "target": "basemodel", "relation": "inherits", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/bx/workflow.py", "source_location": "L13", "weight": 1.0}, {"source": "bx_workflow_workflownodecreate", "target": "bx_workflow_workflownodecreate_validate_approver_id", "relation": "method", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/bx/workflow.py", "source_location": "L23", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_schemas_bx_workflow_py", "target": "bx_workflow_workflownodeout", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/bx/workflow.py", "source_location": "L27", "weight": 1.0}, {"source": "bx_workflow_workflownodeout", "target": "basemodel", "relation": "inherits", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/bx/workflow.py", "source_location": "L27", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_schemas_bx_workflow_py", "target": "bx_workflow_workflowdefcreate", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/bx/workflow.py", "source_location": "L37", "weight": 1.0}, {"source": "bx_workflow_workflowdefcreate", "target": "basemodel", "relation": "inherits", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/bx/workflow.py", "sourLine truncated
|
||||
backend/graphify-out/cache/ast/c49d87c90dd0169443162e7d2fc637f739e0c61712ecbeee34a967ae052306a5.json
Vendored
+1
@@ -0,0 +1 @@
|
||||
{"nodes": [{"id": "users_zlwu_work_00code_shanxia2_0_backend_app_services_bx_reimburse_py", "label": "reimburse.py", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/reimburse.py", "source_location": "L1"}, {"id": "bx_reimburse_reimburseservice", "label": "ReimburseService", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/reimburse.py", "source_location": "L31"}, {"id": "bx_reimburse_reimburseservice_tenant_no", "label": "._tenant_no()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/reimburse.py", "source_location": "L33"}, {"id": "session", "label": "Session", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/reimburse.py", "source_location": "L33"}, {"id": "bxusercontext", "label": "BxUserContext", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/reimburse.py", "source_location": "L33"}, {"id": "str", "label": "str", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/reimburse.py", "source_location": "L33"}, {"id": "bx_reimburse_reimburseservice_get_by_id", "label": ".get_by_id()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/reimburse.py", "source_location": "L37"}, {"id": "bxreimburseapply", "label": "BxReimburseApply", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/reimburse.py", "source_location": "L37"}, {"id": "bx_reimburse_reimburseservice_get_paged", "label": ".get_paged()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/reimburse.py", "source_location": "L41"}, {"id": "int", "label": "int", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/reimburse.py", "source_location": "L41"}, {"id": "any", "label": "Any", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/reimburse.py", "source_location": "L41"}, {"id": "bx_reimburse_reimburseservice_soft_delete", "label": ".soft_delete()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/reimburse.py", "source_location": "L51"}, {"id": "bool", "label": "bool", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/reimburse.py", "source_location": "L51"}, {"id": "bx_reimburse_reimburseservice_workflow_nodes", "label": "._workflow_nodes()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/reimburse.py", "source_location": "L58"}, {"id": "bxworkflownode", "label": "BxWorkflowNode", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/reimburse.py", "source_location": "L58"}, {"id": "bx_reimburse_reimburseservice_pending_approval", "label": ".pending_approval()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/reimburse.py", "source_location": "L71"}, {"id": "bx_reimburse_reimburseservice_approved_by_me", "label": ".approved_by_me()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/reimburse.py", "source_location": "L127"}, {"id": "bx_reimburse_reimburseservice_submit", "label": ".submit()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/reimburse.py", "source_location": "L175"}, {"id": "bx_reimburse_reimburseservice_approve", "label": ".approve()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/reimburse.py", "source_location": "L192"}, {"id": "bx_reimburse_reimburseservice_reject", "label": ".reject()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/reimburse.py", "source_location": "L237"}, {"id": "bx_reimburse_reimburseservice_approval_record_dict", "label": "._approval_record_dict()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/reimburse.py", "source_location": "L274"}, {"id": "bxreimburseapproval", "label": "BxReimburseApproval", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/reimburse.py", "source_location": "L274"}, {"id": "bx_reimburse_reimburseservice_latest_approval_per_node", "label": "._latest_approval_per_node()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/reimburse.py", "source_location": "L287"}, {"id": "bx_reimburse_reimburseservice_query_approvals", "label": "._query_approvals()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/reimburse.py", "source_location": "L304"}, {"id": "bx_reimburse_reimburseservice_get_approvLine truncated
|
||||
backend/graphify-out/cache/ast/c9d8d20d9af9ccc1c30f6d7116e7666b53817693f4ab25c01ea451dc46a7f12a.json
Vendored
+1
@@ -0,0 +1 @@
|
||||
{"nodes": [{"id": "users_zlwu_work_00code_shanxia2_0_backend_app_utils_bx_codegen_py", "label": "bx_codegen.py", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/utils/bx_codegen.py", "source_location": "L1"}, {"id": "utils_bx_codegen_generate_apply_code", "label": "generate_apply_code()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/utils/bx_codegen.py", "source_location": "L8"}, {"id": "session", "label": "Session", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/utils/bx_codegen.py", "source_location": "L8"}, {"id": "str", "label": "str", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/utils/bx_codegen.py", "source_location": "L8"}, {"id": "utils_bx_codegen_generate_title", "label": "generate_title()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/utils/bx_codegen.py", "source_location": "L33"}, {"id": "utils_bx_codegen_rationale_1", "label": "\u62a5\u9500\u5355\u53f7/\u6807\u9898\u751f\u6210\uff08\u4ece bx-backend \u8fc1\u79fb\uff0c\u589e\u52a0 tenant_no \u9694\u79bb\uff09\u3002", "file_type": "rationale", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/utils/bx_codegen.py", "source_location": "L1"}, {"id": "utils_bx_codegen_rationale_9", "label": "\u751f\u6210\u987a\u5e8f\u5355\u53f7\uff1a{prefix}{YYYYMMDD}{3\u4f4d\u5e8f\u53f7}\u3002 prefix \u793a\u4f8b\uff1aBYJ\uff08\u5907\u7528\u91d1\uff09\u3001BX\uff08\u62a5\u9500\uff09\u3002", "file_type": "rationale", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/utils/bx_codegen.py", "source_location": "L9"}], "edges": [{"source": "users_zlwu_work_00code_shanxia2_0_backend_app_utils_bx_codegen_py", "target": "datetime", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/utils/bx_codegen.py", "source_location": "L2", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_utils_bx_codegen_py", "target": "sqlalchemy", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/utils/bx_codegen.py", "source_location": "L4", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_utils_bx_codegen_py", "target": "sqlalchemy_orm", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/utils/bx_codegen.py", "source_location": "L5", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_utils_bx_codegen_py", "target": "utils_bx_codegen_generate_apply_code", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/utils/bx_codegen.py", "source_location": "L8", "weight": 1.0}, {"source": "utils_bx_codegen_generate_apply_code", "target": "session", "relation": "references", "context": "parameter_type", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/utils/bx_codegen.py", "source_location": "L8", "weight": 1.0}, {"source": "utils_bx_codegen_generate_apply_code", "target": "str", "relation": "references", "context": "parameter_type", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/utils/bx_codegen.py", "source_location": "L8", "weight": 1.0}, {"source": "utils_bx_codegen_generate_apply_code", "target": "str", "relation": "references", "context": "parameter_type", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/utils/bx_codegen.py", "source_location": "L8", "weight": 1.0}, {"source": "utils_bx_codegen_generate_apply_code", "target": "str", "relation": "references", "context": "return_type", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/utils/bx_codegen.py", "source_location": "L8", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_utils_bx_codegen_py", "target": "utils_bx_codegen_generate_title", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/utils/bx_codegen.py", "source_location": "L33", "weight": 1.0}, {"source": "utils_bx_codegen_generate_title", "target": "session", "relation": "references", "context": "parameter_type", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/utils/bx_codegen.py", "source_location": "L33", "weight": 1.0}, {"source": "utils_bx_codegen_generate_title", "target": "str", "relation": "references", "context": "parameter_type", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/utils/bx_codegen.py", "source_location": "L33", "weight": 1.0}, {"source": "utils_bx_codegen_generate_title", "target": "str", "relation": "references", "context": "parameLine truncated
|
||||
backend/graphify-out/cache/ast/d6aa4d137ee5f96962ddc7c35a719aa658338f13ccbd378d35758fa73d76de70.json
Vendored
+1
@@ -0,0 +1 @@
|
||||
{"nodes": [{"id": "users_zlwu_work_00code_shanxia2_0_backend_app_schemas_bx_reimburse_py", "label": "reimburse.py", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/bx/reimburse.py", "source_location": "L1"}, {"id": "bx_reimburse_coerce_id", "label": "_coerce_id()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/bx/reimburse.py", "source_location": "L9"}, {"id": "bx_reimburse_reimbursedetailcreate", "label": "ReimburseDetailCreate", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/bx/reimburse.py", "source_location": "L15"}, {"id": "basemodel", "label": "BaseModel", "file_type": "code", "source_file": "", "source_location": ""}, {"id": "bx_reimburse_reimbursedetailcreate_validate_expense_item_id", "label": ".validate_expense_item_id()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/bx/reimburse.py", "source_location": "L24"}, {"id": "bx_reimburse_reimbursedetailout", "label": "ReimburseDetailOut", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/bx/reimburse.py", "source_location": "L31"}, {"id": "bx_reimburse_reimburseapplycreate", "label": "ReimburseApplyCreate", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/bx/reimburse.py", "source_location": "L41"}, {"id": "bx_reimburse_reimburseapplycreate_details_must_not_be_empty", "label": ".details_must_not_be_empty()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/bx/reimburse.py", "source_location": "L50"}, {"id": "bx_reimburse_reimburseapplyupdate", "label": "ReimburseApplyUpdate", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/bx/reimburse.py", "source_location": "L56"}, {"id": "bx_reimburse_reimburseapplyout", "label": "ReimburseApplyOut", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/bx/reimburse.py", "source_location": "L63"}, {"id": "bx_reimburse_reimburseapprovalcreate", "label": "ReimburseApprovalCreate", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/bx/reimburse.py", "source_location": "L89"}, {"id": "bx_reimburse_reimburseapprovalout", "label": "ReimburseApprovalOut", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/bx/reimburse.py", "source_location": "L96"}, {"id": "bx_reimburse_reimbursemystatsout", "label": "ReimburseMyStatsOut", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/bx/reimburse.py", "source_location": "L109"}, {"id": "bx_reimburse_reimburseapproverpendingstatsout", "label": "ReimburseApproverPendingStatsOut", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/bx/reimburse.py", "source_location": "L121"}, {"id": "bx_reimburse_payrequest", "label": "PayRequest", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/bx/reimburse.py", "source_location": "L128"}, {"id": "bx_reimburse_offsetrequest", "label": "OffsetRequest", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/bx/reimburse.py", "source_location": "L135"}, {"id": "bx_reimburse_offsetrequest_validate_advance_id", "label": ".validate_advance_id()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/bx/reimburse.py", "source_location": "L144"}, {"id": "bx_reimburse_offsetitem", "label": "OffsetItem", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/bx/reimburse.py", "source_location": "L151"}, {"id": "bx_reimburse_offsetitem_validate_advance_id", "label": ".validate_advance_id()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/bx/reimburse.py", "source_location": "L159"}, {"id": "bx_reimburse_batchoffsetrequest", "label": "BatchOffsetRequest", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/bx/reimburse.py", "source_location": "L166"}, {"id": "bx_reimburse_reimburseoffsetrecordout", "label": "ReimburseOffsetRecordOut", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/bx/reimburse.py", "source_location": "L174"}, {"id": "bx_reimburse_paymentfinancestatsout", "label": "PaymentFinanceStatsOut", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/bx/reimburse.py", "source_location": "L187"}], "edges": [{"source": "users_zlwu_work_00code_shanxia2_0_backend_app_schemas_bx_reimburse_py", "target": "typing", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/bx/reimburse.py", "source_location": "L1"Line truncated
|
||||
backend/graphify-out/cache/ast/db3a00f89c6343929dbbd1cf5891821fea7670d9630a83ef826da3b7abddc596.json
Vendored
+1
@@ -0,0 +1 @@
|
||||
{"nodes": [{"id": "users_zlwu_work_00code_shanxia2_0_backend_app_api_bx_reimburse_py", "label": "reimburse.py", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/reimburse.py", "source_location": "L1"}, {"id": "bx_reimburse_tenant", "label": "_tenant()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/reimburse.py", "source_location": "L29"}, {"id": "session", "label": "Session", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/reimburse.py", "source_location": "L29"}, {"id": "bxusercontext", "label": "BxUserContext", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/reimburse.py", "source_location": "L29"}, {"id": "str", "label": "str", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/reimburse.py", "source_location": "L29"}, {"id": "bx_reimburse_build_details_data", "label": "_build_details_data()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/reimburse.py", "source_location": "L33"}, {"id": "bx_reimburse_get_generated_title", "label": "get_generated_title()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/reimburse.py", "source_location": "L54"}, {"id": "bx_reimburse_list_reimburses", "label": "list_reimburses()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/reimburse.py", "source_location": "L64"}, {"id": "int", "label": "int", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/reimburse.py", "source_location": "L64"}, {"id": "bx_reimburse_my_reimburses", "label": "my_reimburses()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/reimburse.py", "source_location": "L101"}, {"id": "bx_reimburse_my_reimburse_stats", "label": "my_reimburse_stats()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/reimburse.py", "source_location": "L137"}, {"id": "bx_reimburse_reimburse_status_counts", "label": "reimburse_status_counts()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/reimburse.py", "source_location": "L147"}, {"id": "bx_reimburse_pending_approval", "label": "pending_approval()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/reimburse.py", "source_location": "L156"}, {"id": "bx_reimburse_pending_approval_stats", "label": "pending_approval_stats()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/reimburse.py", "source_location": "L182"}, {"id": "bx_reimburse_approved_by_me", "label": "approved_by_me()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/reimburse.py", "source_location": "L192"}, {"id": "bx_reimburse_get_reimburse", "label": "get_reimburse()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/reimburse.py", "source_location": "L218"}, {"id": "bx_reimburse_get_approvals", "label": "get_approvals()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/reimburse.py", "source_location": "L232"}, {"id": "bx_reimburse_get_approval_history", "label": "get_approval_history()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/reimburse.py", "source_location": "L245"}, {"id": "bx_reimburse_create_reimburse", "label": "create_reimburse()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/reimburse.py", "source_location": "L258"}, {"id": "reimburseapplycreate", "label": "ReimburseApplyCreate", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/reimburse.py", "source_location": "L258"}, {"id": "bx_reimburse_update_reimburse", "label": "update_reimburse()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/reimburse.py", "source_location": "L291"}, {"id": "reimburseapplyupdate", "label": "ReimburseApplyUpdate", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/reimburse.py", "source_location": "L291"}, {"id": "bx_reimburse_submit_reimburse", "label": "submit_reimburse()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/reimburse.py", "source_location": "L316"}, {"id": "bx_reimburse_approve_reimburse", "label": "approve_reimburse()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/reimburse.py", "source_location": "L331"}, {"id": "reimburseapprovalcreate", "label": "ReimburseApprovalCreate", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/reimburse.py", "source_locatiLine truncated
|
||||
backend/graphify-out/cache/ast/dc0691cec4589587fdbacf2dbc9334e3a99face5e924b7ead29b3531d7752c5d.json
Vendored
+1
@@ -0,0 +1 @@
|
||||
{"nodes": [{"id": "users_zlwu_work_00code_shanxia2_0_backend_app_api_bx_workflow_py", "label": "workflow.py", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/workflow.py", "source_location": "L1"}, {"id": "bx_workflow_list_workflows", "label": "list_workflows()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/workflow.py", "source_location": "L22"}, {"id": "int", "label": "int", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/workflow.py", "source_location": "L22"}, {"id": "session", "label": "Session", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/workflow.py", "source_location": "L22"}, {"id": "bxusercontext", "label": "BxUserContext", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/workflow.py", "source_location": "L22"}, {"id": "bx_workflow_get_workflow_by_biz_type", "label": "get_workflow_by_biz_type()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/workflow.py", "source_location": "L36"}, {"id": "str", "label": "str", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/workflow.py", "source_location": "L36"}, {"id": "bx_workflow_get_workflow", "label": "get_workflow()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/workflow.py", "source_location": "L48"}, {"id": "bx_workflow_create_workflow", "label": "create_workflow()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/workflow.py", "source_location": "L61"}, {"id": "workflowdefcreate", "label": "WorkflowDefCreate", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/workflow.py", "source_location": "L61"}, {"id": "bx_workflow_update_workflow", "label": "update_workflow()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/workflow.py", "source_location": "L77"}, {"id": "workflowdefupdate", "label": "WorkflowDefUpdate", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/workflow.py", "source_location": "L77"}, {"id": "bx_workflow_save_workflow_nodes", "label": "save_workflow_nodes()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/workflow.py", "source_location": "L97"}, {"id": "workflownodecreate", "label": "WorkflowNodeCreate", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/workflow.py", "source_location": "L97"}, {"id": "bx_workflow_delete_workflow", "label": "delete_workflow()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/workflow.py", "source_location": "L119"}], "edges": [{"source": "users_zlwu_work_00code_shanxia2_0_backend_app_api_bx_workflow_py", "target": "typing", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/workflow.py", "source_location": "L1", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_api_bx_workflow_py", "target": "fastapi", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/workflow.py", "source_location": "L3", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_api_bx_workflow_py", "target": "sqlalchemy_orm", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/workflow.py", "source_location": "L4", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_api_bx_workflow_py", "target": "app_core_bx_auth", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/workflow.py", "source_location": "L6", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_api_bx_workflow_py", "target": "app_core_database", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/workflow.py", "source_location": "L7", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_api_bx_workflow_py", "target": "app_core_tenant_context", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/workflow.py", "source_location": "L8", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_api_bx_workflow_py", "target": "app_schemas_bx_common", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shaLine truncated
|
||||
backend/graphify-out/cache/ast/df44e578fdf20815ad4dcda2476e44a82171dbd0dde03791233ff1f8bcf59f8d.json
Vendored
+1
@@ -0,0 +1 @@
|
||||
{"nodes": [{"id": "users_zlwu_work_00code_shanxia2_0_backend_app_services_bx_reimburse_py", "label": "reimburse.py", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/reimburse.py", "source_location": "L1"}, {"id": "bx_reimburse_reimburseservice", "label": "ReimburseService", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/reimburse.py", "source_location": "L29"}, {"id": "bx_reimburse_reimburseservice_tenant_no", "label": "._tenant_no()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/reimburse.py", "source_location": "L31"}, {"id": "session", "label": "Session", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/reimburse.py", "source_location": "L31"}, {"id": "bxusercontext", "label": "BxUserContext", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/reimburse.py", "source_location": "L31"}, {"id": "str", "label": "str", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/reimburse.py", "source_location": "L31"}, {"id": "bx_reimburse_reimburseservice_get_by_id", "label": ".get_by_id()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/reimburse.py", "source_location": "L35"}, {"id": "bxreimburseapply", "label": "BxReimburseApply", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/reimburse.py", "source_location": "L35"}, {"id": "bx_reimburse_reimburseservice_get_paged", "label": ".get_paged()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/reimburse.py", "source_location": "L39"}, {"id": "int", "label": "int", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/reimburse.py", "source_location": "L39"}, {"id": "any", "label": "Any", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/reimburse.py", "source_location": "L39"}, {"id": "bx_reimburse_reimburseservice_soft_delete", "label": ".soft_delete()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/reimburse.py", "source_location": "L49"}, {"id": "bool", "label": "bool", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/reimburse.py", "source_location": "L49"}, {"id": "bx_reimburse_reimburseservice_workflow_nodes", "label": "._workflow_nodes()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/reimburse.py", "source_location": "L56"}, {"id": "bxworkflownode", "label": "BxWorkflowNode", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/reimburse.py", "source_location": "L56"}, {"id": "bx_reimburse_reimburseservice_pending_approval", "label": ".pending_approval()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/reimburse.py", "source_location": "L69"}, {"id": "bx_reimburse_reimburseservice_approved_by_me", "label": ".approved_by_me()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/reimburse.py", "source_location": "L125"}, {"id": "bx_reimburse_reimburseservice_submit", "label": ".submit()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/reimburse.py", "source_location": "L173"}, {"id": "bx_reimburse_reimburseservice_approve", "label": ".approve()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/reimburse.py", "source_location": "L190"}, {"id": "bx_reimburse_reimburseservice_reject", "label": ".reject()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/reimburse.py", "source_location": "L235"}, {"id": "bx_reimburse_reimburseservice_get_approvals", "label": ".get_approvals()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/reimburse.py", "source_location": "L272"}, {"id": "bx_reimburse_reimburseservice_create_with_details", "label": ".create_with_details()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/reimburse.py", "source_location": "L324"}, {"id": "bx_reimburse_reimburseservice_update_with_details", "label": ".update_with_details()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/reimburse.py", "source_location": "L370"}, {"id": "bx_reimburse_reimburseservice_get_details", "label": ".get_details()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/reimburse.py", "source_location": "L423"}, {"id": "bxreimbursedetail", "label": "BxReimburseDLine truncated
|
||||
backend/graphify-out/cache/ast/e1776f2969dc96ebcd5a775ec67f445c75c51b2c0bcf6a0f60df96337b61aaf8.json
Vendored
+1
@@ -0,0 +1 @@
|
||||
{"nodes": [{"id": "users_zlwu_work_00code_shanxia2_0_backend_app_services_bx_workflow_py", "label": "workflow.py", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/workflow.py", "source_location": "L1"}, {"id": "bx_workflow_workflowservice", "label": "WorkflowService", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/workflow.py", "source_location": "L14"}, {"id": "bx_workflow_workflowservice_tenant_no", "label": "._tenant_no()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/workflow.py", "source_location": "L16"}, {"id": "session", "label": "Session", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/workflow.py", "source_location": "L16"}, {"id": "bxusercontext", "label": "BxUserContext", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/workflow.py", "source_location": "L16"}, {"id": "str", "label": "str", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/workflow.py", "source_location": "L16"}, {"id": "bx_workflow_workflowservice_get_by_id", "label": ".get_by_id()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/workflow.py", "source_location": "L20"}, {"id": "bxworkflowdef", "label": "BxWorkflowDef", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/workflow.py", "source_location": "L20"}, {"id": "bx_workflow_workflowservice_get_paged", "label": ".get_paged()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/workflow.py", "source_location": "L24"}, {"id": "int", "label": "int", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/workflow.py", "source_location": "L24"}, {"id": "bx_workflow_workflowservice_create", "label": ".create()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/workflow.py", "source_location": "L33"}, {"id": "bx_workflow_workflowservice_update", "label": ".update()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/workflow.py", "source_location": "L50"}, {"id": "bx_workflow_workflowservice_soft_delete", "label": ".soft_delete()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/workflow.py", "source_location": "L68"}, {"id": "bool", "label": "bool", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/workflow.py", "source_location": "L68"}, {"id": "bx_workflow_workflowservice_get_by_biz_type", "label": ".get_by_biz_type()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/workflow.py", "source_location": "L82"}, {"id": "bx_workflow_workflowservice_save_nodes", "label": ".save_nodes()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/workflow.py", "source_location": "L94"}, {"id": "bxworkflownode", "label": "BxWorkflowNode", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/workflow.py", "source_location": "L94"}], "edges": [{"source": "users_zlwu_work_00code_shanxia2_0_backend_app_services_bx_workflow_py", "target": "typing", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/workflow.py", "source_location": "L3", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_services_bx_workflow_py", "target": "sqlalchemy_orm", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/workflow.py", "source_location": "L5", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_services_bx_workflow_py", "target": "app_core_bx_auth", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/workflow.py", "source_location": "L7", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_services_bx_workflow_py", "target": "app_core_tenant_context", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/workflow.py", "source_location": "L8", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_services_bx_workflow_py", "target": "app_core_utils", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/workflow.py", "source_location": "L9", "weight": 1.0}, {"source": "uLine truncated
|
||||
backend/graphify-out/cache/ast/e591563b9a6f84fb8f07bb4fcceac592d711c6ff85fce7cc83b000977f06b9e6.json
Vendored
+1
@@ -0,0 +1 @@
|
||||
{"nodes": [{"id": "users_zlwu_work_00code_shanxia2_0_backend_app_services_bx_advance_py", "label": "advance.py", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/advance.py", "source_location": "L1"}, {"id": "bx_advance_advanceservice", "label": "AdvanceService", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/advance.py", "source_location": "L24"}, {"id": "bx_advance_advanceservice_tenant_no", "label": "._tenant_no()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/advance.py", "source_location": "L26"}, {"id": "session", "label": "Session", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/advance.py", "source_location": "L26"}, {"id": "bxusercontext", "label": "BxUserContext", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/advance.py", "source_location": "L26"}, {"id": "str", "label": "str", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/advance.py", "source_location": "L26"}, {"id": "bx_advance_advanceservice_get_by_id", "label": ".get_by_id()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/advance.py", "source_location": "L30"}, {"id": "bxadvanceapply", "label": "BxAdvanceApply", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/advance.py", "source_location": "L30"}, {"id": "bx_advance_advanceservice_get_paged", "label": ".get_paged()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/advance.py", "source_location": "L34"}, {"id": "int", "label": "int", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/advance.py", "source_location": "L34"}, {"id": "any", "label": "Any", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/advance.py", "source_location": "L34"}, {"id": "bx_advance_advanceservice_create", "label": ".create()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/advance.py", "source_location": "L44"}, {"id": "bx_advance_advanceservice_update", "label": ".update()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/advance.py", "source_location": "L61"}, {"id": "bx_advance_advanceservice_soft_delete", "label": ".soft_delete()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/advance.py", "source_location": "L79"}, {"id": "bool", "label": "bool", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/advance.py", "source_location": "L79"}, {"id": "bx_advance_advanceservice_pending_approval", "label": ".pending_approval()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/advance.py", "source_location": "L86"}, {"id": "bx_advance_advanceservice_approved_by_me", "label": ".approved_by_me()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/advance.py", "source_location": "L142"}, {"id": "bx_advance_advanceservice_workflow_nodes", "label": "._workflow_nodes()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/advance.py", "source_location": "L190"}, {"id": "bxworkflownode", "label": "BxWorkflowNode", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/advance.py", "source_location": "L190"}, {"id": "bx_advance_advanceservice_submit", "label": ".submit()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/advance.py", "source_location": "L203"}, {"id": "bx_advance_advanceservice_approve", "label": ".approve()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/advance.py", "source_location": "L220"}, {"id": "bx_advance_advanceservice_reject", "label": ".reject()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/advance.py", "source_location": "L265"}, {"id": "bx_advance_advanceservice_get_approvals", "label": ".get_approvals()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/advance.py", "source_location": "L302"}, {"id": "bx_advance_advanceservice_global_status_counts", "label": ".global_status_counts()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/advance.py", "source_location": "L354"}, {"id": "bx_advance_advanceservice_my_apply_stats", "label": ".my_apply_stats()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/advance.py", "source_locaLine truncated
|
||||
backend/graphify-out/cache/ast/eb032c84478721c937c421e8cf457716875a593a75c15caa07adec83c80f8b3b.json
Vendored
+1
@@ -0,0 +1 @@
|
||||
{"nodes": [{"id": "users_zlwu_work_00code_shanxia2_0_backend_app_api_bx_expense_item_py", "label": "expense_item.py", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/expense_item.py", "source_location": "L1"}, {"id": "bx_expense_item_get_expense_item_tree", "label": "get_expense_item_tree()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/expense_item.py", "source_location": "L17"}, {"id": "session", "label": "Session", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/expense_item.py", "source_location": "L17"}, {"id": "bxusercontext", "label": "BxUserContext", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/expense_item.py", "source_location": "L17"}, {"id": "bx_expense_item_get_expense_item", "label": "get_expense_item()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/expense_item.py", "source_location": "L27"}, {"id": "str", "label": "str", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/expense_item.py", "source_location": "L27"}, {"id": "bx_expense_item_create_expense_item", "label": "create_expense_item()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/expense_item.py", "source_location": "L40"}, {"id": "expenseitemcreate", "label": "ExpenseItemCreate", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/expense_item.py", "source_location": "L40"}, {"id": "bx_expense_item_update_expense_item", "label": "update_expense_item()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/expense_item.py", "source_location": "L56"}, {"id": "expenseitemupdate", "label": "ExpenseItemUpdate", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/expense_item.py", "source_location": "L56"}, {"id": "bx_expense_item_delete_expense_item", "label": "delete_expense_item()", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/expense_item.py", "source_location": "L77"}], "edges": [{"source": "users_zlwu_work_00code_shanxia2_0_backend_app_api_bx_expense_item_py", "target": "typing", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/expense_item.py", "source_location": "L1", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_api_bx_expense_item_py", "target": "fastapi", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/expense_item.py", "source_location": "L3", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_api_bx_expense_item_py", "target": "sqlalchemy_orm", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/expense_item.py", "source_location": "L4", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_api_bx_expense_item_py", "target": "app_core_bx_auth", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/expense_item.py", "source_location": "L6", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_api_bx_expense_item_py", "target": "app_core_database", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/expense_item.py", "source_location": "L7", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_api_bx_expense_item_py", "target": "app_core_tenant_context", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/expense_item.py", "source_location": "L8", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_api_bx_expense_item_py", "target": "app_schemas_bx_common", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/expense_item.py", "source_location": "L9", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_api_bx_expense_item_py", "target": "app_schemas_bx_expense_item", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/expense_item.py", "source_location": "L10", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_api_bx_expense_item_py", "target": "app_services_bx_expense_item", "relation": "imports_from", "context": "import", "confidence": "EXTRACLine truncated
|
||||
backend/graphify-out/cache/ast/f287214c72345e41d9d122ca55b4d3e279635d99cbf10ed530de0ac32374f31c.json
Vendored
+1
@@ -0,0 +1 @@
|
||||
{"nodes": [{"id": "users_zlwu_work_00code_shanxia2_0_backend_app_schemas_bx_attachment_py", "label": "attachment.py", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/bx/attachment.py", "source_location": "L1"}, {"id": "bx_attachment_attachmentout", "label": "AttachmentOut", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/bx/attachment.py", "source_location": "L9"}, {"id": "basemodel", "label": "BaseModel", "file_type": "code", "source_file": "", "source_location": ""}], "edges": [{"source": "users_zlwu_work_00code_shanxia2_0_backend_app_schemas_bx_attachment_py", "target": "typing", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/bx/attachment.py", "source_location": "L1", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_schemas_bx_attachment_py", "target": "pydantic", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/bx/attachment.py", "source_location": "L3", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_schemas_bx_attachment_py", "target": "pydantic_alias_generators", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/bx/attachment.py", "source_location": "L4", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_schemas_bx_attachment_py", "target": "app_schemas_bx_common", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/bx/attachment.py", "source_location": "L6", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_schemas_bx_attachment_py", "target": "bx_attachment_attachmentout", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/bx/attachment.py", "source_location": "L9", "weight": 1.0}, {"source": "bx_attachment_attachmentout", "target": "basemodel", "relation": "inherits", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/bx/attachment.py", "source_location": "L9", "weight": 1.0}], "raw_calls": []}
|
||||
backend/graphify-out/cache/ast/fe31dec3025948c4a34c5543e8ff1eeedca90c843821b8a2aa3aecedd04b188b.json
Vendored
+1
@@ -0,0 +1 @@
|
||||
{"nodes": [{"id": "users_zlwu_work_00code_shanxia2_0_backend_app_models_bx_models_py", "label": "bx_models.py", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/models/bx_models.py", "source_location": "L1"}, {"id": "models_bx_models_bxexpenseitem", "label": "BxExpenseItem", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/models/bx_models.py", "source_location": "L10"}, {"id": "base", "label": "Base", "file_type": "code", "source_file": "", "source_location": ""}, {"id": "models_bx_models_bxworkflowdef", "label": "BxWorkflowDef", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/models/bx_models.py", "source_location": "L33"}, {"id": "models_bx_models_bxworkflownode", "label": "BxWorkflowNode", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/models/bx_models.py", "source_location": "L61"}, {"id": "models_bx_models_bxadvanceapply", "label": "BxAdvanceApply", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/models/bx_models.py", "source_location": "L85"}, {"id": "models_bx_models_bxadvanceapproval", "label": "BxAdvanceApproval", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/models/bx_models.py", "source_location": "L118"}, {"id": "models_bx_models_bxreimburseapply", "label": "BxReimburseApply", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/models/bx_models.py", "source_location": "L141"}, {"id": "models_bx_models_bxreimbursedetail", "label": "BxReimburseDetail", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/models/bx_models.py", "source_location": "L177"}, {"id": "models_bx_models_bxreimburseapproval", "label": "BxReimburseApproval", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/models/bx_models.py", "source_location": "L198"}, {"id": "models_bx_models_bxreimburseoffset", "label": "BxReimburseOffset", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/models/bx_models.py", "source_location": "L221"}, {"id": "models_bx_models_bxattachment", "label": "BxAttachment", "file_type": "code", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/models/bx_models.py", "source_location": "L239"}, {"id": "models_bx_models_rationale_1", "label": "\u62a5\u9500\uff08bx\uff09\u6a21\u5757\u6570\u636e\u6a21\u578b \u2014 \u5bf9\u9f50 docs/sql/20260606_bx_tables.sql", "file_type": "rationale", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/models/bx_models.py", "source_location": "L1"}], "edges": [{"source": "users_zlwu_work_00code_shanxia2_0_backend_app_models_bx_models_py", "target": "datetime", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/models/bx_models.py", "source_location": "L2", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_models_bx_models_py", "target": "sqlalchemy", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/models/bx_models.py", "source_location": "L4", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_models_bx_models_py", "target": "sqlalchemy_orm", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/models/bx_models.py", "source_location": "L5", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_models_bx_models_py", "target": "app_core_database", "relation": "imports_from", "context": "import", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/models/bx_models.py", "source_location": "L7", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_models_bx_models_py", "target": "models_bx_models_bxexpenseitem", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/models/bx_models.py", "source_location": "L10", "weight": 1.0}, {"source": "models_bx_models_bxexpenseitem", "target": "base", "relation": "inherits", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/models/bx_models.py", "source_location": "L10", "weight": 1.0}, {"source": "users_zlwu_work_00code_shanxia2_0_backend_app_models_bx_models_py", "target": "models_bx_models_bxworkflowdef", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/models/bx_models.py", "source_location": "L33", "weight": 1.0}, {"source": "models_bx_models_bxworkflowdef", "target": "base", "relation": "inherits", "confidence": "EXTRACTED", "source_file": "/Users/zlwu/work/00code/shanxia2.0/backend/app/models/bx_models.py", "source_location":Line truncated
|
||||
+1
-1
@@ -1 +1 @@
|
||||
{"/Users/zlwu/work/00code/shanxia2.0/backend/start-prod.sh":{"size":5362,"mtime_ns":1780108930820143914,"hash":"712114b9a96e370660a7d8455b0cb014b6387a352e25c114bb396bc9815d48e6"},"/Users/zlwu/work/00code/shanxia2.0/backend/start.sh":{"size":9548,"mtime_ns":1780114661446983244,"hash":"4d632863e8a0cd81194b491d83a0218a4157435ae812dec76a6f6197b4d48e57"},"/Users/zlwu/work/00code/shanxia2.0/backend/app/__init__.py":{"size":21,"mtime_ns":1780113982281973984,"hash":"60a04ff08fd97084e83ea809fd13feda6d2848be20ebf309e31fc1dad7523230"},"/Users/zlwu/work/00code/shanxia2.0/backend/app/main.py":{"size":4532,"mtime_ns":1780201410113131199,"hash":"276f225cb323016de117038efef175f4e91a9474bced64b43dc0ea4bd976b057"},"/Users/zlwu/work/00code/shanxia2.0/backend/app/tasks/__init__.py":{"size":1634,"mtime_ns":1780201410115316494,"hash":"9ee508b67da0044015aff95ebddaf52a5ba551ccfee772bf134ca88e2d482e72"},"/Users/zlwu/work/00code/shanxia2.0/backend/app/core/auth.py":{"size":8744,"mtime_ns":1780201410112435240,"hash":"df84858ae3cea547e5ae0174a2ee76cd4df8835f4b75827843369e74ea91098b"},"/Users/zlwu/work/00code/shanxia2.0/backend/app/core/api_crypto.py":{"size":1870,"mtime_ns":1780108930724444498,"hash":"c04b748aea86890a5971f749523c7b17dbad1ddd6f9f7f07a5679d159c984e33"},"/Users/zlwu/work/00code/shanxia2.0/backend/app/core/login_crypto.py":{"size":3858,"mtime_ns":1780108930725155710,"hash":"b82d51afabf2293a9cb1fb2e5f994c383948e7f47ea95fe674686b4f3f3342b1"},"/Users/zlwu/work/00code/shanxia2.0/backend/app/core/config.py":{"size":5505,"mtime_ns":1780131767561871048,"hash":"bd8940c34f0feef909d268e6af9fee67705b0a95eae4906ca82e712097e20748"},"/Users/zlwu/work/00code/shanxia2.0/backend/app/core/wechat_pay.py":{"size":23585,"mtime_ns":1780108930725768130,"hash":"3d52265ce65d21e7103f94afa1e8547aee0823b5ea6d65c50317436ac81fb4fc"},"/Users/zlwu/work/00code/shanxia2.0/backend/app/core/api_request_log_middleware.py":{"size":8978,"mtime_ns":1780108930724617124,"hash":"198e0861bb9933a7cee510524c4802001543468727a45e779bc4684d0214ffe2"},"/Users/zlwu/work/00code/shanxia2.0/backend/app/core/database.py":{"size":1173,"mtime_ns":1780108930724965209,"hash":"8c45b5a56110164f2488c9c8db27db62fe77f0997cf22c53991c0bd1dde2043a"},"/Users/zlwu/work/00code/shanxia2.0/backend/app/core/security.py":{"size":728,"mtime_ns":1780108930725470004,"hash":"df0f01115064f7b8de1c81dbe9a6db39360c236610b68c33b3234a51d7f0025b"},"/Users/zlwu/work/00code/shanxia2.0/backend/app/core/request_payload.py":{"size":2842,"mtime_ns":1780108930725350836,"hash":"e9937151530ab1417ef297aef59111977725cf90be2a8fa76c00a0618789aba0"},"/Users/zlwu/work/00code/shanxia2.0/backend/app/core/__init__.py":{"size":61,"mtime_ns":1780108930724312414,"hash":"3dd1842ee59b0c804176b03b4b8a323bd4a252b7feb1bbc32db64f3a8928570e"},"/Users/zlwu/work/00code/shanxia2.0/backend/app/core/response.py":{"size":1824,"mtime_ns":1780108930725412462,"hash":"f1739352d65ea8287d76e282a59553aa8d63c97e35764c64ac378aa5bd9c347e"},"/Users/zlwu/work/00code/shanxia2.0/backend/app/core/menu_guard.py":{"size":1611,"mtime_ns":1780108930725223002,"hash":"3e26077288c3620a4780038b891a326206b45bffe00aca545bdae30172487235"},"/Users/zlwu/work/00code/shanxia2.0/backend/app/core/db_collation.py":{"size":548,"mtime_ns":1780108930725025043,"hash":"0c680e25a18244ca839a7de6ed1f4313b33bc8da118d89c463aee1b6af00c6f9"},"/Users/zlwu/work/00code/shanxia2.0/backend/app/core/context.py":{"size":421,"mtime_ns":1780108930724824458,"hash":"83a10aee67162374993c10a30bf8bb8bd9c4b35cf48f42c832415ccebd91660f"},"/Users/zlwu/work/00code/shanxia2.0/backend/app/core/utils.py":{"size":1498,"mtime_ns":1780108930725607296,"hash":"09323693661c1d4560458b86a954128ccff82bbaf6522da0b44f24da99ddf9ea"},"/Users/zlwu/work/00code/shanxia2.0/backend/app/core/storage.py":{"size":13209,"mtime_ns":1780108930725541087,"hash":"c3138253eb34f65b09f4436e037fb3179d947f84d3b5fef007ed9a8e3bb135ee"},"/Users/zlwu/work/00code/shanxia2.0/backend/app/core/order_status_compat.py":{"size":2828,"mtime_ns":1780108930725284669,"hash":"5349e5a0745ee6734c4a995337779307adefc46f453906171988a77de2081540"},"/Users/zlwu/work/00code/shanxia2.0/backend/app/core/exceptions.py":{"size":4946,"mtime_ns":1780108930725084335,"hash":"79c997d964bca1a4f12f2b92fb1f181fdb9e2b3cf72eae39f4cc164d23794fd7"},"/Users/zlwu/work/00code/shanxia2.0/backend/app/core/data_scope.py":{"size":5949,"mtime_ns":1780108930724890709,"hash":"c92a7dbcfe3d7440bfafc83a76e9ed431e2b054ddd95bc4bfac52b241635ab17"},"/Users/zlwu/work/00code/shanxia2.0/backend/app/core/admin_request_json.py":{"size":2669,"mtime_ns":1780108930724378914,"hash":"4f68b3cf84291e7bddad6ecf4bb4d29ca5e1ec246a9f7f9c4cf5909d0ec1174a"},"/Users/zlwu/work/00code/shanxia2.0/backend/app/core/api_crypto_middleware.py":{"size":11243,"mtime_ns":1780108930724537332,"hash":"0c2045d182138ec8e333356d36d418004a53948e2eda494cd419a36365ebbfae"},"/Users/zlwu/work/00code/shanxia2.0/backend/app/core/wechat_message.py":{"size":11194,"mtime_ns":1780108930725684255,"hash":"5086070deb14d99d1a69e419b2299ec4eLine truncated
|
||||
{"/Users/zlwu/work/00code/shanxia2.0/backend/start-prod.sh":{"size":5362,"mtime_ns":1780108930820143914,"hash":"712114b9a96e370660a7d8455b0cb014b6387a352e25c114bb396bc9815d48e6"},"/Users/zlwu/work/00code/shanxia2.0/backend/start.sh":{"size":9548,"mtime_ns":1780114661446983244,"hash":"4d632863e8a0cd81194b491d83a0218a4157435ae812dec76a6f6197b4d48e57"},"/Users/zlwu/work/00code/shanxia2.0/backend/app/__init__.py":{"size":21,"mtime_ns":1780113982281973984,"hash":"60a04ff08fd97084e83ea809fd13feda6d2848be20ebf309e31fc1dad7523230"},"/Users/zlwu/work/00code/shanxia2.0/backend/app/main.py":{"size":4650,"mtime_ns":1780750556882139523,"hash":"5906745ed3a9a4a62ccfec436a8fac62e8c6cb5c5a61715bb1979a7e5bef804a"},"/Users/zlwu/work/00code/shanxia2.0/backend/app/tasks/__init__.py":{"size":1634,"mtime_ns":1780201410115316494,"hash":"9ee508b67da0044015aff95ebddaf52a5ba551ccfee772bf134ca88e2d482e72"},"/Users/zlwu/work/00code/shanxia2.0/backend/app/core/auth.py":{"size":8744,"mtime_ns":1780201410112435240,"hash":"df84858ae3cea547e5ae0174a2ee76cd4df8835f4b75827843369e74ea91098b"},"/Users/zlwu/work/00code/shanxia2.0/backend/app/core/api_crypto.py":{"size":1870,"mtime_ns":1780108930724444498,"hash":"c04b748aea86890a5971f749523c7b17dbad1ddd6f9f7f07a5679d159c984e33"},"/Users/zlwu/work/00code/shanxia2.0/backend/app/core/login_crypto.py":{"size":3858,"mtime_ns":1780108930725155710,"hash":"b82d51afabf2293a9cb1fb2e5f994c383948e7f47ea95fe674686b4f3f3342b1"},"/Users/zlwu/work/00code/shanxia2.0/backend/app/core/config.py":{"size":5692,"mtime_ns":1780750556882308648,"hash":"a1404064f42d27efcdf287062da76d4cc863112aa1f2ace1bf86c2f72e8faef9"},"/Users/zlwu/work/00code/shanxia2.0/backend/app/core/wechat_pay.py":{"size":23585,"mtime_ns":1780108930725768130,"hash":"3d52265ce65d21e7103f94afa1e8547aee0823b5ea6d65c50317436ac81fb4fc"},"/Users/zlwu/work/00code/shanxia2.0/backend/app/core/api_request_log_middleware.py":{"size":8978,"mtime_ns":1780108930724617124,"hash":"198e0861bb9933a7cee510524c4802001543468727a45e779bc4684d0214ffe2"},"/Users/zlwu/work/00code/shanxia2.0/backend/app/core/database.py":{"size":1173,"mtime_ns":1780108930724965209,"hash":"8c45b5a56110164f2488c9c8db27db62fe77f0997cf22c53991c0bd1dde2043a"},"/Users/zlwu/work/00code/shanxia2.0/backend/app/core/security.py":{"size":728,"mtime_ns":1780108930725470004,"hash":"df0f01115064f7b8de1c81dbe9a6db39360c236610b68c33b3234a51d7f0025b"},"/Users/zlwu/work/00code/shanxia2.0/backend/app/core/request_payload.py":{"size":2842,"mtime_ns":1780108930725350836,"hash":"e9937151530ab1417ef297aef59111977725cf90be2a8fa76c00a0618789aba0"},"/Users/zlwu/work/00code/shanxia2.0/backend/app/core/__init__.py":{"size":61,"mtime_ns":1780108930724312414,"hash":"3dd1842ee59b0c804176b03b4b8a323bd4a252b7feb1bbc32db64f3a8928570e"},"/Users/zlwu/work/00code/shanxia2.0/backend/app/core/response.py":{"size":1824,"mtime_ns":1780108930725412462,"hash":"f1739352d65ea8287d76e282a59553aa8d63c97e35764c64ac378aa5bd9c347e"},"/Users/zlwu/work/00code/shanxia2.0/backend/app/core/menu_guard.py":{"size":1611,"mtime_ns":1780108930725223002,"hash":"3e26077288c3620a4780038b891a326206b45bffe00aca545bdae30172487235"},"/Users/zlwu/work/00code/shanxia2.0/backend/app/core/db_collation.py":{"size":548,"mtime_ns":1780108930725025043,"hash":"0c680e25a18244ca839a7de6ed1f4313b33bc8da118d89c463aee1b6af00c6f9"},"/Users/zlwu/work/00code/shanxia2.0/backend/app/core/context.py":{"size":421,"mtime_ns":1780108930724824458,"hash":"83a10aee67162374993c10a30bf8bb8bd9c4b35cf48f42c832415ccebd91660f"},"/Users/zlwu/work/00code/shanxia2.0/backend/app/core/utils.py":{"size":1498,"mtime_ns":1780108930725607296,"hash":"09323693661c1d4560458b86a954128ccff82bbaf6522da0b44f24da99ddf9ea"},"/Users/zlwu/work/00code/shanxia2.0/backend/app/core/storage.py":{"size":13209,"mtime_ns":1780108930725541087,"hash":"c3138253eb34f65b09f4436e037fb3179d947f84d3b5fef007ed9a8e3bb135ee"},"/Users/zlwu/work/00code/shanxia2.0/backend/app/core/order_status_compat.py":{"size":2828,"mtime_ns":1780108930725284669,"hash":"5349e5a0745ee6734c4a995337779307adefc46f453906171988a77de2081540"},"/Users/zlwu/work/00code/shanxia2.0/backend/app/core/exceptions.py":{"size":4946,"mtime_ns":1780108930725084335,"hash":"79c997d964bca1a4f12f2b92fb1f181fdb9e2b3cf72eae39f4cc164d23794fd7"},"/Users/zlwu/work/00code/shanxia2.0/backend/app/core/data_scope.py":{"size":5949,"mtime_ns":1780108930724890709,"hash":"c92a7dbcfe3d7440bfafc83a76e9ed431e2b054ddd95bc4bfac52b241635ab17"},"/Users/zlwu/work/00code/shanxia2.0/backend/app/core/admin_request_json.py":{"size":2669,"mtime_ns":1780108930724378914,"hash":"4f68b3cf84291e7bddad6ecf4bb4d29ca5e1ec246a9f7f9c4cf5909d0ec1174a"},"/Users/zlwu/work/00code/shanxia2.0/backend/app/core/api_crypto_middleware.py":{"size":11243,"mtime_ns":1780108930724537332,"hash":"0c2045d182138ec8e333356d36d418004a53948e2eda494cd419a36365ebbfae"},"/Users/zlwu/work/00code/shanxia2.0/backend/app/core/wechat_message.py":{"size":11194,"mtime_ns":1780108930725684255,"hash":"5086070deb14d99d1a69e419b2299ec4eLine truncated
|
||||
@@ -63,12 +63,12 @@
|
||||
</div>
|
||||
<div id="legend"></div>
|
||||
</div>
|
||||
<div id="stats">2643 nodes · 18676 edges · 106 communities</div>
|
||||
<div id="stats">3047 nodes · 20600 edges · 130 communities</div>
|
||||
</div>
|
||||
<script>
|
||||
const RAW_NODES = [{"id": "start_prod_sh", "label": "start-prod.sh", "color": {"background": "#EDC948", "border": "#EDC948", "highlight": {"background": "#ffffff", "border": "#EDC948"}}, "size": 10.9, "font": {"size": 0, "color": "#ffffff"}, "title": "start-prod.sh", "community": 25, "community_name": "Community 25", "source_file": "start-prod.sh", "file_type": "code", "degree": 13}, {"id": "users_zlwu_work_00code_shanxia2_0_backend_start_prod_sh__entry", "label": "start-prod.sh script", "color": {"background": "#EDC948", "border": "#EDC948", "highlight": {"background": "#ffffff", "border": "#EDC948"}}, "size": 10.5, "font": {"size": 0, "color": "#ffffff"}, "title": "start-prod.sh script", "community": 25, "community_name": "Community 25", "source_file": "start-prod.sh", "file_type": "code", "degree": 7}, {"id": "backend_start_prod_log_info", "label": "log_info()", "color": {"background": "#EDC948", "border": "#EDC948", "highlight": {"background": "#ffffff", "border": "#EDC948"}}, "size": 10.3, "font": {"size": 0, "color": "#ffffff"}, "title": "log_info()", "community": 25, "community_name": "Community 25", "source_file": "start-prod.sh", "file_type": "code", "degree": 4}, {"id": "backend_start_prod_log_warn", "label": "log_warn()", "color": {"background": "#EDC948", "border": "#EDC948", "highlight": {"background": "#ffffff", "border": "#EDC948"}}, "size": 10.3, "font": {"size": 0, "color": "#ffffff"}, "title": "log_warn()", "community": 25, "community_name": "Community 25", "source_file": "start-prod.sh", "file_type": "code", "degree": 5}, {"id": "backend_start_prod_log_error", "label": "log_error()", "color": {"background": "#EDC948", "border": "#EDC948", "highlight": {"background": "#ffffff", "border": "#EDC948"}}, "size": 10.3, "font": {"size": 0, "color": "#ffffff"}, "title": "log_error()", "community": 25, "community_name": "Community 25", "source_file": "start-prod.sh", "file_type": "code", "degree": 5}, {"id": "backend_start_prod_show_help", "label": "show_help()", "color": {"background": "#EDC948", "border": "#EDC948", "highlight": {"background": "#ffffff", "border": "#EDC948"}}, "size": 10.1, "font": {"size": 0, "color": "#ffffff"}, "title": "show_help()", "community": 25, "community_name": "Community 25", "source_file": "start-prod.sh", "file_type": "code", "degree": 2}, {"id": "backend_start_prod_ensure_dirs", "label": "ensure_dirs()", "color": {"background": "#EDC948", "border": "#EDC948", "highlight": {"background": "#ffffff", "border": "#EDC948"}}, "size": 10.2, "font": {"size": 0, "color": "#ffffff"}, "title": "ensure_dirs()", "community": 25, "community_name": "Community 25", "source_file": "start-prod.sh", "file_type": "code", "degree": 3}, {"id": "backend_start_prod_check_python", "label": "check_python()", "color": {"background": "#EDC948", "border": "#EDC948", "highlight": {"background": "#ffffff", "border": "#EDC948"}}, "size": 10.3, "font": {"size": 0, "color": "#ffffff"}, "title": "check_python()", "community": 25, "community_name": "Community 25", "source_file": "start-prod.sh", "file_type": "code", "degree": 4}, {"id": "backend_start_prod_ensure_venv_and_runtime", "label": "ensure_venv_and_runtime()", "color": {"background": "#EDC948", "border": "#EDC948", "highlight": {"background": "#ffffff", "border": "#EDC948"}}, "size": 10.3, "font": {"size": 0, "color": "#ffffff"}, "title": "ensure_venv_and_runtime()", "community": 25, "community_name": "Community 25", "source_file": "start-prod.sh", "file_type": "code", "degree": 4}, {"id": "backend_start_prod_is_running", "label": "is_running()", "color": {"background": "#EDC948", "border": "#EDC948", "highlight": {"background": "#ffffff", "border": "#EDC948"}}, "size": 10.3, "font": {"size": 0, "color": "#ffffff"}, "title": "is_running()", "community": 25, "community_name": "Community 25", "source_file": "start-prod.sh", "file_type": "code", "degree": 4}, {"id": "backend_start_prod_start_server", "label": "start_server()", "color": {"background": "#EDC948", "border": "#EDC948", "highlight": {"background": "#ffffff", "border": "#EDC948"}}, "size": 10.6, "font": {"size": 0, "color": "#ffffff"}, "title": "start_server()", "community": 25, "community_name": "Community 25", "source_file": "start-prod.sh", "file_type": "code", "degree": 9}, {"id": "backend_start_prod_stop_server", "label": "stop_server()", "color": {"background": "#EDC948", "border": "#EDC948", "highlight": {"background": "#ffffff", "border": "#EDC948"}}, "size": 10.3, "font": {"size": 0, "color": "#ffffff"}, "title": "stop_server()", "community": 25, "community_name": "Community 25", "source_file": "start-prod.sh", "file_type": "code", "degree": 5}, {"id": "backend_start_prod_status_server", "label": "status_server()", "color": {"background": "#EDC948", "border": "#EDC948", "highlight": {"background": "#ffffff", "border": "#EDC948"}}, "size": 10.2, "font": {"size": 0, "color": "#ffffff"}, "title": "status_server()", "community": 25, "community_name": "Community 25", "source_fiLine truncated
|
||||
const RAW_EDGES = [{"from": "start_prod_sh", "to": "backend_start_prod_check_python", "label": "defines", "title": "defines [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "start_prod_sh", "to": "backend_start_prod_ensure_dirs", "label": "defines", "title": "defines [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "start_prod_sh", "to": "backend_start_prod_ensure_venv_and_runtime", "label": "defines", "title": "defines [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "start_prod_sh", "to": "backend_start_prod_is_running", "label": "defines", "title": "defines [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "start_prod_sh", "to": "backend_start_prod_log_error", "label": "defines", "title": "defines [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "start_prod_sh", "to": "backend_start_prod_log_info", "label": "defines", "title": "defines [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "start_prod_sh", "to": "backend_start_prod_log_warn", "label": "defines", "title": "defines [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "start_prod_sh", "to": "backend_start_prod_show_help", "label": "defines", "title": "defines [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "start_prod_sh", "to": "backend_start_prod_show_logs", "label": "defines", "title": "defines [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "start_prod_sh", "to": "backend_start_prod_start_server", "label": "defines", "title": "defines [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "start_prod_sh", "to": "backend_start_prod_status_server", "label": "defines", "title": "defines [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "start_prod_sh", "to": "backend_start_prod_stop_server", "label": "defines", "title": "defines [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "start_prod_sh", "to": "users_zlwu_work_00code_shanxia2_0_backend_start_prod_sh__entry", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "users_zlwu_work_00code_shanxia2_0_backend_start_prod_sh__entry", "to": "backend_start_prod_log_error", "label": "calls", "title": "calls [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "users_zlwu_work_00code_shanxia2_0_backend_start_prod_sh__entry", "to": "backend_start_prod_show_help", "label": "calls", "title": "calls [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "users_zlwu_work_00code_shanxia2_0_backend_start_prod_sh__entry", "to": "backend_start_prod_show_logs", "label": "calls", "title": "calls [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "users_zlwu_work_00code_shanxia2_0_backend_start_prod_sh__entry", "to": "backend_start_prod_start_server", "label": "calls", "title": "calls [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "users_zlwu_work_00code_shanxia2_0_backend_start_prod_sh__entry", "to": "backend_start_prod_status_server", "label": "calls", "title": "calls [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "users_zlwu_work_00code_shanxia2_0_backend_start_prod_sh__entry", "to": "backend_start_prod_stop_server", "label": "calls", "title": "calls [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "backend_start_prod_check_python", "to": "backend_start_prod_log_info", "label": "calls", "title": "calls [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "backend_start_prod_start_server", "to": "backend_start_prod_log_info", "label": "calls", "title": "calls [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "backend_start_prod_stop_server", "to": "backend_start_prod_log_info", "label": "calls", "title": "calls [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "backend_start_prod_ensure_venv_and_runtime", "to": "backend_start_prod_log_warn", "label": "calls", "title": "calls [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "conLine truncated
|
||||
const LEGEND = [{"cid": 0, "color": "#4E79A7", "label": "Community 0", "count": 44}, {"cid": 1, "color": "#F28E2B", "label": "Community 1", "count": 103}, {"cid": 2, "color": "#E15759", "label": "Community 2", "count": 24}, {"cid": 3, "color": "#76B7B2", "label": "Community 3", "count": 35}, {"cid": 4, "color": "#59A14F", "label": "Community 4", "count": 30}, {"cid": 5, "color": "#EDC948", "label": "Community 5", "count": 67}, {"cid": 6, "color": "#B07AA1", "label": "Community 6", "count": 95}, {"cid": 7, "color": "#FF9DA7", "label": "Community 7", "count": 9}, {"cid": 8, "color": "#9C755F", "label": "Community 8", "count": 36}, {"cid": 9, "color": "#BAB0AC", "label": "Community 9", "count": 16}, {"cid": 10, "color": "#4E79A7", "label": "Community 10", "count": 57}, {"cid": 11, "color": "#F28E2B", "label": "Community 11", "count": 169}, {"cid": 12, "color": "#E15759", "label": "Community 12", "count": 85}, {"cid": 13, "color": "#76B7B2", "label": "Community 13", "count": 222}, {"cid": 14, "color": "#59A14F", "label": "Community 14", "count": 40}, {"cid": 15, "color": "#EDC948", "label": "Community 15", "count": 26}, {"cid": 16, "color": "#B07AA1", "label": "Community 16", "count": 33}, {"cid": 17, "color": "#FF9DA7", "label": "Community 17", "count": 23}, {"cid": 18, "color": "#9C755F", "label": "Community 18", "count": 37}, {"cid": 19, "color": "#BAB0AC", "label": "Community 19", "count": 11}, {"cid": 20, "color": "#4E79A7", "label": "Community 20", "count": 18}, {"cid": 21, "color": "#F28E2B", "label": "Community 21", "count": 17}, {"cid": 22, "color": "#E15759", "label": "Community 22", "count": 54}, {"cid": 23, "color": "#76B7B2", "label": "Community 23", "count": 23}, {"cid": 24, "color": "#59A14F", "label": "Community 24", "count": 15}, {"cid": 25, "color": "#EDC948", "label": "Community 25", "count": 14}, {"cid": 26, "color": "#B07AA1", "label": "Community 26", "count": 12}, {"cid": 27, "color": "#FF9DA7", "label": "Community 27", "count": 21}, {"cid": 28, "color": "#9C755F", "label": "Community 28", "count": 20}, {"cid": 29, "color": "#BAB0AC", "label": "Community 29", "count": 8}, {"cid": 30, "color": "#4E79A7", "label": "Community 30", "count": 5}, {"cid": 31, "color": "#F28E2B", "label": "Community 31", "count": 2}, {"cid": 32, "color": "#E15759", "label": "Community 32", "count": 1}, {"cid": 33, "color": "#76B7B2", "label": "Community 33", "count": 1}, {"cid": 34, "color": "#59A14F", "label": "Community 34", "count": 1}, {"cid": 35, "color": "#EDC948", "label": "Community 35", "count": 1}, {"cid": 36, "color": "#B07AA1", "label": "Community 36", "count": 34}, {"cid": 37, "color": "#FF9DA7", "label": "Community 37", "count": 25}, {"cid": 38, "color": "#9C755F", "label": "Community 38", "count": 5}, {"cid": 39, "color": "#BAB0AC", "label": "Community 39", "count": 27}, {"cid": 40, "color": "#4E79A7", "label": "Community 40", "count": 34}, {"cid": 41, "color": "#F28E2B", "label": "Community 41", "count": 19}, {"cid": 42, "color": "#E15759", "label": "Community 42", "count": 17}, {"cid": 43, "color": "#76B7B2", "label": "Community 43", "count": 18}, {"cid": 44, "color": "#59A14F", "label": "Community 44", "count": 24}, {"cid": 45, "color": "#EDC948", "label": "Community 45", "count": 77}, {"cid": 46, "color": "#B07AA1", "label": "Community 46", "count": 29}, {"cid": 47, "color": "#FF9DA7", "label": "Community 47", "count": 29}, {"cid": 48, "color": "#9C755F", "label": "Community 48", "count": 54}, {"cid": 49, "color": "#BAB0AC", "label": "Community 49", "count": 12}, {"cid": 50, "color": "#4E79A7", "label": "Community 50", "count": 23}, {"cid": 51, "color": "#F28E2B", "label": "Community 51", "count": 23}, {"cid": 52, "color": "#E15759", "label": "Community 52", "count": 14}, {"cid": 53, "color": "#76B7B2", "label": "Community 53", "count": 7}, {"cid": 54, "color": "#59A14F", "label": "Community 54", "count": 22}, {"cid": 55, "color": "#EDC948", "label": "Community 55", "count": 17}, {"cid": 56, "color": "#B07AA1", "label": "Community 56", "count": 12}, {"cid": 57, "color": "#FF9DA7", "label": "Community 57", "count": 26}, {"cid": 58, "color": "#9C755F", "label": "Community 58", "count": 3}, {"cid": 59, "color": "#BAB0AC", "label": "Community 59", "count": 18}, {"cid": 60, "color": "#4E79A7", "label": "Community 60", "count": 33}, {"cid": 61, "color": "#F28E2B", "label": "Community 61", "count": 30}, {"cid": 62, "color": "#E15759", "label": "Community 62", "count": 18}, {"cid": 63, "color": "#76B7B2", "label": "Community 63", "count": 30}, {"cid": 64, "color": "#59A14F", "label": "Community 64", "count": 2}, {"cid": 65, "color": "#EDC948", "label": "Community 65", "count": 16}, {"cid": 66, "color": "#B07AA1", "label": "Community 66", "count": 1}, {"cid": 67, "color": "#FF9DA7", "label": "Community 67", "count": 1}, {"cid": 68, "color": "#9C755F", "label": "Community 68", "count": 19}, {"cid": 69, "color": "#BAB0AC", "label": "Community 69", "count": 46}, {"cid": 70, "color": "#4E79A7", "label": "CoLine truncated
|
||||
const RAW_NODES = [{"id": "start_prod_sh", "label": "start-prod.sh", "color": {"background": "#EDC948", "border": "#EDC948", "highlight": {"background": "#ffffff", "border": "#EDC948"}}, "size": 10.9, "font": {"size": 0, "color": "#ffffff"}, "title": "start-prod.sh", "community": 25, "community_name": "Community 25", "source_file": "start-prod.sh", "file_type": "code", "degree": 13}, {"id": "users_zlwu_work_00code_shanxia2_0_backend_start_prod_sh__entry", "label": "start-prod.sh script", "color": {"background": "#EDC948", "border": "#EDC948", "highlight": {"background": "#ffffff", "border": "#EDC948"}}, "size": 10.5, "font": {"size": 0, "color": "#ffffff"}, "title": "start-prod.sh script", "community": 25, "community_name": "Community 25", "source_file": "start-prod.sh", "file_type": "code", "degree": 7}, {"id": "backend_start_prod_log_info", "label": "log_info()", "color": {"background": "#EDC948", "border": "#EDC948", "highlight": {"background": "#ffffff", "border": "#EDC948"}}, "size": 10.3, "font": {"size": 0, "color": "#ffffff"}, "title": "log_info()", "community": 25, "community_name": "Community 25", "source_file": "start-prod.sh", "file_type": "code", "degree": 4}, {"id": "backend_start_prod_log_warn", "label": "log_warn()", "color": {"background": "#EDC948", "border": "#EDC948", "highlight": {"background": "#ffffff", "border": "#EDC948"}}, "size": 10.3, "font": {"size": 0, "color": "#ffffff"}, "title": "log_warn()", "community": 25, "community_name": "Community 25", "source_file": "start-prod.sh", "file_type": "code", "degree": 5}, {"id": "backend_start_prod_log_error", "label": "log_error()", "color": {"background": "#EDC948", "border": "#EDC948", "highlight": {"background": "#ffffff", "border": "#EDC948"}}, "size": 10.3, "font": {"size": 0, "color": "#ffffff"}, "title": "log_error()", "community": 25, "community_name": "Community 25", "source_file": "start-prod.sh", "file_type": "code", "degree": 5}, {"id": "backend_start_prod_show_help", "label": "show_help()", "color": {"background": "#EDC948", "border": "#EDC948", "highlight": {"background": "#ffffff", "border": "#EDC948"}}, "size": 10.1, "font": {"size": 0, "color": "#ffffff"}, "title": "show_help()", "community": 25, "community_name": "Community 25", "source_file": "start-prod.sh", "file_type": "code", "degree": 2}, {"id": "backend_start_prod_ensure_dirs", "label": "ensure_dirs()", "color": {"background": "#EDC948", "border": "#EDC948", "highlight": {"background": "#ffffff", "border": "#EDC948"}}, "size": 10.2, "font": {"size": 0, "color": "#ffffff"}, "title": "ensure_dirs()", "community": 25, "community_name": "Community 25", "source_file": "start-prod.sh", "file_type": "code", "degree": 3}, {"id": "backend_start_prod_check_python", "label": "check_python()", "color": {"background": "#EDC948", "border": "#EDC948", "highlight": {"background": "#ffffff", "border": "#EDC948"}}, "size": 10.3, "font": {"size": 0, "color": "#ffffff"}, "title": "check_python()", "community": 25, "community_name": "Community 25", "source_file": "start-prod.sh", "file_type": "code", "degree": 4}, {"id": "backend_start_prod_ensure_venv_and_runtime", "label": "ensure_venv_and_runtime()", "color": {"background": "#EDC948", "border": "#EDC948", "highlight": {"background": "#ffffff", "border": "#EDC948"}}, "size": 10.3, "font": {"size": 0, "color": "#ffffff"}, "title": "ensure_venv_and_runtime()", "community": 25, "community_name": "Community 25", "source_file": "start-prod.sh", "file_type": "code", "degree": 4}, {"id": "backend_start_prod_is_running", "label": "is_running()", "color": {"background": "#EDC948", "border": "#EDC948", "highlight": {"background": "#ffffff", "border": "#EDC948"}}, "size": 10.3, "font": {"size": 0, "color": "#ffffff"}, "title": "is_running()", "community": 25, "community_name": "Community 25", "source_file": "start-prod.sh", "file_type": "code", "degree": 4}, {"id": "backend_start_prod_start_server", "label": "start_server()", "color": {"background": "#EDC948", "border": "#EDC948", "highlight": {"background": "#ffffff", "border": "#EDC948"}}, "size": 10.6, "font": {"size": 0, "color": "#ffffff"}, "title": "start_server()", "community": 25, "community_name": "Community 25", "source_file": "start-prod.sh", "file_type": "code", "degree": 9}, {"id": "backend_start_prod_stop_server", "label": "stop_server()", "color": {"background": "#EDC948", "border": "#EDC948", "highlight": {"background": "#ffffff", "border": "#EDC948"}}, "size": 10.3, "font": {"size": 0, "color": "#ffffff"}, "title": "stop_server()", "community": 25, "community_name": "Community 25", "source_file": "start-prod.sh", "file_type": "code", "degree": 5}, {"id": "backend_start_prod_status_server", "label": "status_server()", "color": {"background": "#EDC948", "border": "#EDC948", "highlight": {"background": "#ffffff", "border": "#EDC948"}}, "size": 10.2, "font": {"size": 0, "color": "#ffffff"}, "title": "status_server()", "community": 25, "community_name": "Community 25", "source_fiLine truncated
|
||||
const RAW_EDGES = [{"from": "start_prod_sh", "to": "backend_start_prod_check_python", "label": "defines", "title": "defines [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "start_prod_sh", "to": "backend_start_prod_ensure_dirs", "label": "defines", "title": "defines [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "start_prod_sh", "to": "backend_start_prod_ensure_venv_and_runtime", "label": "defines", "title": "defines [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "start_prod_sh", "to": "backend_start_prod_is_running", "label": "defines", "title": "defines [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "start_prod_sh", "to": "backend_start_prod_log_error", "label": "defines", "title": "defines [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "start_prod_sh", "to": "backend_start_prod_log_info", "label": "defines", "title": "defines [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "start_prod_sh", "to": "backend_start_prod_log_warn", "label": "defines", "title": "defines [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "start_prod_sh", "to": "backend_start_prod_show_help", "label": "defines", "title": "defines [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "start_prod_sh", "to": "backend_start_prod_show_logs", "label": "defines", "title": "defines [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "start_prod_sh", "to": "backend_start_prod_start_server", "label": "defines", "title": "defines [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "start_prod_sh", "to": "backend_start_prod_status_server", "label": "defines", "title": "defines [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "start_prod_sh", "to": "backend_start_prod_stop_server", "label": "defines", "title": "defines [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "start_prod_sh", "to": "users_zlwu_work_00code_shanxia2_0_backend_start_prod_sh__entry", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "users_zlwu_work_00code_shanxia2_0_backend_start_prod_sh__entry", "to": "backend_start_prod_log_error", "label": "calls", "title": "calls [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "users_zlwu_work_00code_shanxia2_0_backend_start_prod_sh__entry", "to": "backend_start_prod_show_help", "label": "calls", "title": "calls [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "users_zlwu_work_00code_shanxia2_0_backend_start_prod_sh__entry", "to": "backend_start_prod_show_logs", "label": "calls", "title": "calls [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "users_zlwu_work_00code_shanxia2_0_backend_start_prod_sh__entry", "to": "backend_start_prod_start_server", "label": "calls", "title": "calls [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "users_zlwu_work_00code_shanxia2_0_backend_start_prod_sh__entry", "to": "backend_start_prod_status_server", "label": "calls", "title": "calls [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "users_zlwu_work_00code_shanxia2_0_backend_start_prod_sh__entry", "to": "backend_start_prod_stop_server", "label": "calls", "title": "calls [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "backend_start_prod_check_python", "to": "backend_start_prod_log_info", "label": "calls", "title": "calls [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "backend_start_prod_start_server", "to": "backend_start_prod_log_info", "label": "calls", "title": "calls [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "backend_start_prod_stop_server", "to": "backend_start_prod_log_info", "label": "calls", "title": "calls [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "backend_start_prod_ensure_venv_and_runtime", "to": "backend_start_prod_log_warn", "label": "calls", "title": "calls [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "conLine truncated
|
||||
const LEGEND = [{"cid": 0, "color": "#4E79A7", "label": "Community 0", "count": 28}, {"cid": 1, "color": "#F28E2B", "label": "Community 1", "count": 43}, {"cid": 2, "color": "#E15759", "label": "Community 2", "count": 23}, {"cid": 3, "color": "#76B7B2", "label": "Community 3", "count": 35}, {"cid": 4, "color": "#59A14F", "label": "Community 4", "count": 42}, {"cid": 5, "color": "#EDC948", "label": "Community 5", "count": 18}, {"cid": 6, "color": "#B07AA1", "label": "Community 6", "count": 73}, {"cid": 7, "color": "#FF9DA7", "label": "Community 7", "count": 9}, {"cid": 8, "color": "#9C755F", "label": "Community 8", "count": 53}, {"cid": 9, "color": "#BAB0AC", "label": "Community 9", "count": 16}, {"cid": 10, "color": "#4E79A7", "label": "Community 10", "count": 70}, {"cid": 11, "color": "#F28E2B", "label": "Community 11", "count": 168}, {"cid": 12, "color": "#E15759", "label": "Community 12", "count": 53}, {"cid": 13, "color": "#76B7B2", "label": "Community 13", "count": 222}, {"cid": 14, "color": "#59A14F", "label": "Community 14", "count": 46}, {"cid": 15, "color": "#EDC948", "label": "Community 15", "count": 26}, {"cid": 16, "color": "#B07AA1", "label": "Community 16", "count": 33}, {"cid": 17, "color": "#FF9DA7", "label": "Community 17", "count": 67}, {"cid": 18, "color": "#9C755F", "label": "Community 18", "count": 37}, {"cid": 19, "color": "#BAB0AC", "label": "Community 19", "count": 22}, {"cid": 20, "color": "#4E79A7", "label": "Community 20", "count": 18}, {"cid": 21, "color": "#F28E2B", "label": "Community 21", "count": 17}, {"cid": 22, "color": "#E15759", "label": "Community 22", "count": 24}, {"cid": 23, "color": "#76B7B2", "label": "Community 23", "count": 17}, {"cid": 24, "color": "#59A14F", "label": "Community 24", "count": 15}, {"cid": 25, "color": "#EDC948", "label": "Community 25", "count": 14}, {"cid": 26, "color": "#B07AA1", "label": "Community 26", "count": 12}, {"cid": 27, "color": "#FF9DA7", "label": "Community 27", "count": 33}, {"cid": 28, "color": "#9C755F", "label": "Community 28", "count": 38}, {"cid": 29, "color": "#BAB0AC", "label": "Community 29", "count": 8}, {"cid": 30, "color": "#4E79A7", "label": "Community 30", "count": 5}, {"cid": 31, "color": "#F28E2B", "label": "Community 31", "count": 2}, {"cid": 32, "color": "#E15759", "label": "Community 32", "count": 1}, {"cid": 33, "color": "#76B7B2", "label": "Community 33", "count": 1}, {"cid": 34, "color": "#59A14F", "label": "Community 34", "count": 1}, {"cid": 35, "color": "#EDC948", "label": "Community 35", "count": 1}, {"cid": 36, "color": "#B07AA1", "label": "Community 36", "count": 15}, {"cid": 37, "color": "#FF9DA7", "label": "Community 37", "count": 55}, {"cid": 38, "color": "#9C755F", "label": "Community 38", "count": 22}, {"cid": 39, "color": "#BAB0AC", "label": "Community 39", "count": 27}, {"cid": 40, "color": "#4E79A7", "label": "Community 40", "count": 63}, {"cid": 41, "color": "#F28E2B", "label": "Community 41", "count": 34}, {"cid": 42, "color": "#E15759", "label": "Community 42", "count": 17}, {"cid": 43, "color": "#76B7B2", "label": "Community 43", "count": 21}, {"cid": 44, "color": "#59A14F", "label": "Community 44", "count": 18}, {"cid": 45, "color": "#EDC948", "label": "Community 45", "count": 35}, {"cid": 46, "color": "#B07AA1", "label": "Community 46", "count": 89}, {"cid": 47, "color": "#FF9DA7", "label": "Community 47", "count": 55}, {"cid": 48, "color": "#9C755F", "label": "Community 48", "count": 55}, {"cid": 49, "color": "#BAB0AC", "label": "Community 49", "count": 29}, {"cid": 50, "color": "#4E79A7", "label": "Community 50", "count": 25}, {"cid": 51, "color": "#F28E2B", "label": "Community 51", "count": 23}, {"cid": 52, "color": "#E15759", "label": "Community 52", "count": 7}, {"cid": 53, "color": "#76B7B2", "label": "Community 53", "count": 21}, {"cid": 54, "color": "#59A14F", "label": "Community 54", "count": 22}, {"cid": 55, "color": "#EDC948", "label": "Community 55", "count": 17}, {"cid": 56, "color": "#B07AA1", "label": "Community 56", "count": 12}, {"cid": 57, "color": "#FF9DA7", "label": "Community 57", "count": 19}, {"cid": 58, "color": "#9C755F", "label": "Community 58", "count": 3}, {"cid": 59, "color": "#BAB0AC", "label": "Community 59", "count": 18}, {"cid": 60, "color": "#4E79A7", "label": "Community 60", "count": 33}, {"cid": 61, "color": "#F28E2B", "label": "Community 61", "count": 33}, {"cid": 62, "color": "#E15759", "label": "Community 62", "count": 18}, {"cid": 63, "color": "#76B7B2", "label": "Community 63", "count": 31}, {"cid": 64, "color": "#59A14F", "label": "Community 64", "count": 2}, {"cid": 65, "color": "#EDC948", "label": "Community 65", "count": 16}, {"cid": 66, "color": "#B07AA1", "label": "Community 66", "count": 1}, {"cid": 67, "color": "#FF9DA7", "label": "Community 67", "count": 1}, {"cid": 68, "color": "#9C755F", "label": "Community 68", "count": 16}, {"cid": 69, "color": "#BAB0AC", "label": "Community 69", "count": 46}, {"cid": 70, "color": "#4E79A7", "label": "CoLine truncated
|
||||
|
||||
// HTML-escape helper — prevents XSS when injecting graph data into innerHTML
|
||||
function esc(s) {
|
||||
|
||||
+24926
-1068
File diff suppressed because it is too large.
Load diff
+526
-113
@@ -1,334 +1,747 @@
|
||||
{
|
||||
"/Users/zlwu/work/00code/shanxia2.0/backend/app/__init__.py": {
|
||||
"mtime": 1780113982.281974,
|
||||
"hash": "9c26ed050e94de5ab7c16bf27c0c42ef"
|
||||
"ast_hash": "9c26ed050e94de5ab7c16bf27c0c42ef",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/backend/app/main.py": {
|
||||
"mtime": 1780129938.8065724,
|
||||
"hash": "7b32b6d042a2b3afa012cd3d8fe9cfac"
|
||||
"mtime": 1780750556.8821394,
|
||||
"ast_hash": "9d2dc014c76287a8e8a4a7f4c4c633cc",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/backend/app/tasks/customer_pool.py": {
|
||||
"mtime": 1780148500.3765707,
|
||||
"hash": "6aa9af295015a82fdb6f54e50a8f6a2f"
|
||||
"mtime": 1780202350.1478229,
|
||||
"ast_hash": "1fcafe4082c11b33ab705292cf07b20f",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/backend/app/tasks/__init__.py": {
|
||||
"mtime": 1780148514.5971222,
|
||||
"hash": "753c8681539418af3ddf8c57880b6442"
|
||||
"mtime": 1780201410.1153164,
|
||||
"ast_hash": "334dffe3a8b19bc6b49008d6f7265a11",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/backend/app/core/tenant_context.py": {
|
||||
"mtime": 1780136000.1439688,
|
||||
"hash": "b18133acb1c4bd1ab0709c786f70e133"
|
||||
"mtime": 1780201410.2101986,
|
||||
"ast_hash": "b18133acb1c4bd1ab0709c786f70e133",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/backend/app/core/auth.py": {
|
||||
"mtime": 1780136008.2288265,
|
||||
"hash": "66e0e3cc285a14d0f224f3bd3ee24db7"
|
||||
"mtime": 1780201410.1124353,
|
||||
"ast_hash": "66e0e3cc285a14d0f224f3bd3ee24db7",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/backend/app/core/api_crypto.py": {
|
||||
"mtime": 1780108930.7244444,
|
||||
"hash": "fe51609d806a6f1ccb81ddce26e79320"
|
||||
"ast_hash": "fe51609d806a6f1ccb81ddce26e79320",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/backend/app/core/login_crypto.py": {
|
||||
"mtime": 1780108930.7251556,
|
||||
"hash": "3f7807dffdde603ff65eeeed5883f115"
|
||||
"ast_hash": "3f7807dffdde603ff65eeeed5883f115",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/backend/app/core/config.py": {
|
||||
"mtime": 1780131767.561871,
|
||||
"hash": "650ee00a9cad587e2ca66be4bc583aff"
|
||||
"mtime": 1780750556.8823087,
|
||||
"ast_hash": "b7a28e6af80b6160097dfd7dbdfa5ff6",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/backend/app/core/wechat_pay.py": {
|
||||
"mtime": 1780108930.725768,
|
||||
"hash": "7b125f92286034b9c80b7015ea7eac0e"
|
||||
"ast_hash": "7b125f92286034b9c80b7015ea7eac0e",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/backend/app/core/api_request_log_middleware.py": {
|
||||
"mtime": 1780108930.7246172,
|
||||
"hash": "c6c3d77e419c40a3315a4d8cb9c86198"
|
||||
"ast_hash": "c6c3d77e419c40a3315a4d8cb9c86198",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/backend/app/core/database.py": {
|
||||
"mtime": 1780108930.724965,
|
||||
"hash": "8679f18f61d636cf8c9888af4583f140"
|
||||
"ast_hash": "8679f18f61d636cf8c9888af4583f140",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/backend/app/core/security.py": {
|
||||
"mtime": 1780108930.72547,
|
||||
"hash": "d4b24a2d7249c3e3fb15d5e7456fbed8"
|
||||
"ast_hash": "d4b24a2d7249c3e3fb15d5e7456fbed8",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/backend/app/core/request_payload.py": {
|
||||
"mtime": 1780108930.7253509,
|
||||
"hash": "f683e5ef0867a02da2c06d8461359096"
|
||||
"ast_hash": "f683e5ef0867a02da2c06d8461359096",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/backend/app/core/__init__.py": {
|
||||
"mtime": 1780108930.7243123,
|
||||
"hash": "04e3e5031c7ca38b0fc3c69272f0b4da"
|
||||
"ast_hash": "04e3e5031c7ca38b0fc3c69272f0b4da",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/backend/app/core/response.py": {
|
||||
"mtime": 1780108930.7254124,
|
||||
"hash": "bec8efa5e032e42a16cafeff26bf98af"
|
||||
"ast_hash": "bec8efa5e032e42a16cafeff26bf98af",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/backend/app/core/menu_guard.py": {
|
||||
"mtime": 1780108930.725223,
|
||||
"hash": "c63dc7c451f9b8b826e88135bbbc667e"
|
||||
"ast_hash": "c63dc7c451f9b8b826e88135bbbc667e",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/backend/app/core/db_collation.py": {
|
||||
"mtime": 1780108930.725025,
|
||||
"hash": "2d581fb593646b13bba707de9e64368f"
|
||||
"ast_hash": "2d581fb593646b13bba707de9e64368f",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/backend/app/core/context.py": {
|
||||
"mtime": 1780108930.7248244,
|
||||
"hash": "4a9ca81161363408fe2ac0397cde2a1c"
|
||||
"ast_hash": "4a9ca81161363408fe2ac0397cde2a1c",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/backend/app/core/utils.py": {
|
||||
"mtime": 1780108930.7256074,
|
||||
"hash": "88470f8073435a02b371a8a95c7d54a1"
|
||||
"ast_hash": "88470f8073435a02b371a8a95c7d54a1",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/backend/app/core/storage.py": {
|
||||
"mtime": 1780108930.725541,
|
||||
"hash": "81f48c571d43280f09fd8dd0eda348cc"
|
||||
"ast_hash": "81f48c571d43280f09fd8dd0eda348cc",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/backend/app/core/order_status_compat.py": {
|
||||
"mtime": 1780108930.7252846,
|
||||
"hash": "bd9a75bf01f391271943d8ade0f96558"
|
||||
"ast_hash": "bd9a75bf01f391271943d8ade0f96558",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/backend/app/core/exceptions.py": {
|
||||
"mtime": 1780108930.7250843,
|
||||
"hash": "6b750c71e0cccaa33199ab7dd9784d47"
|
||||
"ast_hash": "6b750c71e0cccaa33199ab7dd9784d47",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/backend/app/core/data_scope.py": {
|
||||
"mtime": 1780108930.7248907,
|
||||
"hash": "6a28c0d184a61ebf4426e9475c9caddf"
|
||||
"ast_hash": "6a28c0d184a61ebf4426e9475c9caddf",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/backend/app/core/admin_request_json.py": {
|
||||
"mtime": 1780108930.7243788,
|
||||
"hash": "8ca43f66333d7a0219028e53f488d3e6"
|
||||
"ast_hash": "8ca43f66333d7a0219028e53f488d3e6",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/backend/app/core/api_crypto_middleware.py": {
|
||||
"mtime": 1780108930.7245374,
|
||||
"hash": "ccd86a39a77b19b1a3641dc854d7ddb7"
|
||||
"ast_hash": "ccd86a39a77b19b1a3641dc854d7ddb7",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/backend/app/core/wechat_message.py": {
|
||||
"mtime": 1780108930.7256842,
|
||||
"hash": "bccf04281267702872c44091979972e1"
|
||||
"ast_hash": "bccf04281267702872c44091979972e1",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/backend/app/models/models.py": {
|
||||
"mtime": 1780131847.0058825,
|
||||
"hash": "2412d5b473634e2e582d07b3ac2f8d0f"
|
||||
"mtime": 1780201410.1145027,
|
||||
"ast_hash": "2412d5b473634e2e582d07b3ac2f8d0f",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/backend/app/models/__init__.py": {
|
||||
"mtime": 1780112936.52883,
|
||||
"hash": "c7b352109a86ebf6a84e98cade8c0fc0"
|
||||
"ast_hash": "c7b352109a86ebf6a84e98cade8c0fc0",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/backend/app/models/crm_models.py": {
|
||||
"mtime": 1780150221.3008816,
|
||||
"hash": "8e9c2517e004387f5e7276250c1f1096"
|
||||
"mtime": 1780743830.2210455,
|
||||
"ast_hash": "e219acfafb17fc75b435021e04fc892a",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/backend/app/models/base.py": {
|
||||
"mtime": 1780108930.807299,
|
||||
"hash": "bd94a0e35e05556b29b23e2fdbe108ee"
|
||||
"ast_hash": "bd94a0e35e05556b29b23e2fdbe108ee",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/auth.py": {
|
||||
"mtime": 1780108930.8081977,
|
||||
"hash": "10bd8e938e2e2069dd06b69c1a261db5"
|
||||
"ast_hash": "10bd8e938e2e2069dd06b69c1a261db5",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/user.py": {
|
||||
"mtime": 1780108930.8101847,
|
||||
"hash": "7c9449203e3f490cf6c7925c53830bb9"
|
||||
"ast_hash": "7c9449203e3f490cf6c7925c53830bb9",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/__init__.py": {
|
||||
"mtime": 1780112973.062398,
|
||||
"hash": "6928db58baf42e0b4c181fb52ab50c4a"
|
||||
"ast_hash": "6928db58baf42e0b4c181fb52ab50c4a",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/menu.py": {
|
||||
"mtime": 1780108930.808682,
|
||||
"hash": "4a96aebf6a475372053a632212422204"
|
||||
"ast_hash": "4a96aebf6a475372053a632212422204",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/attachment.py": {
|
||||
"mtime": 1780108930.8081448,
|
||||
"hash": "a2a9aa2a9ec2ad982bfc0925bd60ff47"
|
||||
"ast_hash": "a2a9aa2a9ec2ad982bfc0925bd60ff47",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/common.py": {
|
||||
"mtime": 1780108930.8084266,
|
||||
"hash": "49c0726bb57476e86f16f3b67dfb89e3"
|
||||
"ast_hash": "49c0726bb57476e86f16f3b67dfb89e3",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/workflow.py": {
|
||||
"mtime": 1780108930.810246,
|
||||
"hash": "c8f5dda38b78a3b7b08e26994d82bb99"
|
||||
"ast_hash": "c8f5dda38b78a3b7b08e26994d82bb99",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/leave.py": {
|
||||
"mtime": 1780108930.808614,
|
||||
"hash": "5466d56c6c00865aac2400bc5ed0bfde"
|
||||
"ast_hash": "5466d56c6c00865aac2400bc5ed0bfde",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/crm/pool_rule.py": {
|
||||
"mtime": 1780146664.2302885,
|
||||
"hash": "de74af98ef8b3f4cea1515b45221d000"
|
||||
"mtime": 1780202212.7342336,
|
||||
"ast_hash": "75feeee85a38a29ff9d54872ced67b52",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/crm/customer_pool.py": {
|
||||
"mtime": 1780146654.2520175,
|
||||
"hash": "41f825d4a540b3b21773664726aa5925"
|
||||
"mtime": 1780202198.6982312,
|
||||
"ast_hash": "a741112d51c7b9429d0b34845674253c",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/crm/customer_follow.py": {
|
||||
"mtime": 1780146651.429359,
|
||||
"hash": "e0dc2a6ccc7643de2fc02c321a238f07"
|
||||
"mtime": 1780201410.2139344,
|
||||
"ast_hash": "d59a60bd1ff1fdd175d98bd39aa0b248",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/crm/__init__.py": {
|
||||
"mtime": 1780129331.8594196,
|
||||
"hash": "d41d8cd98f00b204e9800998ecf8427e"
|
||||
"mtime": 1780201410.213315,
|
||||
"ast_hash": "d41d8cd98f00b204e9800998ecf8427e",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/crm/product.py": {
|
||||
"mtime": 1780135028.7992775,
|
||||
"hash": "93a8897e3a2b6380268b4fb241cd1fde"
|
||||
"mtime": 1780743830.2208753,
|
||||
"ast_hash": "56b53f2ca2ffccab8186a6cb61e7c94e",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/crm/customer.py": {
|
||||
"mtime": 1780146617.7360954,
|
||||
"hash": "42d1c32291de54a365f6802bd064ebc0"
|
||||
"mtime": 1780713560.8434699,
|
||||
"ast_hash": "639b5ea6917acab50233b93149d96f3b",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/crm/contact.py": {
|
||||
"mtime": 1780146642.8435316,
|
||||
"hash": "9d145bfd34f8106be403e7058c144111"
|
||||
"mtime": 1780742840.9759488,
|
||||
"ast_hash": "b8b1b11592045acba091761fe3a193aa",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/backend/app/crud/sample_code.py": {
|
||||
"mtime": 1780114002.126415,
|
||||
"hash": "b7daeb88aeae6bb90b6db066c5a9dc32"
|
||||
"ast_hash": "b7daeb88aeae6bb90b6db066c5a9dc32",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/backend/app/crud/post.py": {
|
||||
"mtime": 1780114001.6183877,
|
||||
"hash": "fb8194bc855fd9928b51ad2923481be3"
|
||||
"ast_hash": "fb8194bc855fd9928b51ad2923481be3",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/backend/app/crud/user.py": {
|
||||
"mtime": 1780132195.6693316,
|
||||
"hash": "18d14c927fd17385d3c5727c32192087"
|
||||
"mtime": 1780201410.1127322,
|
||||
"ast_hash": "18d14c927fd17385d3c5727c32192087",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/backend/app/crud/dict_type.py": {
|
||||
"mtime": 1780108930.7273602,
|
||||
"hash": "1078f742bd94ea4910f6b0455e7b6907"
|
||||
"ast_hash": "1078f742bd94ea4910f6b0455e7b6907",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/backend/app/crud/tenant.py": {
|
||||
"mtime": 1780108930.7319968,
|
||||
"hash": "c06904189c34747b76d2156eec371510"
|
||||
"ast_hash": "c06904189c34747b76d2156eec371510",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/backend/app/crud/biz_no_generator.py": {
|
||||
"mtime": 1780108930.726091,
|
||||
"hash": "7fbe59bac864b3b6a1ce8c98d3433806"
|
||||
"ast_hash": "7fbe59bac864b3b6a1ce8c98d3433806",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/backend/app/crud/__init__.py": {
|
||||
"mtime": 1780108930.725878,
|
||||
"hash": "187d5328ae0c945daec2698273de8e3f"
|
||||
"ast_hash": "187d5328ae0c945daec2698273de8e3f",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/backend/app/crud/role.py": {
|
||||
"mtime": 1780114000.0273001,
|
||||
"hash": "2cd44770735b6a837e6b6e962baee4c1"
|
||||
"ast_hash": "2cd44770735b6a837e6b6e962baee4c1",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/backend/app/crud/menu.py": {
|
||||
"mtime": 1780113999.2640977,
|
||||
"hash": "f1beeee9f545a3c3be738d41db5bce92"
|
||||
"ast_hash": "f1beeee9f545a3c3be738d41db5bce92",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/backend/app/crud/site.py": {
|
||||
"mtime": 1780113998.4629104,
|
||||
"hash": "15931bf4ec37b46d0c69787857570f8f"
|
||||
"ast_hash": "15931bf4ec37b46d0c69787857570f8f",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/backend/app/crud/api_request_log.py": {
|
||||
"mtime": 1780108930.725946,
|
||||
"hash": "7720097399d092082a8f3dfe85e7cf17"
|
||||
"ast_hash": "7720097399d092082a8f3dfe85e7cf17",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/backend/app/crud/dict_data.py": {
|
||||
"mtime": 1780112650.1176188,
|
||||
"hash": "73db684fd213bcafa513c4688011e3e9"
|
||||
"ast_hash": "73db684fd213bcafa513c4688011e3e9",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/backend/app/crud/ethnic.py": {
|
||||
"mtime": 1780108930.727449,
|
||||
"hash": "00eda51c8ed1364f97c402a7473845a7"
|
||||
"ast_hash": "00eda51c8ed1364f97c402a7473845a7",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/backend/app/crud/workflow.py": {
|
||||
"mtime": 1780113998.1283996,
|
||||
"hash": "0f633df841ec3b1add87d19c4dd915f7"
|
||||
"ast_hash": "0f633df841ec3b1add87d19c4dd915f7",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/backend/app/crud/dept.py": {
|
||||
"mtime": 1780113996.9075956,
|
||||
"hash": "be372df2f78a90c68ab8b719a7aa7690"
|
||||
"ast_hash": "be372df2f78a90c68ab8b719a7aa7690",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/backend/app/crud/base.py": {
|
||||
"mtime": 1780108930.7260103,
|
||||
"hash": "06a4dbc841251f19cc2c2c394529f94c"
|
||||
"ast_hash": "06a4dbc841251f19cc2c2c394529f94c",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/backend/app/crud/leave.py": {
|
||||
"mtime": 1780113996.1154153,
|
||||
"hash": "1632690f656222fb876eb136ca2035db"
|
||||
"ast_hash": "1632690f656222fb876eb136ca2035db",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/backend/app/crud/crm/pool_rule.py": {
|
||||
"mtime": 1780148540.1242862,
|
||||
"hash": "e975f0167db96a1895bac63c792b6c97"
|
||||
"mtime": 1780202270.0656207,
|
||||
"ast_hash": "e1692096d32c0fe8c742744725d1a28e",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/backend/app/crud/crm/customer_follow.py": {
|
||||
"mtime": 1780147793.2627335,
|
||||
"hash": "8196ca6a811adcfe69f7d4399c0d164e"
|
||||
"mtime": 1780730768.3131928,
|
||||
"ast_hash": "a9c334b9b2df04b5ac130a58d3c6e21b",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/backend/app/crud/crm/__init__.py": {
|
||||
"mtime": 1780129578.933081,
|
||||
"hash": "d41d8cd98f00b204e9800998ecf8427e"
|
||||
"mtime": 1780201410.2102547,
|
||||
"ast_hash": "d41d8cd98f00b204e9800998ecf8427e",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/backend/app/crud/crm/product.py": {
|
||||
"mtime": 1780129637.8935082,
|
||||
"hash": "434a739ff235bc09da6a80ae363b05f2"
|
||||
"mtime": 1780743830.2505348,
|
||||
"ast_hash": "fc7384d219c7405aec4121235966bae0",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/backend/app/crud/crm/customer.py": {
|
||||
"mtime": 1780148039.453028,
|
||||
"hash": "492328d53b41893fabb02f2c03389c19"
|
||||
"mtime": 1780713573.6127172,
|
||||
"ast_hash": "550c56779b2d3d6a4ad79c792e84eea2",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/backend/app/crud/crm/contact.py": {
|
||||
"mtime": 1780147415.5234418,
|
||||
"hash": "504e27b49e3cca101eba696695702947"
|
||||
"mtime": 1780742842.0334857,
|
||||
"ast_hash": "e6f05d53c32fc8a564af616b7f71ce4e",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/backend/app/api/public.py": {
|
||||
"mtime": 1780132204.7861738,
|
||||
"hash": "b8dbbad0cee1fcfbca1b29fce2709ac3"
|
||||
"mtime": 1780242127.112912,
|
||||
"ast_hash": "535c23e75e73d357bec70077940a8f58",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/backend/app/api/crm.py": {
|
||||
"mtime": 1780150691.0089288,
|
||||
"hash": "0e5d9937b200cf143d7b1f5e7ca39df5"
|
||||
"mtime": 1780743830.2466538,
|
||||
"ast_hash": "2653a10ba9dc92333bb62a12dd58ea4d",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/backend/app/api/__init__.py": {
|
||||
"mtime": 1780129936.4530525,
|
||||
"hash": "8a72471f9488247ccc6483544e3dd015"
|
||||
"mtime": 1780750556.8831582,
|
||||
"ast_hash": "f0ed76e504b60330b436160d96753b61",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/backend/app/api/menu.py": {
|
||||
"mtime": 1780150457.723112,
|
||||
"hash": "f88d23c27bb4142f77c42741ea90b9cd"
|
||||
"mtime": 1780211169.1086953,
|
||||
"ast_hash": "f88d23c27bb4142f77c42741ea90b9cd",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/backend/app/api/admin.py": {
|
||||
"mtime": 1780113995.6094534,
|
||||
"hash": "fb95c76c1927b1140aa1baaa10dfec13"
|
||||
"mtime": 1780736311.9087148,
|
||||
"ast_hash": "b04ea9596095a1f88fd7e4b9ba050144",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/backend/app/api/workflow.py": {
|
||||
"mtime": 1780113993.7604175,
|
||||
"hash": "d1a662b8282b35634082fa2a96fba3f1"
|
||||
"ast_hash": "d1a662b8282b35634082fa2a96fba3f1",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/backend/app/api/leave.py": {
|
||||
"mtime": 1780108930.7226436,
|
||||
"hash": "ee4d128a94fe28cb7c34ff3db71699a1"
|
||||
"ast_hash": "ee4d128a94fe28cb7c34ff3db71699a1",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/backend/app/services/workflow_callback.py": {
|
||||
"mtime": 1780108930.810395,
|
||||
"hash": "6e6a664c5edb9d5f294caef41f5fc477"
|
||||
"ast_hash": "6e6a664c5edb9d5f294caef41f5fc477",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/backend/app/services/workflow_engine.py": {
|
||||
"mtime": 1780113992.9149039,
|
||||
"hash": "fa0d8d7290b264cc636268b3191c4ea7"
|
||||
"ast_hash": "fa0d8d7290b264cc636268b3191c4ea7",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/backend/app/services/web_auth_roles.py": {
|
||||
"mtime": 1780132204.0484734,
|
||||
"hash": "76817c400c5eb1caf47ebe6aa4ab01a4"
|
||||
"mtime": 1780201410.114958,
|
||||
"ast_hash": "76817c400c5eb1caf47ebe6aa4ab01a4",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/backend/app/ws/__init__.py": {
|
||||
"mtime": 1780108930.810617,
|
||||
"hash": "fe3e36317dd396513ca21b57101ee48f"
|
||||
"ast_hash": "fe3e36317dd396513ca21b57101ee48f",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/backend/scripts/generate_dict_reimport_sql.py": {
|
||||
"mtime": 1780134700.0788686,
|
||||
"hash": "c6aae5828051c66f51b0da5561b399f8"
|
||||
"mtime": 1780201410.2450788,
|
||||
"ast_hash": "c6aae5828051c66f51b0da5561b399f8",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/backend/requirements.txt": {
|
||||
"mtime": 1780129939.3284025,
|
||||
"hash": "b253ed31d8d9baf7b62ec4819c9901ef"
|
||||
"mtime": 1780201410.1338527,
|
||||
"ast_hash": "b253ed31d8d9baf7b62ec4819c9901ef",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/backend/README.md": {
|
||||
"mtime": 1780114581.2918417,
|
||||
"hash": "bc7b9cd033927a3f580cd89c5deb6494"
|
||||
"ast_hash": "bc7b9cd033927a3f580cd89c5deb6494",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/backend/start-prod.sh": {
|
||||
"mtime": 1780108930.820144,
|
||||
"ast_hash": "7e463abdbe55313b4e9959312fd91460",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/backend/start.sh": {
|
||||
"mtime": 1780114661.4469833,
|
||||
"ast_hash": "214c10e3fb95b8d7f17bcd5c6dd96126",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/backend/app/core/attachment_biz.py": {
|
||||
"mtime": 1780750904.0571795,
|
||||
"ast_hash": "31445f82b9838f6ddcbf08ecedaea351",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/backend/app/core/bx_auth.py": {
|
||||
"mtime": 1780750556.882335,
|
||||
"ast_hash": "992aca5bcca63b250109f23d36031bdb",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/backend/app/utils/bx_date_range.py": {
|
||||
"mtime": 1780750556.881769,
|
||||
"ast_hash": "c40b659e0b1d8a549e97923a9a536719",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/backend/app/utils/crm_export_columns.py": {
|
||||
"mtime": 1780743830.2552605,
|
||||
"ast_hash": "b24d3dcc0dadcfcc7b6db5171873a852",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/backend/app/utils/__init__.py": {
|
||||
"mtime": 1780242127.0433192,
|
||||
"ast_hash": "d41d8cd98f00b204e9800998ecf8427e",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/backend/app/utils/excel_export.py": {
|
||||
"mtime": 1780242127.113234,
|
||||
"ast_hash": "3a3590bf5730f7eb196963e76d5baa21",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/backend/app/utils/bx_codegen.py": {
|
||||
"mtime": 1780750556.8829591,
|
||||
"ast_hash": "ca25a3c561c4a1bfc566168d85b5f4de",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/backend/app/models/bx_models.py": {
|
||||
"mtime": 1780750591.4901433,
|
||||
"ast_hash": "e8acfeef225d507ed02a31a5e64ba3f1",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/monitor/__init__.py": {
|
||||
"mtime": 1780242127.108406,
|
||||
"ast_hash": "68b329da9893e34099c7d8ad5cb9c940",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/monitor/operlog.py": {
|
||||
"mtime": 1780201410.2162259,
|
||||
"ast_hash": "47b4532502b115b79d489386f8470fbf",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/bx/__init__.py": {
|
||||
"mtime": 1780750556.8817346,
|
||||
"ast_hash": "2cea3812d44c57f24aa7f00648a14412",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/bx/common.py": {
|
||||
"mtime": 1780750556.882896,
|
||||
"ast_hash": "e97cb788e93cfac0688c0aa4cbd2cf93",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/crm/quote.py": {
|
||||
"mtime": 1780745856.749184,
|
||||
"ast_hash": "d3d1b49b13fecb1c34fbb695ca6cafe9",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/crm/supplier_info.py": {
|
||||
"mtime": 1780242127.1122696,
|
||||
"ast_hash": "60446fd83e876332a414fecefc3216ee",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/crm/opportunity.py": {
|
||||
"mtime": 1780242127.112297,
|
||||
"ast_hash": "6af8aec9a012bb026f75feebab2f41f3",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/crm/clue.py": {
|
||||
"mtime": 1780215022.1890757,
|
||||
"ast_hash": "fce08aacb7699a63010fcd3f29f8a965",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/crm/statistics.py": {
|
||||
"mtime": 1780201410.2159066,
|
||||
"ast_hash": "6b5620e22a44ce3555597fe45d968813",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/crm/contract.py": {
|
||||
"mtime": 1780750556.8821254,
|
||||
"ast_hash": "6553f54ca1fd19086c170095f402a628",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/crm/invoice_info.py": {
|
||||
"mtime": 1780406386.885208,
|
||||
"ast_hash": "910b8037a62a9af50f5803f8a243e3ae",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/backend/app/crud/oss.py": {
|
||||
"mtime": 1780201410.2129664,
|
||||
"ast_hash": "8ee3bcd0df19a921a7530e52c89e4866",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/backend/app/crud/monitor/__init__.py": {
|
||||
"mtime": 1780242127.1123073,
|
||||
"ast_hash": "68b329da9893e34099c7d8ad5cb9c940",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/backend/app/crud/monitor/oper_log.py": {
|
||||
"mtime": 1780201410.2128606,
|
||||
"ast_hash": "4cfec230d90a820a2350201da6e940bf",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/backend/app/crud/crm/contract_product.py": {
|
||||
"mtime": 1780750556.8823483,
|
||||
"ast_hash": "d2e1538af2d36ecc9daf28a3b135bd0f",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/backend/app/crud/crm/customer_pool.py": {
|
||||
"mtime": 1780202237.3421319,
|
||||
"ast_hash": "a54f2cb33f4466814ac86f043d844b98",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/backend/app/crud/crm/contract_approval.py": {
|
||||
"mtime": 1780750556.8831775,
|
||||
"ast_hash": "c9c338510247afdcd733412c10e0ded3",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/backend/app/crud/crm/opportunity_follow.py": {
|
||||
"mtime": 1780242127.1121516,
|
||||
"ast_hash": "6fe6db9ed2c4f2a7b703464c83961fdf",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/backend/app/crud/crm/quote.py": {
|
||||
"mtime": 1780745858.4985561,
|
||||
"ast_hash": "a70dc5bf1f9cf76746aa2c0718041690",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/backend/app/crud/crm/clue_follow.py": {
|
||||
"mtime": 1780215022.1935425,
|
||||
"ast_hash": "5ac9d3d0e7c35d761bdfda85a19b3178",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/backend/app/crud/crm/quote_product.py": {
|
||||
"mtime": 1780242127.0685878,
|
||||
"ast_hash": "99a00e493072478bdd3e91e6436efd99",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/backend/app/crud/crm/supplier_info.py": {
|
||||
"mtime": 1780242127.1134887,
|
||||
"ast_hash": "7d09a0306a02be994c6cb455c7238e3a",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/backend/app/crud/crm/quote_share_log.py": {
|
||||
"mtime": 1780242127.1124375,
|
||||
"ast_hash": "a07b92a54b8b0306dfc06845f038a52d",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/backend/app/crud/crm/quote_approval.py": {
|
||||
"mtime": 1780736832.004071,
|
||||
"ast_hash": "7af79c7ce3f3d5b8a42260b68f9613d6",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/backend/app/crud/crm/opportunity_product.py": {
|
||||
"mtime": 1780242127.0218031,
|
||||
"ast_hash": "715eeca2e6270b4527ceec40c4007e11",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/backend/app/crud/crm/opportunity.py": {
|
||||
"mtime": 1780242127.1123164,
|
||||
"ast_hash": "fca0ee3a3a9d131cf586c8e25f67e40b",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/backend/app/crud/crm/clue.py": {
|
||||
"mtime": 1780215022.193645,
|
||||
"ast_hash": "6a233d23691eee9749ebb7848b54e650",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/backend/app/crud/crm/clue_statistics.py": {
|
||||
"mtime": 1780750556.8829157,
|
||||
"ast_hash": "9a026c628764467e4d1398900105dc78",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/backend/app/crud/crm/statistics.py": {
|
||||
"mtime": 1780201410.2125814,
|
||||
"ast_hash": "a881a548c85953fc7da786343d69b9f8",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/backend/app/crud/crm/contract.py": {
|
||||
"mtime": 1780750556.8728096,
|
||||
"ast_hash": "3cd90455687d8cc24d4b664d1fd5eaa2",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/backend/app/crud/crm/invoice_info.py": {
|
||||
"mtime": 1780406390.4614334,
|
||||
"ast_hash": "c64a80cd0c5825f111e30fb6d745a40f",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/backend/app/api/monitor.py": {
|
||||
"mtime": 1780201410.2100992,
|
||||
"ast_hash": "438a2c9feb094343269bc83f7d1e884e",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/backend/app/api/crm_contract_sub_routes.py": {
|
||||
"mtime": 1780750556.8831708,
|
||||
"ast_hash": "c05e2faf142cb664a73975112d26d658",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/backend/app/api/crm_quote_routes.py": {
|
||||
"mtime": 1780736833.57648,
|
||||
"ast_hash": "1c648042be53d61883b62f966aa900ca",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/backend/app/api/crm_contract_routes.py": {
|
||||
"mtime": 1780750556.8818061,
|
||||
"ast_hash": "e12302586789d2e8cf85469226be2899",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/__init__.py": {
|
||||
"mtime": 1780751360.1800659,
|
||||
"ast_hash": "683657a15bc1923bff7a7d60f1dd965d",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/backend/app/services/crm_quote_pdf.py": {
|
||||
"mtime": 1780242127.1123822,
|
||||
"ast_hash": "c6247a99b20d9541dbabd49791104918",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/bx/expense_item.py": {
|
||||
"mtime": 1780750595.66133,
|
||||
"ast_hash": "2dcb1f8935122ecc1129d47f41329e2d",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/bx/workflow.py": {
|
||||
"mtime": 1780750597.0023274,
|
||||
"ast_hash": "84a4177765ae7baf25f55b8a7858cffe",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/expense_item.py": {
|
||||
"mtime": 1780750631.6409054,
|
||||
"ast_hash": "ec3143dd9c80ed89ccbdada33af3b048",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/workflow.py": {
|
||||
"mtime": 1780750609.568306,
|
||||
"ast_hash": "254bddbaabdcab96560f20fe41924675",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/expense_item.py": {
|
||||
"mtime": 1780750601.2191534,
|
||||
"ast_hash": "a3f9e3f9e03b2b81d048be2fbb995a53",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/__init__.py": {
|
||||
"mtime": 1780750594.045302,
|
||||
"ast_hash": "782178a68c005e9671eeaef56ce8979f",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/workflow.py": {
|
||||
"mtime": 1780750604.01886,
|
||||
"ast_hash": "28fdbea9fada1d94d7de516d3979682d",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/base.py": {
|
||||
"mtime": 1780750593.8290622,
|
||||
"ast_hash": "1e6a5197afea4b037af84cccf34a884b",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/bx/attachment.py": {
|
||||
"mtime": 1780750871.4800005,
|
||||
"ast_hash": "97ee54c0f5e7e6944a6d5edba9959b7b",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/bx/advance.py": {
|
||||
"mtime": 1780751332.9608216,
|
||||
"ast_hash": "cfef88a2406327f06f40623d0449b0f1",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/attachment.py": {
|
||||
"mtime": 1780750903.379992,
|
||||
"ast_hash": "c3d0da835eff5f4d08d174741c7faa83",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/advance.py": {
|
||||
"mtime": 1780750899.1853952,
|
||||
"ast_hash": "9c83a5bfd6e2e780c216585ea3df6884",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/attachment.py": {
|
||||
"mtime": 1780750887.666369,
|
||||
"ast_hash": "1534ad3911e5b3da36e09fec5efbb9fc",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/advance.py": {
|
||||
"mtime": 1780751337.5985446,
|
||||
"ast_hash": "f37820e31e876d2d9c3e7aecd61c64f6",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/storage.py": {
|
||||
"mtime": 1780750869.826924,
|
||||
"ast_hash": "a2549a79ff52c07c21bcdce831ca28f5",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/bx/reimburse.py": {
|
||||
"mtime": 1780751335.1849163,
|
||||
"ast_hash": "4d040ab00d9288b03a0e5448e54340cd",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/reimburse.py": {
|
||||
"mtime": 1780751015.345417,
|
||||
"ast_hash": "c0024c52ab77393141773302deaa44e5",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/reimburse.py": {
|
||||
"mtime": 1780751365.9291217,
|
||||
"ast_hash": "cd82cdcd1fecce13dd5c078782e128a5",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/payment.py": {
|
||||
"mtime": 1780751365.9410522,
|
||||
"ast_hash": "f9e1133888b3bf36e702a6e303623a34",
|
||||
"semantic_hash": ""
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,469 @@
|
||||
# 报销系统(bx)移植实施方案
|
||||
|
||||
> **编写日期**:2026-06-06
|
||||
> **状态**:方案已定稿,待按阶段实施
|
||||
> **源系统**:`shanxia/bx/bx-backend` + `shanxia/bx/bx-web`
|
||||
> **目标系统**:`shanxia2.0/backend` + `shanxia2.0/web-admin`
|
||||
> **DDL 基线**:`docs/sql/20260606_bx_tables.sql`(已在 shanxia2.0 库执行)
|
||||
|
||||
---
|
||||
|
||||
## 1. 迁移目标
|
||||
|
||||
将原报销系统业务功能迁入山峡一体化门户(shanxia2.0),实现:
|
||||
|
||||
1. **业务等价**:备用金、报销、工作流、支付/冲抵、视图中心等能力与 bx 原系统一致;
|
||||
2. **协议兼容**:移植 API 保持 bx 原 **REST 风格**(GET/PUT/DELETE/POST)、**入参位置**、**响应 envelope**(`code:0`、`msg`、`data.rows`),**不**统一为 CRM 的 POST Body 风格;
|
||||
3. **体系融合**:用户/角色/菜单/认证使用门户 `sys_*`,业务表使用 `bx_*` + 门户公共字段;
|
||||
4. **UI 融合**:Web 端挂「报销管理」一级菜单,页面适配 Fresh Mint 规范(第二阶段)。
|
||||
|
||||
**不在本次范围**:`bx-mobile` 移动端、`bx_user/bx_role/bx_menu` 等独立权限表、历史业务数据导入(空库启动)。
|
||||
|
||||
---
|
||||
|
||||
## 2. 范围边界
|
||||
|
||||
### 2.1 数据库(10 张业务表,已完成 DDL)
|
||||
|
||||
| 表 | 用途 | DDL 状态 |
|
||||
|----|------|---------|
|
||||
| `bx_expense_item` | 费用项目(二级树) | ✅ |
|
||||
| `bx_workflow_def` | 工作流定义 | ✅ |
|
||||
| `bx_workflow_node` | 工作流节点 | ✅ |
|
||||
| `bx_advance_apply` | 备用金申请 | ✅ |
|
||||
| `bx_advance_approval` | 备用金审批记录 | ✅ |
|
||||
| `bx_reimburse_apply` | 报销申请 | ✅ |
|
||||
| `bx_reimburse_detail` | 报销明细 | ✅ |
|
||||
| `bx_reimburse_approval` | 报销审批记录 | ✅ |
|
||||
| `bx_reimburse_offset` | 冲抵关联 | ✅ |
|
||||
| `bx_attachment` | 附件 | ✅ |
|
||||
|
||||
**不建表**:`bx_user`、`bx_role`、`bx_role_user`、`bx_menu`、`bx_menu_role`。
|
||||
|
||||
### 2.2 后端 API(约 60 个端点,待移植)
|
||||
|
||||
| 模块 | 源文件 | 端点数 | 优先级 |
|
||||
|------|--------|--------|--------|
|
||||
| 费用项目 | `routers/expense_item.py` | 5 | P1 |
|
||||
| 工作流 | `routers/workflow.py` | 8 | P1 |
|
||||
| 备用金 | `routers/advance.py` | 14 | P2 |
|
||||
| 附件 | `routers/attachment.py` | 6 | P2 |
|
||||
| 报销 | `routers/reimburse.py` | 15 | P3 |
|
||||
| 支付/发放 | `routers/payment.py` | 12 | P4 |
|
||||
|
||||
**不移植**:`auth.py`、`user.py`、`role.py`、`menu.py`。
|
||||
|
||||
### 2.3 前端页面(13 页,第二阶段)
|
||||
|
||||
| 分组 | 页面 | 源文件 |
|
||||
|------|------|--------|
|
||||
| 基础配置 | 费用项目管理、工作流(备用金)、工作流(报销) | `ExpenseProjectPage`、`WfAdvancePage`、`WfReimbursePage` |
|
||||
| 备用金 | 申请、审批、发放管理 | `AdvanceApplyPage`、`AdvanceApprovePage`、`AdvanceIssuePage` |
|
||||
| 报销 | 申请、审批、支付管理 | `ReimburseApplyPage`、`ReimburseApprovePage`、`PaymentPage` |
|
||||
| 视图中心 | 我的申请、待我审批、全部申请单 | `MinePage`、`TodoPage`、`AllPage` |
|
||||
|
||||
**不移植**:用户/角色/菜单管理、首页 Dashboard、Demo 页。
|
||||
|
||||
---
|
||||
|
||||
## 3. 核心原则(与 CRM 移植的差异)
|
||||
|
||||
| 原则 | 说明 |
|
||||
|------|------|
|
||||
| **API 协议保持 bx 原样** | 列表用 GET + Query;响应 `{ code: 0, msg, data }`;分页 `data.rows`;**禁止**改为门户 `code:200` / `message` / `data.list` |
|
||||
| **Router 近原样复制** | 从 `bx-backend/app/routers/` 复制到 `backend/app/api/bx/`,仅改 Depends、import、前缀、租户注入 |
|
||||
| **Service 选择性迁移** | `services/*.py` 业务算法可复用;必须加 `tenant_no`、UUID 主键、`sys_user` 用户 ID |
|
||||
| **不走 CRM crud 分层** | bx 模块内部保持 `router → service → model`,不强制拆 `crud/bx/`(除非后续维护需要) |
|
||||
| **最小改动** | 不重命名 URL、不改 HTTP 方法、不改前端 camelCase 字段名 |
|
||||
| **门户能力注入** | 认证、租户、DB Session、对象存储用 shanxia2.0 现有能力 |
|
||||
|
||||
---
|
||||
|
||||
## 4. 源系统与目标系统对照
|
||||
|
||||
### 4.1 技术栈(同源,利于移植)
|
||||
|
||||
| 项 | bx-backend | shanxia2.0 backend |
|
||||
|----|-----------|-------------------|
|
||||
| 语言 | Python 3 | Python 3.9 |
|
||||
| 框架 | FastAPI | FastAPI |
|
||||
| ORM | SQLAlchemy | SQLAlchemy |
|
||||
| 校验 | Pydantic v2 | Pydantic v2 |
|
||||
|
||||
### 4.2 API 协议对照
|
||||
|
||||
| 维度 | bx 原系统 | shanxia2.0 CRM(勿用于 bx) | bx 移植目标 |
|
||||
|------|----------|---------------------------|------------|
|
||||
| 成功码 | `0` | `200` | **保持 `0`** |
|
||||
| 消息字段 | `msg` | `message` | **保持 `msg`** |
|
||||
| 时间戳 | 无 | `timestamp` | **不加** |
|
||||
| 分页字段 | `rows, total, page, pageSize` | `list, total, page, pageSize` | **保持 `rows`** |
|
||||
| 列表请求 | GET + query | POST + body | **保持 GET** |
|
||||
| 路径示例 | `/api/advances/` | `/api/web/crm/customer/list` | **保持 `/api/advances/`** |
|
||||
|
||||
### 4.3 数据模型对照
|
||||
|
||||
| 维度 | bx 原 sx.sql | shanxia2.0 已执行 DDL |
|
||||
|------|-------------|----------------------|
|
||||
| 主键 | `bigint AUTO_INCREMENT` | `varchar(64) UUID` |
|
||||
| 外键 ID | `bigint` | `varchar(64)` |
|
||||
| 租户 | 无 | `tenant_no DEFAULT 'shanxia2.0'` |
|
||||
| 用户引用 | `bx_user.id` | `sys_user.id` |
|
||||
|
||||
---
|
||||
|
||||
## 5. 目标架构
|
||||
|
||||
### 5.1 后端目录结构
|
||||
|
||||
```
|
||||
backend/app/
|
||||
├── models/bx_models.py # 10 张表 ORM(对齐 20260606 DDL)
|
||||
├── schemas/bx/
|
||||
│ ├── common.py # ApiResponse / PagedData(从 bx 复制)
|
||||
│ ├── expense_item.py
|
||||
│ ├── workflow.py
|
||||
│ ├── advance.py
|
||||
│ ├── reimburse.py
|
||||
│ ├── payment.py
|
||||
│ └── attachment.py # id: int → str
|
||||
├── services/bx/ # 从 bx-backend/services 迁移
|
||||
│ ├── base.py # 可选:通用分页(改 UUID)
|
||||
│ ├── expense_item.py
|
||||
│ ├── workflow.py
|
||||
│ ├── advance.py
|
||||
│ ├── reimburse.py
|
||||
│ ├── payment.py
|
||||
│ └── attachment.py
|
||||
├── core/
|
||||
│ └── bx_auth.py # 门户 user → BxUserContext
|
||||
└── api/bx/
|
||||
├── __init__.py # 聚合 bx_router
|
||||
├── expense_item.py # prefix="/expense-items"
|
||||
├── workflow.py # prefix="/workflows"
|
||||
├── advance.py # prefix="/advances"
|
||||
├── reimburse.py # prefix="/reimburses"
|
||||
├── payment.py # prefix="/payments"
|
||||
└── attachment.py # prefix="/attachments"
|
||||
```
|
||||
|
||||
### 5.2 路由挂载(避免 `/api/api/...`)
|
||||
|
||||
bx 原 router 前缀为 `/api/advances`;门户 `main.py` 已挂 `prefix="/api"`。
|
||||
|
||||
**规则**:bx router 的 `APIRouter(prefix=...)` **去掉 `/api`**,例如:
|
||||
|
||||
```python
|
||||
# bx 原:prefix="/api/advances"
|
||||
# 门户:prefix="/advances"
|
||||
router = APIRouter(prefix="/advances", tags=["备用金管理"])
|
||||
```
|
||||
|
||||
```python
|
||||
# main.py
|
||||
from app.api.bx import bx_router
|
||||
app.include_router(bx_router, prefix=settings.API_V1_PREFIX) # → /api/advances/...
|
||||
```
|
||||
|
||||
### 5.3 响应包装(独立体系)
|
||||
|
||||
bx 模块 **禁止** 使用 `app.core.response.success_response()`。
|
||||
|
||||
统一使用 `schemas/bx/common.py`:
|
||||
|
||||
```python
|
||||
class ApiResponse(BaseModel, Generic[T]):
|
||||
code: int = 0
|
||||
msg: str = "success"
|
||||
data: Optional[T] = None
|
||||
|
||||
class PagedData(BaseModel, Generic[T]):
|
||||
rows: List[T]
|
||||
total: int
|
||||
page: int
|
||||
page_size: int # JSON 序列化为 pageSize(alias_generator=to_camel)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 6. 门户适配层
|
||||
|
||||
### 6.1 认证(`core/bx_auth.py`)
|
||||
|
||||
bx 原:`get_current_user` → ORM `User`,`user.id: int`
|
||||
门户:`require_admin_or_super_admin` → `dict`,`user_id: str`
|
||||
|
||||
```python
|
||||
@dataclass
|
||||
class BxUserContext:
|
||||
id: str # sys_user.id
|
||||
name: str # nick_name 冗余写入 applicant_name 等
|
||||
dept_id: str # create_dept_id
|
||||
|
||||
def get_bx_current_user(user: dict = Depends(require_admin_or_super_admin)) -> BxUserContext:
|
||||
...
|
||||
```
|
||||
|
||||
Router 中:`Depends(get_current_user)` → `Depends(get_bx_current_user)`。
|
||||
|
||||
### 6.2 租户隔离
|
||||
|
||||
所有业务查询/写入通过 `get_tenant_no(db, user_dict)` 获取 `tenant_no`,在 Service 层追加:
|
||||
|
||||
```python
|
||||
query.filter(Model.tenant_no == tenant_no, Model.del_flag == 0)
|
||||
```
|
||||
|
||||
创建记录时:
|
||||
|
||||
```python
|
||||
obj_in["id"] = generate_uuid()
|
||||
obj_in["tenant_no"] = tenant_no
|
||||
obj_in["create_by"] = user.id
|
||||
obj_in["create_dept_id"] = user.dept_id or ""
|
||||
```
|
||||
|
||||
### 6.3 API 加密中间件
|
||||
|
||||
门户默认对 `/api/*` 启用 `ApiCryptoMiddleware`;bx 原系统无加密。
|
||||
|
||||
**开发阶段**:将 bx 业务路径加入 `API_ENCRYPT_EXCLUDE_PATHS`(`backend/app/core/config.py`):
|
||||
|
||||
```
|
||||
/api/expense-items,
|
||||
/api/workflows,
|
||||
/api/advances,
|
||||
/api/reimburses,
|
||||
/api/payments,
|
||||
/api/attachments
|
||||
```
|
||||
|
||||
**前端接入 web-admin 后**:评估是否改为走门户加密(需 bx 页 axios 适配),或长期保持 exclude。
|
||||
|
||||
### 6.4 附件 / MinIO
|
||||
|
||||
不直接拷贝 `bx-backend/app/services/minio.py`。实现 `services/bx/storage.py` 适配器,内部调用门户已有 OSS/MinIO 上传能力,对外仍暴露:
|
||||
|
||||
- `POST /api/attachments/upload`(multipart)
|
||||
- `GET /api/attachments/download/{id}`(StreamingResponse)
|
||||
- `GET /api/attachments/preview/{id}`
|
||||
|
||||
---
|
||||
|
||||
## 7. 分阶段实施计划
|
||||
|
||||
### 总览
|
||||
|
||||
```
|
||||
P0 基础设施 → P1 基础配置 → P2 备用金+附件 → P3 报销 → P4 支付 → P5 菜单 → P6 前端
|
||||
│ │ │ │ │ │ │
|
||||
ORM/Auth expense+wf advance reimburse payment sys_menu web-admin
|
||||
```
|
||||
|
||||
### P0:基础设施(后端骨架)
|
||||
|
||||
| 步骤 | 任务 | 产出 | 完成标准 |
|
||||
|------|------|------|---------|
|
||||
| P0-1 | 创建 `models/bx_models.py` | 10 表 ORM | 字段顺序与 DDL 一致 |
|
||||
| P0-2 | 创建 `schemas/bx/common.py` | ApiResponse / PagedData | 与 bx 响应一致 |
|
||||
| P0-3 | 创建 `core/bx_auth.py` | BxUserContext + Depends | 能解析门户 JWT 用户 |
|
||||
| P0-4 | 创建 `api/bx/__init__.py` | 空 bx_router | main.py 可注册 |
|
||||
| P0-5 | 配置加密排除路径 | config 更新 | bx 路径不加密 |
|
||||
| P0-6 | 迁移 `utils/codegen.py`、`date_range.py` | 单号生成等 | 单元可调用 |
|
||||
|
||||
**验收**:服务启动无报错;`GET /api/health` 正常;bx_router 已挂载。
|
||||
|
||||
---
|
||||
|
||||
### P1:基础配置(费用项目 + 工作流)
|
||||
|
||||
| 步骤 | 任务 | 源参考 |
|
||||
|------|------|--------|
|
||||
| P1-1 | `schemas/bx/expense_item.py` | `bx-backend/app/schemas/expense_item.py` |
|
||||
| P1-2 | `services/bx/expense_item.py` | 加 tenant + UUID |
|
||||
| P1-3 | `api/bx/expense_item.py` | 5 端点原样 |
|
||||
| P1-4 | `schemas/bx/workflow.py` + service + router | 8 端点 |
|
||||
|
||||
**API 清单**:
|
||||
|
||||
| 方法 | 路径 |
|
||||
|------|------|
|
||||
| GET | `/api/expense-items/tree` |
|
||||
| GET/POST/PUT/DELETE | `/api/expense-items/`、`/api/expense-items/{item_id}` |
|
||||
| GET | `/api/workflows/`、`/api/workflows/biz/{biz_type}`、`/api/workflows/{workflow_id}` |
|
||||
| POST/PUT/DELETE | `/api/workflows/`、`/api/workflows/{workflow_id}` |
|
||||
| PUT | `/api/workflows/{workflow_id}/nodes` |
|
||||
|
||||
**验收**:Swagger 可调通 CRUD;费用树、工作流节点保存与原 bx 行为一致。
|
||||
|
||||
---
|
||||
|
||||
### P2:备用金 + 附件
|
||||
|
||||
| 步骤 | 任务 | 说明 |
|
||||
|------|------|------|
|
||||
| P2-1 | advance schemas / service / router | 含 submit/approve/reject 状态机 |
|
||||
| P2-2 | attachment storage 适配 + router | upload/download/preview/bind-biz |
|
||||
| P2-3 | 联调:申请 → 上传附件 → 提交审批 | 端到端 |
|
||||
|
||||
**API 清单(advance,14 端点)**:
|
||||
|
||||
| 方法 | 路径 |
|
||||
|------|------|
|
||||
| GET | `/api/advances/`、`/my`、`/my/stats`、`/stats/status-counts` |
|
||||
| GET | `/api/advances/pending-approval`、`/pending-approval/stats`、`/approved-by-me` |
|
||||
| GET | `/api/advances/{advance_id}`、`/{advance_id}/approvals` |
|
||||
| POST | `/api/advances/`、`/{advance_id}/submit`、`/approve`、`/reject` |
|
||||
| PUT/DELETE | `/api/advances/{advance_id}` |
|
||||
|
||||
**验收**:完整备用金审批链路;附件 upload/list/download 可用。
|
||||
|
||||
---
|
||||
|
||||
### P3:报销
|
||||
|
||||
| 步骤 | 任务 |
|
||||
|------|------|
|
||||
| P3-1 | reimburse schemas(含 detail) |
|
||||
| P3-2 | reimburse service(明细、标题生成) |
|
||||
| P3-3 | reimburse router(15 端点) |
|
||||
|
||||
**验收**:报销申请 CRUD + 明细 + 审批流与 bx 一致。
|
||||
|
||||
---
|
||||
|
||||
### P4:支付 / 发放 / 冲抵
|
||||
|
||||
| 步骤 | 任务 |
|
||||
|------|------|
|
||||
| P4-1 | payment service(最复杂:pay/offset/issue/batch-offset) |
|
||||
| P4-2 | payment router(含 CSV export StreamingResponse) |
|
||||
|
||||
**验收**:报销支付、备用金发放、冲抵关联、offset-records 查询正确。
|
||||
|
||||
---
|
||||
|
||||
### P5:菜单与权限(门户 sys_menu)
|
||||
|
||||
在 `sys_menu` 新增一级 **「报销管理」**(`parent_id='2'`,Web 端根),子结构:
|
||||
|
||||
```
|
||||
报销管理
|
||||
├── 基础配置
|
||||
│ ├── 费用项目管理
|
||||
│ ├── 工作流配置(备用金)
|
||||
│ └── 工作流配置(报销单)
|
||||
├── 备用金
|
||||
│ ├── 备用金申请
|
||||
│ ├── 备用金审批
|
||||
│ └── 备用金发放管理
|
||||
├── 报销
|
||||
│ ├── 报销申请
|
||||
│ ├── 报销审批
|
||||
│ └── 支付管理(发放/冲抵)
|
||||
└── 视图中心
|
||||
├── 我的申请单
|
||||
├── 待我审批
|
||||
└── 全部申请单(总经理)
|
||||
```
|
||||
|
||||
权限标识(`perms`)建议前缀 `bx:`,与 CRM `crm:` 并列。角色-菜单通过 `sys_role_menu` 配置(可参考 bx 原 `bx-menu-role-init.sql` 角色语义:员工/财务/总经理)。
|
||||
|
||||
**验收**:admin 登录可见菜单;无权限用户 403。
|
||||
|
||||
---
|
||||
|
||||
### P6:前端移植(web-admin)
|
||||
|
||||
| 步骤 | 任务 | 参考 |
|
||||
|------|------|------|
|
||||
| P6-1 | 拷贝 `bx-web/src/views/pages/*.vue` → `web-admin/src/views/bx/` | 排除 User/Role/Menu/Home/Demo |
|
||||
| P6-2 | 拷贝/适配 `bx-web/src/api/` | baseURL 指向门户 `/api`,协议已是 bx 风格 |
|
||||
| P6-3 | Fresh Mint UI 适配 | 参考 `docs/crm-migration/step-03-frontend-adapt.md` |
|
||||
| P6-4 | 认证改为门户登录态 | 不再调 `/api/auth/login` |
|
||||
| P6-5 | 用户下拉改用 `sys_user` API | 替代 `userApi.dropdown` |
|
||||
| P6-6 | 路由与 component 路径对齐 sys_menu | hash 路由 |
|
||||
|
||||
**UI 规范**:`docs/web-admin-ui-spec-fresh-mint.md`;列表参考 `/#/demo/order`,树形参考 `/#/demo/category`。
|
||||
|
||||
**验收**:各页面功能与 bx-web 对照通过;UI 符合 Fresh Mint。
|
||||
|
||||
---
|
||||
|
||||
## 8. 单模块后端实施 SOP(每个模块重复)
|
||||
|
||||
1. **读源**:`bx-backend/app/routers/{module}.py` + `services/{module}.py`,中文简述业务逻辑
|
||||
2. **Schema**:复制到 `schemas/bx/`,`id` 及外键改 `str`,保留 camelCase alias
|
||||
3. **Service**:复制到 `services/bx/`,追加 `tenant_no` 过滤、UUID 生成、用户字段映射
|
||||
4. **Router**:复制到 `api/bx/`,改 Depends / import / prefix(去 `/api`)
|
||||
5. **注册**:在 `api/bx/__init__.py` include_router
|
||||
6. **验证**:Swagger 或 Postman 对照 bx 原接口逐项测试
|
||||
7. **更新**:[module-status.md](./module-status.md)
|
||||
|
||||
---
|
||||
|
||||
## 9. 完整 API 路径索引(移植后保持不变)
|
||||
|
||||
详见 [01-api-inventory.md](./01-api-inventory.md)。
|
||||
|
||||
---
|
||||
|
||||
## 10. 验证清单
|
||||
|
||||
### 10.1 后端协议
|
||||
|
||||
- [ ] 成功响应 `code === 0`,字段名为 `msg`(非 `message`)
|
||||
- [ ] 分页 `data.rows`(非 `data.list`)
|
||||
- [ ] 列表接口为 GET + query 参数
|
||||
- [ ] 路径与 bx-web `api/index.ts` 一致
|
||||
- [ ] 错误时 HTTP 4xx/5xx + 合理 detail(与 bx 行为接近)
|
||||
|
||||
### 10.2 业务
|
||||
|
||||
- [ ] 费用项目二级树 CRUD
|
||||
- [ ] 工作流定义 + 节点保存(advance / reimburse 各一条)
|
||||
- [ ] 备用金:草稿 → 提交 → 多级审批 → 驳回/通过 → 发放
|
||||
- [ ] 报销:申请 + 明细 + 审批 + 支付/冲抵
|
||||
- [ ] 附件:upload → bind-biz → download/preview
|
||||
- [ ] 视图:我的 / 待办 / 全部(总经理)
|
||||
|
||||
### 10.3 门户集成
|
||||
|
||||
- [ ] 租户隔离:不同 tenant 数据不可见
|
||||
- [ ] 门户 JWT 可访问 bx 接口
|
||||
- [ ] 菜单权限控制生效
|
||||
|
||||
---
|
||||
|
||||
## 11. 风险与对策
|
||||
|
||||
| 风险 | 对策 |
|
||||
|------|------|
|
||||
| ID 类型 int→str,前端 bx 页仍用 number | Schema 用 str;前端 P6 逐步改类型;JSON 字符串 ID 可兼容 |
|
||||
| API 加密与 bx GET 冲突 | 开发期 exclude;联调后再定是否前端加密 |
|
||||
| 门户与 bx 响应双标准并存 | bx 模块独立 common.py,禁止混用 success_response |
|
||||
| payment 业务复杂 | 单独 P4,充分对照 bx service 单测/手测 |
|
||||
| 审批人取自 workflow_node.approver_id | 配置工作流时选 sys_user,与原 bx 选 bx_user 操作一致 |
|
||||
|
||||
---
|
||||
|
||||
## 12. 文档索引
|
||||
|
||||
| 文档 | 用途 |
|
||||
|------|------|
|
||||
| [00-migration-plan.md](./00-migration-plan.md) | 本文:总实施方案 |
|
||||
| [module-status.md](./module-status.md) | 模块进度跟踪 |
|
||||
| [01-api-inventory.md](./01-api-inventory.md) | 全量 API 路径与方法 |
|
||||
| [ref-backend-adapt.md](./ref-backend-adapt.md) | 后端适配细则(认证/租户/Service 改造清单) |
|
||||
| `docs/sql/20260606_bx_tables.sql` | DDL 权威来源 |
|
||||
| `docs/sql/sx.sql` | bx 原表业务字段对照 |
|
||||
| `docs/crm-migration/ref-lessons-learned.md` | 前端/UI 踩坑(P6 参考) |
|
||||
| `docs/web-admin-ui-spec-fresh-mint.md` | Web UI 规范(P6) |
|
||||
|
||||
---
|
||||
|
||||
## 13. 下一步行动
|
||||
|
||||
**当前建议从 P0 开始**:创建 `bx_models.py`、`schemas/bx/common.py`、`core/bx_auth.py` 并挂载空 `bx_router`。
|
||||
|
||||
每完成一个阶段,更新 [module-status.md](./module-status.md) 并在 PR/提交说明中标注阶段编号(如 `bx P1 expense-item`)。
|
||||
@@ -0,0 +1,141 @@
|
||||
# 报销系统 API 全量清单(移植后路径保持不变)
|
||||
|
||||
> 源:`shanxia/bx/bx-backend/app/routers/` + `shanxia/bx/bx-web/src/api/index.ts`
|
||||
> 挂载:门户 `API_V1_PREFIX=/api` + router prefix(**不含** `/api` 前缀)
|
||||
|
||||
---
|
||||
|
||||
## 费用项目 `/api/expense-items`
|
||||
|
||||
| 方法 | 路径 | 说明 |
|
||||
|------|------|------|
|
||||
| GET | `/api/expense-items/tree` | 费用项目树 |
|
||||
| GET | `/api/expense-items/{item_id}` | 详情 |
|
||||
| POST | `/api/expense-items/` | 新增 |
|
||||
| PUT | `/api/expense-items/{item_id}` | 更新 |
|
||||
| DELETE | `/api/expense-items/{item_id}` | 软删除 |
|
||||
|
||||
---
|
||||
|
||||
## 工作流 `/api/workflows`
|
||||
|
||||
| 方法 | 路径 | 说明 |
|
||||
|------|------|------|
|
||||
| GET | `/api/workflows/` | 分页列表(page, pageSize) |
|
||||
| GET | `/api/workflows/biz/{biz_type}` | 按业务类型(advance / reimburse) |
|
||||
| GET | `/api/workflows/{workflow_id}` | 详情(含节点) |
|
||||
| POST | `/api/workflows/` | 新增(body 可含 nodes) |
|
||||
| PUT | `/api/workflows/{workflow_id}` | 更新 |
|
||||
| PUT | `/api/workflows/{workflow_id}/nodes` | 保存节点列表 |
|
||||
| DELETE | `/api/workflows/{workflow_id}` | 软删除 |
|
||||
|
||||
---
|
||||
|
||||
## 备用金 `/api/advances`
|
||||
|
||||
| 方法 | 路径 | 说明 |
|
||||
|------|------|------|
|
||||
| GET | `/api/advances/` | 列表(status, keyword, applicantId, applyDate) |
|
||||
| GET | `/api/advances/my` | 我的申请 |
|
||||
| GET | `/api/advances/my/stats` | 我的统计 |
|
||||
| GET | `/api/advances/stats/status-counts` | 状态计数 |
|
||||
| GET | `/api/advances/pending-approval` | 待我审批 |
|
||||
| GET | `/api/advances/pending-approval/stats` | 待审批统计 |
|
||||
| GET | `/api/advances/approved-by-me` | 我已审批 |
|
||||
| GET | `/api/advances/{advance_id}` | 详情 |
|
||||
| GET | `/api/advances/{advance_id}/approvals` | 审批记录 |
|
||||
| POST | `/api/advances/` | 新增 |
|
||||
| PUT | `/api/advances/{advance_id}` | 更新 |
|
||||
| POST | `/api/advances/{advance_id}/submit` | 提交 |
|
||||
| POST | `/api/advances/{advance_id}/approve` | 审批通过 |
|
||||
| POST | `/api/advances/{advance_id}/reject` | 审批驳回 |
|
||||
| DELETE | `/api/advances/{advance_id}` | 软删除 |
|
||||
|
||||
---
|
||||
|
||||
## 报销 `/api/reimburses`
|
||||
|
||||
| 方法 | 路径 | 说明 |
|
||||
|------|------|------|
|
||||
| GET | `/api/reimburses/generate-title` | 自动生成标题 |
|
||||
| GET | `/api/reimburses/` | 列表 |
|
||||
| GET | `/api/reimburses/my` | 我的申请 |
|
||||
| GET | `/api/reimburses/my/stats` | 我的统计 |
|
||||
| GET | `/api/reimburses/stats/status-counts` | 状态计数 |
|
||||
| GET | `/api/reimburses/pending-approval` | 待我审批 |
|
||||
| GET | `/api/reimburses/pending-approval/stats` | 待审批统计 |
|
||||
| GET | `/api/reimburses/approved-by-me` | 我已审批 |
|
||||
| GET | `/api/reimburses/{reimburse_id}` | 详情 |
|
||||
| GET | `/api/reimburses/{reimburse_id}/approvals` | 审批记录 |
|
||||
| POST | `/api/reimburses/` | 新增(含明细) |
|
||||
| PUT | `/api/reimburses/{reimburse_id}` | 更新 |
|
||||
| POST | `/api/reimburses/{reimburse_id}/submit` | 提交 |
|
||||
| POST | `/api/reimburses/{reimburse_id}/approve` | 审批通过 |
|
||||
| POST | `/api/reimburses/{reimburse_id}/reject` | 审批驳回 |
|
||||
| DELETE | `/api/reimburses/{reimburse_id}` | 软删除 |
|
||||
|
||||
---
|
||||
|
||||
## 支付 / 发放 `/api/payments`
|
||||
|
||||
| 方法 | 路径 | 说明 |
|
||||
|------|------|------|
|
||||
| GET | `/api/payments/pending` | 待支付报销列表 |
|
||||
| GET | `/api/payments/stats` | 财务统计 |
|
||||
| GET | `/api/payments/processed` | 已处理列表 |
|
||||
| POST | `/api/payments/{id}/pay` | 报销发放 |
|
||||
| POST | `/api/payments/{id}/offset` | 单笔冲抵 |
|
||||
| POST | `/api/payments/{id}/batch-offset` | 批量冲抵 |
|
||||
| GET | `/api/payments/advance-issues` | 备用金发放列表 |
|
||||
| GET | `/api/payments/advance-issues/stats` | 发放统计 |
|
||||
| GET | `/api/payments/advance-issues/export` | 导出 CSV(StreamingResponse) |
|
||||
| POST | `/api/payments/advance/{advance_id}/issue` | 备用金发放 |
|
||||
| GET | `/api/payments/advance/{advance_id}/offset-records` | 备用金被冲抵记录 |
|
||||
| GET | `/api/payments/{id}/offset-records` | 报销冲抵记录 |
|
||||
|
||||
---
|
||||
|
||||
## 附件 `/api/attachments`
|
||||
|
||||
| 方法 | 路径 | 说明 |
|
||||
|------|------|------|
|
||||
| POST | `/api/attachments/upload` | 上传(multipart: file, biz_type, biz_id) |
|
||||
| GET | `/api/attachments/download/{attachment_id}` | 下载文件流 |
|
||||
| GET | `/api/attachments/preview/{attachment_id}` | 预览 URL |
|
||||
| GET | `/api/attachments/list` | 按 biz_type、biz_id 列表 |
|
||||
| PUT | `/api/attachments/bind-biz` | 绑定业务单(query: ids, biz_type, biz_id) |
|
||||
| DELETE | `/api/attachments/{attachment_id}` | 软删除 |
|
||||
|
||||
---
|
||||
|
||||
## 响应格式(所有 JSON 接口)
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"msg": "success",
|
||||
"data": { }
|
||||
}
|
||||
```
|
||||
|
||||
分页 `data` 结构:
|
||||
|
||||
```json
|
||||
{
|
||||
"rows": [],
|
||||
"total": 0,
|
||||
"page": 1,
|
||||
"pageSize": 10
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 不移植的 API
|
||||
|
||||
| 前缀 | 说明 |
|
||||
|------|------|
|
||||
| `/api/auth/*` | 门户登录 |
|
||||
| `/api/users/*` | sys_user |
|
||||
| `/api/roles/*` | sys_role |
|
||||
| `/api/menus/*` | sys_menu(门户菜单接口) |
|
||||
@@ -0,0 +1,43 @@
|
||||
# 报销(bx)模块移植状态跟踪表
|
||||
|
||||
> 实施过程中更新此文档。方案见 [00-migration-plan.md](./00-migration-plan.md)。
|
||||
|
||||
---
|
||||
|
||||
## 阶段总览
|
||||
|
||||
| 阶段 | 内容 | 状态 | 日期 |
|
||||
|------|------|------|------|
|
||||
| DDL | 10 张 `bx_*` 业务表 | ✅ 已完成 | 2026-06-06 |
|
||||
| P0 | 基础设施(ORM/Auth/Router 骨架) | ✅ 已完成 | 2026-06-06 |
|
||||
| P1 | 费用项目 + 工作流 | ✅ 已完成 | 2026-06-06 |
|
||||
| P2 | 备用金 + 附件 | ✅ 已完成 | 2026-06-06 |
|
||||
| P3 | 报销 | ✅ 已完成 | 2026-06-06 |
|
||||
| P4 | 支付/发放/冲抵 | ✅ 已完成 | 2026-06-06 |
|
||||
| P5 | sys_menu 菜单与权限 | ✅ 已完成 | 2026-06-06 |
|
||||
| P6 | web-admin 前端(拷贝 + 门户适配) | 🟡 进行中 | 2026-06-06 |
|
||||
| P6-FM | Fresh Mint UI 深度对齐 | ⬜ 未开始 | — |
|
||||
|
||||
---
|
||||
|
||||
## 后端模块明细
|
||||
|
||||
| 模块 | 表 | 后端 | 前端 | 验证 | 备注 |
|
||||
|------|-----|------|------|------|------|
|
||||
| 费用项目 | `bx_expense_item` | ✅ | 🟡 | — | P6 页面已拷贝 |
|
||||
| 工作流 | `bx_workflow_def`、`bx_workflow_node` | ✅ | 🟡 | — | P6 页面已拷贝 |
|
||||
| 备用金 | `bx_advance_apply`、`bx_advance_approval` | ✅ | 🟡 | — | P6 页面已拷贝 |
|
||||
| 附件 | `bx_attachment` | ✅ | 🟡 | — | 组件内上传已拷贝 |
|
||||
| 报销 | `bx_reimburse_apply`、`bx_reimburse_detail`、`bx_reimburse_approval` | ✅ | 🟡 | — | P6 页面已拷贝 |
|
||||
| 支付 | `bx_reimburse_offset` + payment 逻辑 | ✅ | 🟡 | — | P6 页面已拷贝 |
|
||||
| 视图中心 | —(聚合 API) | ✅ | 🟡 | — | 我的/待办/全部页已拷贝 |
|
||||
|
||||
---
|
||||
|
||||
## 不移植项
|
||||
|
||||
| 项 | 替代 |
|
||||
|----|------|
|
||||
| `bx_user` / `bx_role` / `bx_menu` | `sys_user` / `sys_role` / `sys_menu` |
|
||||
| `bx-backend/routers/auth.py` | 门户 `/api/web/auth/login` |
|
||||
| bx-web User/Role/Menu 页 | 门户系统管理 |
|
||||
@@ -0,0 +1,147 @@
|
||||
# 报销后端移植适配细则
|
||||
|
||||
> 实施 P0–P4 时加载。与 [00-migration-plan.md](./00-migration-plan.md) 配套。
|
||||
|
||||
---
|
||||
|
||||
## 1. 文件复制对照表
|
||||
|
||||
| bx-backend 源 | shanxia2.0 目标 | 改造程度 |
|
||||
|---------------|----------------|---------|
|
||||
| `schemas/common.py` | `schemas/bx/common.py` | 原样 |
|
||||
| `schemas/expense_item.py` 等 | `schemas/bx/*.py` | id 改 str |
|
||||
| `services/*.py` | `services/bx/*.py` | tenant + uuid + user |
|
||||
| `routers/*.py` | `api/bx/*.py` | Depends + prefix + import |
|
||||
| `models/*.py` | `models/bx_models.py` | 按 DDL 重写 |
|
||||
| `utils/codegen.py` | `utils/bx_codegen.py` 或 `utils/codegen.py` | 租户隔离可选 |
|
||||
| `core/deps.py` | **不复制** | 用 `core/bx_auth.py` |
|
||||
| `services/minio.py` | **不复制** | 门户 storage 适配 |
|
||||
|
||||
---
|
||||
|
||||
## 2. Router 改造检查清单
|
||||
|
||||
复制每个 router 后逐项核对:
|
||||
|
||||
- [ ] `APIRouter(prefix="/api/xxx")` → `prefix="/xxx"`(去掉 `/api`)
|
||||
- [ ] `from app.database import get_db` → `from app.core.database import get_db`
|
||||
- [ ] `Depends(get_current_user)` → `Depends(get_bx_current_user)`
|
||||
- [ ] `User` 类型 → `BxUserContext`
|
||||
- [ ] `require_roles("ADMIN")` → `Depends(get_bx_current_user)` 或 `require_menu_code("bx:...")`(P5 后)
|
||||
- [ ] 路径参数 `{advance_id}: int` → `str`
|
||||
- [ ] `response_model=ApiResponse[...]` 保持不变
|
||||
- [ ] **禁止** `return success_response(...)`
|
||||
|
||||
---
|
||||
|
||||
## 3. Service 改造检查清单
|
||||
|
||||
- [ ] 所有 `get_by_id(model, db, id: int)` → `id: str`
|
||||
- [ ] 查询追加 `Model.tenant_no == tenant_no`
|
||||
- [ ] 创建:`generate_uuid()`、`tenant_no`、`create_by`、`create_dept_id`
|
||||
- [ ] `applicant_id` / `approver_id` 使用 `sys_user.id`(str)
|
||||
- [ ] 冗余姓名字段:从 `SysUser.nick_name` 写入 `applicant_name` 等
|
||||
- [ ] 单号生成:`generate_apply_code` 加租户维度(同日重置逻辑保留)
|
||||
- [ ] 软删除:`del_flag=1`,查询默认 `del_flag=0`
|
||||
|
||||
---
|
||||
|
||||
## 4. Schema 改造检查清单
|
||||
|
||||
- [ ] `AdvanceApplyOut.id: int` → `str`
|
||||
- [ ] `expense_item_id: Optional[int]` → `Optional[str]`
|
||||
- [ ] 保留 `model_config`:`populate_by_name=True`, `alias_generator=to_camel`
|
||||
- [ ] 保留 `DatetimeToStr` / `apply_time` 等字段 alias
|
||||
- [ ] Create/Update body 与 bx 原字段一致
|
||||
|
||||
---
|
||||
|
||||
## 5. bx_auth 参考实现
|
||||
|
||||
```python
|
||||
# backend/app/core/bx_auth.py(实施 P0 时落地)
|
||||
from dataclasses import dataclass
|
||||
from fastapi import Depends
|
||||
from app.core.menu_guard import require_admin_or_super_admin
|
||||
|
||||
@dataclass
|
||||
class BxUserContext:
|
||||
id: str
|
||||
name: str
|
||||
dept_id: str
|
||||
|
||||
def get_bx_current_user(
|
||||
user: dict = Depends(require_admin_or_super_admin),
|
||||
) -> BxUserContext:
|
||||
return BxUserContext(
|
||||
id=user.get("user_id") or "",
|
||||
name=user.get("nick_name") or user.get("username") or "",
|
||||
dept_id=user.get("dept_id") or "",
|
||||
)
|
||||
```
|
||||
|
||||
Service 中需要 tenant 时:
|
||||
|
||||
```python
|
||||
from app.core.tenant_context import get_tenant_no
|
||||
|
||||
tenant_no = get_tenant_no(db, {"user_id": user.id, "role": ...})
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 6. main.py 注册
|
||||
|
||||
```python
|
||||
from app.api.bx import bx_router
|
||||
|
||||
app.include_router(bx_router, prefix=settings.API_V1_PREFIX)
|
||||
```
|
||||
|
||||
`api/bx/__init__.py`:
|
||||
|
||||
```python
|
||||
from fastapi import APIRouter
|
||||
from app.api.bx import expense_item, workflow, advance, reimburse, payment, attachment
|
||||
|
||||
bx_router = APIRouter()
|
||||
bx_router.include_router(expense_item.router)
|
||||
bx_router.include_router(workflow.router)
|
||||
# ...
|
||||
```
|
||||
|
||||
`app/api/__init__.py` 增加 `bx_router` 导出(可选,或直接 main 引用)。
|
||||
|
||||
---
|
||||
|
||||
## 7. 加密排除(config.py)
|
||||
|
||||
在 `API_ENCRYPT_EXCLUDE_PATHS` 追加(逗号分隔):
|
||||
|
||||
```
|
||||
/api/expense-items,
|
||||
/api/workflows,
|
||||
/api/advances,
|
||||
/api/reimburses,
|
||||
/api/payments,
|
||||
/api/attachments
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 8. 字段一致性(可选)
|
||||
|
||||
后端 CRUD 落地后,若 WriteBody 字段较多,可扩展 `scripts/check_field_consistency.py` 支持 `bx_*` 表,规则同 CRM。
|
||||
|
||||
---
|
||||
|
||||
## 9. 测试建议
|
||||
|
||||
| 阶段 | 方式 |
|
||||
|------|------|
|
||||
| P1 | Swagger `/docs` 手动测 expense-items / workflows |
|
||||
| P2 | 备用金完整流程 + 附件 upload |
|
||||
| P3–P4 | 对照 bx 原环境相同操作序列 |
|
||||
| 协议 | 断言响应 `code===0`、`data.rows` 存在 |
|
||||
|
||||
原 bx 环境(8011)可与门户(8000)并行,便于 diff 响应结构。
|
||||
@@ -0,0 +1,298 @@
|
||||
/*
|
||||
报销系统(bx_*)表结构迁移 — shanxia2.0 门户标准字段适配
|
||||
|
||||
来源:docs/sql/sx.sql 中 bx_* 业务表(排除 bx_user / bx_role / bx_role_user / bx_menu / bx_menu_role)
|
||||
适配:主键 UUID(varchar64)、tenant_no、order_num、create_dept_id、del_flag smallint 等公共字段
|
||||
说明:仅建表,不导入数据
|
||||
*/
|
||||
|
||||
SET NAMES utf8mb4;
|
||||
SET FOREIGN_KEY_CHECKS = 0;
|
||||
|
||||
-- ----------------------------
|
||||
-- Table structure for bx_expense_item
|
||||
-- ----------------------------
|
||||
DROP TABLE IF EXISTS `bx_expense_item`;
|
||||
CREATE TABLE `bx_expense_item` (
|
||||
`id` varchar(64) NOT NULL COMMENT '主键ID(UUID)',
|
||||
`parent_id` varchar(64) NOT NULL DEFAULT '0' COMMENT '父级项目ID(0为一级项目)',
|
||||
`item_name` varchar(128) NOT NULL COMMENT '项目名称',
|
||||
`item_code` varchar(64) DEFAULT NULL COMMENT '项目编码',
|
||||
`level` tinyint(4) NOT NULL DEFAULT '1' COMMENT '层级:1-一级 2-二级',
|
||||
`sort_order` int(11) NOT NULL DEFAULT '0' COMMENT '排序号',
|
||||
`status` tinyint(4) NOT NULL DEFAULT '1' COMMENT '状态:1-启用 0-禁用',
|
||||
`tenant_no` varchar(64) NOT NULL DEFAULT 'shanxia2.0' COMMENT '租户编号',
|
||||
`order_num` int(11) DEFAULT NULL COMMENT '排序号(公共)',
|
||||
`remark` varchar(512) DEFAULT NULL COMMENT '备注',
|
||||
`create_by` varchar(64) DEFAULT NULL COMMENT '创建人',
|
||||
`create_dept_id` varchar(64) NOT NULL DEFAULT '' COMMENT '创建部门',
|
||||
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||
`update_by` varchar(64) DEFAULT NULL COMMENT '更新人',
|
||||
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
||||
`del_flag` smallint(6) NOT NULL DEFAULT '0' COMMENT '删除标记:0-正常 1-已删除',
|
||||
PRIMARY KEY (`id`) USING BTREE,
|
||||
KEY `idx_parent_id` (`parent_id`) USING BTREE,
|
||||
KEY `idx_tenant_no` (`tenant_no`) USING BTREE
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='报销-费用项目表';
|
||||
|
||||
-- ----------------------------
|
||||
-- Table structure for bx_workflow_def
|
||||
-- ----------------------------
|
||||
DROP TABLE IF EXISTS `bx_workflow_def`;
|
||||
CREATE TABLE `bx_workflow_def` (
|
||||
`id` varchar(64) NOT NULL COMMENT '主键ID(UUID)',
|
||||
`biz_type` varchar(32) NOT NULL COMMENT '业务类型:advance-备用金 reimburse-报销单',
|
||||
`wf_name` varchar(128) NOT NULL COMMENT '工作流名称',
|
||||
`status` tinyint(4) NOT NULL DEFAULT '1' COMMENT '状态:1-启用 0-禁用',
|
||||
`tenant_no` varchar(64) NOT NULL DEFAULT 'shanxia2.0' COMMENT '租户编号',
|
||||
`order_num` int(11) DEFAULT NULL COMMENT '排序号(公共)',
|
||||
`remark` varchar(512) DEFAULT NULL COMMENT '备注',
|
||||
`create_by` varchar(64) DEFAULT NULL COMMENT '创建人',
|
||||
`create_dept_id` varchar(64) NOT NULL DEFAULT '' COMMENT '创建部门',
|
||||
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||
`update_by` varchar(64) DEFAULT NULL COMMENT '更新人',
|
||||
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
||||
`del_flag` smallint(6) NOT NULL DEFAULT '0' COMMENT '删除标记:0-正常 1-已删除',
|
||||
PRIMARY KEY (`id`) USING BTREE,
|
||||
KEY `idx_biz_type` (`biz_type`) USING BTREE,
|
||||
KEY `idx_tenant_no` (`tenant_no`) USING BTREE
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='报销-工作流定义表';
|
||||
|
||||
-- ----------------------------
|
||||
-- Table structure for bx_workflow_node
|
||||
-- ----------------------------
|
||||
DROP TABLE IF EXISTS `bx_workflow_node`;
|
||||
CREATE TABLE `bx_workflow_node` (
|
||||
`id` varchar(64) NOT NULL COMMENT '主键ID(UUID)',
|
||||
`wf_id` varchar(64) NOT NULL COMMENT '工作流定义ID',
|
||||
`node_name` varchar(128) NOT NULL COMMENT '节点名称(如:主管审批、财务复核)',
|
||||
`node_order` int(11) NOT NULL DEFAULT '0' COMMENT '节点顺序(从小到大执行)',
|
||||
`approver_id` varchar(64) DEFAULT NULL COMMENT '审批人用户ID',
|
||||
`approver_name` varchar(64) DEFAULT NULL COMMENT '审批人姓名(冗余)',
|
||||
`tenant_no` varchar(64) NOT NULL DEFAULT 'shanxia2.0' COMMENT '租户编号',
|
||||
`order_num` int(11) DEFAULT NULL COMMENT '排序号(公共)',
|
||||
`remark` varchar(512) DEFAULT NULL COMMENT '备注',
|
||||
`create_by` varchar(64) DEFAULT NULL COMMENT '创建人',
|
||||
`create_dept_id` varchar(64) NOT NULL DEFAULT '' COMMENT '创建部门',
|
||||
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||
`update_by` varchar(64) DEFAULT NULL COMMENT '更新人',
|
||||
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
||||
`del_flag` smallint(6) NOT NULL DEFAULT '0' COMMENT '删除标记:0-正常 1-已删除',
|
||||
PRIMARY KEY (`id`) USING BTREE,
|
||||
KEY `idx_wf_id` (`wf_id`) USING BTREE,
|
||||
KEY `idx_tenant_no` (`tenant_no`) USING BTREE
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='报销-工作流节点表';
|
||||
|
||||
-- ----------------------------
|
||||
-- Table structure for bx_advance_apply
|
||||
-- ----------------------------
|
||||
DROP TABLE IF EXISTS `bx_advance_apply`;
|
||||
CREATE TABLE `bx_advance_apply` (
|
||||
`id` varchar(64) NOT NULL COMMENT '主键ID(UUID)',
|
||||
`apply_code` varchar(32) NOT NULL COMMENT '申请单号(如 BYJ20260424001)',
|
||||
`applicant_id` varchar(64) NOT NULL COMMENT '申请人用户ID',
|
||||
`applicant_name` varchar(64) NOT NULL COMMENT '申请人姓名(冗余)',
|
||||
`reason` varchar(1024) NOT NULL COMMENT '申请原因',
|
||||
`purpose` varchar(1024) DEFAULT NULL COMMENT '申请目的',
|
||||
`expense_item_id` varchar(64) DEFAULT NULL COMMENT '费用项目ID',
|
||||
`amount` decimal(14,2) NOT NULL COMMENT '申请金额',
|
||||
`status` varchar(32) NOT NULL DEFAULT 'draft' COMMENT '状态:draft-草稿 pending-待审批 approved-审批通过 rejected-审批驳回 issued-已发放',
|
||||
`current_node` varchar(128) DEFAULT NULL COMMENT '当前审批节点名称',
|
||||
`wf_id` varchar(64) DEFAULT NULL COMMENT '关联工作流定义ID',
|
||||
`issue_status` varchar(32) DEFAULT NULL COMMENT '发放状态:unissued-未发放 issued-已发放',
|
||||
`issue_time` datetime DEFAULT NULL COMMENT '发放时间',
|
||||
`issue_user_id` varchar(64) DEFAULT NULL COMMENT '发放操作人ID',
|
||||
`issue_user_name` varchar(64) DEFAULT NULL COMMENT '发放操作人姓名',
|
||||
`issue_remark` varchar(512) DEFAULT NULL COMMENT '发放备注',
|
||||
`actual_amount` decimal(14,2) DEFAULT NULL COMMENT '实际发放金额',
|
||||
`tenant_no` varchar(64) NOT NULL DEFAULT 'shanxia2.0' COMMENT '租户编号',
|
||||
`order_num` int(11) DEFAULT NULL COMMENT '排序号(公共)',
|
||||
`remark` varchar(512) DEFAULT NULL COMMENT '备注',
|
||||
`create_by` varchar(64) DEFAULT NULL COMMENT '创建人',
|
||||
`create_dept_id` varchar(64) NOT NULL DEFAULT '' COMMENT '创建部门',
|
||||
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||
`update_by` varchar(64) DEFAULT NULL COMMENT '更新人',
|
||||
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
||||
`del_flag` smallint(6) NOT NULL DEFAULT '0' COMMENT '删除标记:0-正常 1-已删除',
|
||||
PRIMARY KEY (`id`) USING BTREE,
|
||||
UNIQUE KEY `uk_apply_code` (`apply_code`) USING BTREE,
|
||||
KEY `idx_applicant_id` (`applicant_id`) USING BTREE,
|
||||
KEY `idx_status` (`status`) USING BTREE,
|
||||
KEY `idx_tenant_no` (`tenant_no`) USING BTREE
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='报销-备用金申请单';
|
||||
|
||||
-- ----------------------------
|
||||
-- Table structure for bx_advance_approval
|
||||
-- ----------------------------
|
||||
DROP TABLE IF EXISTS `bx_advance_approval`;
|
||||
CREATE TABLE `bx_advance_approval` (
|
||||
`id` varchar(64) NOT NULL COMMENT '主键ID(UUID)',
|
||||
`apply_id` varchar(64) NOT NULL COMMENT '备用金申请单ID',
|
||||
`node_order` int(11) NOT NULL COMMENT '节点顺序',
|
||||
`node_name` varchar(128) NOT NULL COMMENT '节点名称',
|
||||
`approver_id` varchar(64) NOT NULL COMMENT '审批人用户ID',
|
||||
`approver_name` varchar(64) NOT NULL COMMENT '审批人姓名',
|
||||
`approval_status` varchar(32) NOT NULL COMMENT '审批结果:approved-通过 rejected-驳回',
|
||||
`approval_opinion` varchar(1024) DEFAULT NULL COMMENT '审批意见',
|
||||
`approval_time` datetime NOT NULL COMMENT '审批时间',
|
||||
`tenant_no` varchar(64) NOT NULL DEFAULT 'shanxia2.0' COMMENT '租户编号',
|
||||
`order_num` int(11) DEFAULT NULL COMMENT '排序号(公共)',
|
||||
`remark` varchar(512) DEFAULT NULL COMMENT '备注',
|
||||
`create_by` varchar(64) DEFAULT NULL COMMENT '创建人',
|
||||
`create_dept_id` varchar(64) NOT NULL DEFAULT '' COMMENT '创建部门',
|
||||
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||
`update_by` varchar(64) DEFAULT NULL COMMENT '更新人',
|
||||
`update_time` datetime DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
||||
`del_flag` smallint(6) NOT NULL DEFAULT '0' COMMENT '删除标记:0-正常 1-已删除',
|
||||
PRIMARY KEY (`id`) USING BTREE,
|
||||
KEY `idx_apply_id` (`apply_id`) USING BTREE,
|
||||
KEY `idx_tenant_no` (`tenant_no`) USING BTREE
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='报销-备用金审批记录表';
|
||||
|
||||
-- ----------------------------
|
||||
-- Table structure for bx_reimburse_apply
|
||||
-- ----------------------------
|
||||
DROP TABLE IF EXISTS `bx_reimburse_apply`;
|
||||
CREATE TABLE `bx_reimburse_apply` (
|
||||
`id` varchar(64) NOT NULL COMMENT '主键ID(UUID)',
|
||||
`apply_code` varchar(32) NOT NULL COMMENT '报销单号(如 BX20260424001)',
|
||||
`title` varchar(256) NOT NULL COMMENT '报销标题',
|
||||
`applicant_id` varchar(64) NOT NULL COMMENT '申请人用户ID',
|
||||
`applicant_name` varchar(64) NOT NULL COMMENT '申请人姓名(冗余)',
|
||||
`expense_id` varchar(64) NOT NULL COMMENT '费用项目ID(二级项目)',
|
||||
`expense_name` varchar(128) NOT NULL COMMENT '费用项目名称(冗余)',
|
||||
`amount` decimal(14,2) NOT NULL COMMENT '报销金额',
|
||||
`invoice_count` int(11) NOT NULL DEFAULT '0' COMMENT '发票数量',
|
||||
`attach_count` int(11) NOT NULL DEFAULT '0' COMMENT '附件数量',
|
||||
`status` varchar(32) NOT NULL DEFAULT 'draft' COMMENT '状态:draft-草稿 pending-待审批 approved-审批通过 rejected-审批驳回 paid-已发放 offset-已冲抵',
|
||||
`current_node` varchar(128) DEFAULT NULL COMMENT '当前审批节点名称',
|
||||
`wf_id` varchar(64) DEFAULT NULL COMMENT '关联工作流定义ID',
|
||||
`pay_status` varchar(32) DEFAULT NULL COMMENT '支付状态:unpaid-未支付 paid-已发放 offset-已冲抵',
|
||||
`pay_time` datetime DEFAULT NULL COMMENT '支付时间',
|
||||
`pay_user_id` varchar(64) DEFAULT NULL COMMENT '支付操作人ID',
|
||||
`pay_user_name` varchar(64) DEFAULT NULL COMMENT '支付操作人姓名',
|
||||
`actual_amount` decimal(14,2) DEFAULT NULL COMMENT '实际发放金额',
|
||||
`offset_advance_id` varchar(64) DEFAULT NULL COMMENT '冲抵关联的备用金单ID',
|
||||
`offset_amount` decimal(14,2) DEFAULT NULL COMMENT '冲抵金额',
|
||||
`tenant_no` varchar(64) NOT NULL DEFAULT 'shanxia2.0' COMMENT '租户编号',
|
||||
`order_num` int(11) DEFAULT NULL COMMENT '排序号(公共)',
|
||||
`remark` varchar(512) DEFAULT NULL COMMENT '备注说明',
|
||||
`create_by` varchar(64) DEFAULT NULL COMMENT '创建人',
|
||||
`create_dept_id` varchar(64) NOT NULL DEFAULT '' COMMENT '创建部门',
|
||||
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||
`update_by` varchar(64) DEFAULT NULL COMMENT '更新人',
|
||||
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
||||
`del_flag` smallint(6) NOT NULL DEFAULT '0' COMMENT '删除标记:0-正常 1-已删除',
|
||||
PRIMARY KEY (`id`) USING BTREE,
|
||||
UNIQUE KEY `uk_apply_code` (`apply_code`) USING BTREE,
|
||||
KEY `idx_applicant_id` (`applicant_id`) USING BTREE,
|
||||
KEY `idx_status` (`status`) USING BTREE,
|
||||
KEY `idx_expense_id` (`expense_id`) USING BTREE,
|
||||
KEY `idx_tenant_no` (`tenant_no`) USING BTREE
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='报销-报销申请单';
|
||||
|
||||
-- ----------------------------
|
||||
-- Table structure for bx_reimburse_detail
|
||||
-- ----------------------------
|
||||
DROP TABLE IF EXISTS `bx_reimburse_detail`;
|
||||
CREATE TABLE `bx_reimburse_detail` (
|
||||
`id` varchar(64) NOT NULL COMMENT '主键ID(UUID)',
|
||||
`reimburse_id` varchar(64) NOT NULL COMMENT '报销单ID',
|
||||
`expense_id` varchar(64) NOT NULL COMMENT '费用项目ID',
|
||||
`expense_name` varchar(128) NOT NULL COMMENT '费用项目名称',
|
||||
`amount` decimal(14,2) NOT NULL COMMENT '报销金额',
|
||||
`tenant_no` varchar(64) NOT NULL DEFAULT 'shanxia2.0' COMMENT '租户编号',
|
||||
`order_num` int(11) DEFAULT NULL COMMENT '排序号(公共)',
|
||||
`remark` varchar(512) DEFAULT NULL COMMENT '备注',
|
||||
`create_by` varchar(64) DEFAULT NULL COMMENT '创建人',
|
||||
`create_dept_id` varchar(64) NOT NULL DEFAULT '' COMMENT '创建部门',
|
||||
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||
`update_by` varchar(64) DEFAULT NULL COMMENT '更新人',
|
||||
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
||||
`del_flag` smallint(6) NOT NULL DEFAULT '0' COMMENT '删除标记:0-正常 1-已删除',
|
||||
PRIMARY KEY (`id`) USING BTREE,
|
||||
KEY `idx_reimburse_id` (`reimburse_id`) USING BTREE,
|
||||
KEY `idx_tenant_no` (`tenant_no`) USING BTREE
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='报销-报销明细';
|
||||
|
||||
-- ----------------------------
|
||||
-- Table structure for bx_reimburse_approval
|
||||
-- ----------------------------
|
||||
DROP TABLE IF EXISTS `bx_reimburse_approval`;
|
||||
CREATE TABLE `bx_reimburse_approval` (
|
||||
`id` varchar(64) NOT NULL COMMENT '主键ID(UUID)',
|
||||
`apply_id` varchar(64) NOT NULL COMMENT '报销申请单ID',
|
||||
`node_order` int(11) NOT NULL COMMENT '节点顺序',
|
||||
`node_name` varchar(128) NOT NULL COMMENT '节点名称',
|
||||
`approver_id` varchar(64) NOT NULL COMMENT '审批人用户ID',
|
||||
`approver_name` varchar(64) NOT NULL COMMENT '审批人姓名',
|
||||
`approval_status` varchar(32) NOT NULL COMMENT '审批结果:approved-通过 rejected-驳回',
|
||||
`approval_opinion` varchar(1024) DEFAULT NULL COMMENT '审批意见',
|
||||
`approval_time` datetime NOT NULL COMMENT '审批时间',
|
||||
`tenant_no` varchar(64) NOT NULL DEFAULT 'shanxia2.0' COMMENT '租户编号',
|
||||
`order_num` int(11) DEFAULT NULL COMMENT '排序号(公共)',
|
||||
`remark` varchar(512) DEFAULT NULL COMMENT '备注',
|
||||
`create_by` varchar(64) DEFAULT NULL COMMENT '创建人',
|
||||
`create_dept_id` varchar(64) NOT NULL DEFAULT '' COMMENT '创建部门',
|
||||
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||
`update_by` varchar(64) DEFAULT NULL COMMENT '更新人',
|
||||
`update_time` datetime DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
||||
`del_flag` smallint(6) NOT NULL DEFAULT '0' COMMENT '删除标记:0-正常 1-已删除',
|
||||
PRIMARY KEY (`id`) USING BTREE,
|
||||
KEY `idx_apply_id` (`apply_id`) USING BTREE,
|
||||
KEY `idx_tenant_no` (`tenant_no`) USING BTREE
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='报销-报销审批记录表';
|
||||
|
||||
-- ----------------------------
|
||||
-- Table structure for bx_reimburse_offset
|
||||
-- ----------------------------
|
||||
DROP TABLE IF EXISTS `bx_reimburse_offset`;
|
||||
CREATE TABLE `bx_reimburse_offset` (
|
||||
`id` varchar(64) NOT NULL COMMENT '主键ID(UUID)',
|
||||
`reimburse_id` varchar(64) NOT NULL COMMENT '报销申请单ID',
|
||||
`advance_id` varchar(64) NOT NULL COMMENT '备用金申请单ID',
|
||||
`offset_amount` decimal(14,2) NOT NULL COMMENT '冲抵金额',
|
||||
`tenant_no` varchar(64) NOT NULL DEFAULT 'shanxia2.0' COMMENT '租户编号',
|
||||
`order_num` int(11) DEFAULT NULL COMMENT '排序号(公共)',
|
||||
`remark` varchar(512) DEFAULT NULL COMMENT '备注',
|
||||
`create_by` varchar(64) DEFAULT NULL COMMENT '创建人',
|
||||
`create_dept_id` varchar(64) NOT NULL DEFAULT '' COMMENT '创建部门',
|
||||
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||
`update_by` varchar(64) DEFAULT NULL COMMENT '更新人',
|
||||
`update_time` datetime DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
||||
`del_flag` smallint(6) NOT NULL DEFAULT '0' COMMENT '删除标记:0-正常 1-已删除',
|
||||
PRIMARY KEY (`id`) USING BTREE,
|
||||
KEY `idx_reimburse_id` (`reimburse_id`) USING BTREE,
|
||||
KEY `idx_advance_id` (`advance_id`) USING BTREE,
|
||||
KEY `idx_tenant_no` (`tenant_no`) USING BTREE
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='报销-报销单备用金冲抵关联表';
|
||||
|
||||
-- ----------------------------
|
||||
-- Table structure for bx_attachment
|
||||
-- ----------------------------
|
||||
DROP TABLE IF EXISTS `bx_attachment`;
|
||||
CREATE TABLE `bx_attachment` (
|
||||
`id` varchar(64) NOT NULL COMMENT '主键ID(UUID)',
|
||||
`biz_type` varchar(32) NOT NULL COMMENT '业务类型:advance-备用金 reimburse-报销 advance_issue-备用金发放',
|
||||
`biz_id` varchar(64) NOT NULL COMMENT '业务单据ID',
|
||||
`file_name` varchar(256) NOT NULL COMMENT '文件名',
|
||||
`file_path` varchar(512) NOT NULL COMMENT '文件存储路径',
|
||||
`file_type` varchar(128) DEFAULT NULL COMMENT '文件MIME类型',
|
||||
`file_size` bigint(20) DEFAULT NULL COMMENT '文件大小(字节)',
|
||||
`attach_type` varchar(32) DEFAULT 'attachment' COMMENT '附件类型:invoice-发票 attachment-普通附件 issue_proof-发放截图',
|
||||
`sort_order` int(11) NOT NULL DEFAULT '0' COMMENT '排序号',
|
||||
`tenant_no` varchar(64) NOT NULL DEFAULT 'shanxia2.0' COMMENT '租户编号',
|
||||
`order_num` int(11) DEFAULT NULL COMMENT '排序号(公共)',
|
||||
`remark` varchar(512) DEFAULT NULL COMMENT '备注',
|
||||
`create_by` varchar(64) DEFAULT NULL COMMENT '创建人',
|
||||
`create_dept_id` varchar(64) NOT NULL DEFAULT '' COMMENT '创建部门',
|
||||
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||
`update_by` varchar(64) DEFAULT NULL COMMENT '更新人',
|
||||
`update_time` datetime DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
||||
`del_flag` smallint(6) NOT NULL DEFAULT '0' COMMENT '删除标记:0-正常 1-已删除',
|
||||
PRIMARY KEY (`id`) USING BTREE,
|
||||
KEY `idx_biz` (`biz_type`,`biz_id`) USING BTREE,
|
||||
KEY `idx_tenant_no` (`tenant_no`) USING BTREE
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='报销-附件表';
|
||||
|
||||
SET FOREIGN_KEY_CHECKS = 1;
|
||||
@@ -51,6 +51,352 @@ CREATE TABLE `biz_leave_request` (
|
||||
BEGIN;
|
||||
COMMIT;
|
||||
|
||||
-- ----------------------------
|
||||
-- Table structure for bx_advance_apply
|
||||
-- ----------------------------
|
||||
DROP TABLE IF EXISTS `bx_advance_apply`;
|
||||
CREATE TABLE `bx_advance_apply` (
|
||||
`id` varchar(64) NOT NULL COMMENT '主键ID(UUID)',
|
||||
`apply_code` varchar(32) NOT NULL COMMENT '申请单号(如 BYJ20260424001)',
|
||||
`applicant_id` varchar(64) NOT NULL COMMENT '申请人用户ID',
|
||||
`applicant_name` varchar(64) NOT NULL COMMENT '申请人姓名(冗余)',
|
||||
`reason` varchar(1024) NOT NULL COMMENT '申请原因',
|
||||
`purpose` varchar(1024) DEFAULT NULL COMMENT '申请目的',
|
||||
`expense_item_id` varchar(64) DEFAULT NULL COMMENT '费用项目ID',
|
||||
`amount` decimal(14,2) NOT NULL COMMENT '申请金额',
|
||||
`status` varchar(32) NOT NULL DEFAULT 'draft' COMMENT '状态:draft-草稿 pending-待审批 approved-审批通过 rejected-审批驳回 issued-已发放',
|
||||
`current_node` varchar(128) DEFAULT NULL COMMENT '当前审批节点名称',
|
||||
`wf_id` varchar(64) DEFAULT NULL COMMENT '关联工作流定义ID',
|
||||
`issue_status` varchar(32) DEFAULT NULL COMMENT '发放状态:unissued-未发放 issued-已发放',
|
||||
`issue_time` datetime DEFAULT NULL COMMENT '发放时间',
|
||||
`issue_user_id` varchar(64) DEFAULT NULL COMMENT '发放操作人ID',
|
||||
`issue_user_name` varchar(64) DEFAULT NULL COMMENT '发放操作人姓名',
|
||||
`issue_remark` varchar(512) DEFAULT NULL COMMENT '发放备注',
|
||||
`actual_amount` decimal(14,2) DEFAULT NULL COMMENT '实际发放金额',
|
||||
`tenant_no` varchar(64) NOT NULL DEFAULT 'shanxia2.0' COMMENT '租户编号',
|
||||
`order_num` int(11) DEFAULT NULL COMMENT '排序号(公共)',
|
||||
`remark` varchar(512) DEFAULT NULL COMMENT '备注',
|
||||
`create_by` varchar(64) DEFAULT NULL COMMENT '创建人',
|
||||
`create_dept_id` varchar(64) NOT NULL DEFAULT '' COMMENT '创建部门',
|
||||
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||
`update_by` varchar(64) DEFAULT NULL COMMENT '更新人',
|
||||
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
||||
`del_flag` smallint(6) NOT NULL DEFAULT '0' COMMENT '删除标记:0-正常 1-已删除',
|
||||
PRIMARY KEY (`id`) USING BTREE,
|
||||
UNIQUE KEY `uk_apply_code` (`apply_code`) USING BTREE,
|
||||
KEY `idx_applicant_id` (`applicant_id`) USING BTREE,
|
||||
KEY `idx_status` (`status`) USING BTREE,
|
||||
KEY `idx_tenant_no` (`tenant_no`) USING BTREE
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='报销-备用金申请单';
|
||||
|
||||
-- ----------------------------
|
||||
-- Records of bx_advance_apply
|
||||
-- ----------------------------
|
||||
BEGIN;
|
||||
COMMIT;
|
||||
|
||||
-- ----------------------------
|
||||
-- Table structure for bx_advance_approval
|
||||
-- ----------------------------
|
||||
DROP TABLE IF EXISTS `bx_advance_approval`;
|
||||
CREATE TABLE `bx_advance_approval` (
|
||||
`id` varchar(64) NOT NULL COMMENT '主键ID(UUID)',
|
||||
`apply_id` varchar(64) NOT NULL COMMENT '备用金申请单ID',
|
||||
`node_order` int(11) NOT NULL COMMENT '节点顺序',
|
||||
`node_name` varchar(128) NOT NULL COMMENT '节点名称',
|
||||
`approver_id` varchar(64) NOT NULL COMMENT '审批人用户ID',
|
||||
`approver_name` varchar(64) NOT NULL COMMENT '审批人姓名',
|
||||
`approval_status` varchar(32) NOT NULL COMMENT '审批结果:approved-通过 rejected-驳回',
|
||||
`approval_opinion` varchar(1024) DEFAULT NULL COMMENT '审批意见',
|
||||
`approval_time` datetime NOT NULL COMMENT '审批时间',
|
||||
`tenant_no` varchar(64) NOT NULL DEFAULT 'shanxia2.0' COMMENT '租户编号',
|
||||
`order_num` int(11) DEFAULT NULL COMMENT '排序号(公共)',
|
||||
`remark` varchar(512) DEFAULT NULL COMMENT '备注',
|
||||
`create_by` varchar(64) DEFAULT NULL COMMENT '创建人',
|
||||
`create_dept_id` varchar(64) NOT NULL DEFAULT '' COMMENT '创建部门',
|
||||
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||
`update_by` varchar(64) DEFAULT NULL COMMENT '更新人',
|
||||
`update_time` datetime DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
||||
`del_flag` smallint(6) NOT NULL DEFAULT '0' COMMENT '删除标记:0-正常 1-已删除',
|
||||
PRIMARY KEY (`id`) USING BTREE,
|
||||
KEY `idx_apply_id` (`apply_id`) USING BTREE,
|
||||
KEY `idx_tenant_no` (`tenant_no`) USING BTREE
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='报销-备用金审批记录表';
|
||||
|
||||
-- ----------------------------
|
||||
-- Records of bx_advance_approval
|
||||
-- ----------------------------
|
||||
BEGIN;
|
||||
COMMIT;
|
||||
|
||||
-- ----------------------------
|
||||
-- Table structure for bx_attachment
|
||||
-- ----------------------------
|
||||
DROP TABLE IF EXISTS `bx_attachment`;
|
||||
CREATE TABLE `bx_attachment` (
|
||||
`id` varchar(64) NOT NULL COMMENT '主键ID(UUID)',
|
||||
`biz_type` varchar(32) NOT NULL COMMENT '业务类型:advance-备用金 reimburse-报销 advance_issue-备用金发放',
|
||||
`biz_id` varchar(64) NOT NULL COMMENT '业务单据ID',
|
||||
`file_name` varchar(256) NOT NULL COMMENT '文件名',
|
||||
`file_path` varchar(512) NOT NULL COMMENT '文件存储路径',
|
||||
`file_type` varchar(128) DEFAULT NULL COMMENT '文件MIME类型',
|
||||
`file_size` bigint(20) DEFAULT NULL COMMENT '文件大小(字节)',
|
||||
`attach_type` varchar(32) DEFAULT 'attachment' COMMENT '附件类型:invoice-发票 attachment-普通附件 issue_proof-发放截图',
|
||||
`sort_order` int(11) NOT NULL DEFAULT '0' COMMENT '排序号',
|
||||
`tenant_no` varchar(64) NOT NULL DEFAULT 'shanxia2.0' COMMENT '租户编号',
|
||||
`order_num` int(11) DEFAULT NULL COMMENT '排序号(公共)',
|
||||
`remark` varchar(512) DEFAULT NULL COMMENT '备注',
|
||||
`create_by` varchar(64) DEFAULT NULL COMMENT '创建人',
|
||||
`create_dept_id` varchar(64) NOT NULL DEFAULT '' COMMENT '创建部门',
|
||||
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||
`update_by` varchar(64) DEFAULT NULL COMMENT '更新人',
|
||||
`update_time` datetime DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
||||
`del_flag` smallint(6) NOT NULL DEFAULT '0' COMMENT '删除标记:0-正常 1-已删除',
|
||||
PRIMARY KEY (`id`) USING BTREE,
|
||||
KEY `idx_biz` (`biz_type`,`biz_id`) USING BTREE,
|
||||
KEY `idx_tenant_no` (`tenant_no`) USING BTREE
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='报销-附件表';
|
||||
|
||||
-- ----------------------------
|
||||
-- Records of bx_attachment
|
||||
-- ----------------------------
|
||||
BEGIN;
|
||||
COMMIT;
|
||||
|
||||
-- ----------------------------
|
||||
-- Table structure for bx_expense_item
|
||||
-- ----------------------------
|
||||
DROP TABLE IF EXISTS `bx_expense_item`;
|
||||
CREATE TABLE `bx_expense_item` (
|
||||
`id` varchar(64) NOT NULL COMMENT '主键ID(UUID)',
|
||||
`parent_id` varchar(64) NOT NULL DEFAULT '0' COMMENT '父级项目ID(0为一级项目)',
|
||||
`item_name` varchar(128) NOT NULL COMMENT '项目名称',
|
||||
`item_code` varchar(64) DEFAULT NULL COMMENT '项目编码',
|
||||
`level` tinyint(4) NOT NULL DEFAULT '1' COMMENT '层级:1-一级 2-二级',
|
||||
`sort_order` int(11) NOT NULL DEFAULT '0' COMMENT '排序号',
|
||||
`status` tinyint(4) NOT NULL DEFAULT '1' COMMENT '状态:1-启用 0-禁用',
|
||||
`tenant_no` varchar(64) NOT NULL DEFAULT 'shanxia2.0' COMMENT '租户编号',
|
||||
`order_num` int(11) DEFAULT NULL COMMENT '排序号(公共)',
|
||||
`remark` varchar(512) DEFAULT NULL COMMENT '备注',
|
||||
`create_by` varchar(64) DEFAULT NULL COMMENT '创建人',
|
||||
`create_dept_id` varchar(64) NOT NULL DEFAULT '' COMMENT '创建部门',
|
||||
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||
`update_by` varchar(64) DEFAULT NULL COMMENT '更新人',
|
||||
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
||||
`del_flag` smallint(6) NOT NULL DEFAULT '0' COMMENT '删除标记:0-正常 1-已删除',
|
||||
PRIMARY KEY (`id`) USING BTREE,
|
||||
KEY `idx_parent_id` (`parent_id`) USING BTREE,
|
||||
KEY `idx_tenant_no` (`tenant_no`) USING BTREE
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='报销-费用项目表';
|
||||
|
||||
-- ----------------------------
|
||||
-- Records of bx_expense_item
|
||||
-- ----------------------------
|
||||
BEGIN;
|
||||
COMMIT;
|
||||
|
||||
-- ----------------------------
|
||||
-- Table structure for bx_reimburse_apply
|
||||
-- ----------------------------
|
||||
DROP TABLE IF EXISTS `bx_reimburse_apply`;
|
||||
CREATE TABLE `bx_reimburse_apply` (
|
||||
`id` varchar(64) NOT NULL COMMENT '主键ID(UUID)',
|
||||
`apply_code` varchar(32) NOT NULL COMMENT '报销单号(如 BX20260424001)',
|
||||
`title` varchar(256) NOT NULL COMMENT '报销标题',
|
||||
`applicant_id` varchar(64) NOT NULL COMMENT '申请人用户ID',
|
||||
`applicant_name` varchar(64) NOT NULL COMMENT '申请人姓名(冗余)',
|
||||
`expense_id` varchar(64) NOT NULL COMMENT '费用项目ID(二级项目)',
|
||||
`expense_name` varchar(128) NOT NULL COMMENT '费用项目名称(冗余)',
|
||||
`amount` decimal(14,2) NOT NULL COMMENT '报销金额',
|
||||
`invoice_count` int(11) NOT NULL DEFAULT '0' COMMENT '发票数量',
|
||||
`attach_count` int(11) NOT NULL DEFAULT '0' COMMENT '附件数量',
|
||||
`status` varchar(32) NOT NULL DEFAULT 'draft' COMMENT '状态:draft-草稿 pending-待审批 approved-审批通过 rejected-审批驳回 paid-已发放 offset-已冲抵',
|
||||
`current_node` varchar(128) DEFAULT NULL COMMENT '当前审批节点名称',
|
||||
`wf_id` varchar(64) DEFAULT NULL COMMENT '关联工作流定义ID',
|
||||
`pay_status` varchar(32) DEFAULT NULL COMMENT '支付状态:unpaid-未支付 paid-已发放 offset-已冲抵',
|
||||
`pay_time` datetime DEFAULT NULL COMMENT '支付时间',
|
||||
`pay_user_id` varchar(64) DEFAULT NULL COMMENT '支付操作人ID',
|
||||
`pay_user_name` varchar(64) DEFAULT NULL COMMENT '支付操作人姓名',
|
||||
`actual_amount` decimal(14,2) DEFAULT NULL COMMENT '实际发放金额',
|
||||
`offset_advance_id` varchar(64) DEFAULT NULL COMMENT '冲抵关联的备用金单ID',
|
||||
`offset_amount` decimal(14,2) DEFAULT NULL COMMENT '冲抵金额',
|
||||
`tenant_no` varchar(64) NOT NULL DEFAULT 'shanxia2.0' COMMENT '租户编号',
|
||||
`order_num` int(11) DEFAULT NULL COMMENT '排序号(公共)',
|
||||
`remark` varchar(512) DEFAULT NULL COMMENT '备注说明',
|
||||
`create_by` varchar(64) DEFAULT NULL COMMENT '创建人',
|
||||
`create_dept_id` varchar(64) NOT NULL DEFAULT '' COMMENT '创建部门',
|
||||
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||
`update_by` varchar(64) DEFAULT NULL COMMENT '更新人',
|
||||
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
||||
`del_flag` smallint(6) NOT NULL DEFAULT '0' COMMENT '删除标记:0-正常 1-已删除',
|
||||
PRIMARY KEY (`id`) USING BTREE,
|
||||
UNIQUE KEY `uk_apply_code` (`apply_code`) USING BTREE,
|
||||
KEY `idx_applicant_id` (`applicant_id`) USING BTREE,
|
||||
KEY `idx_status` (`status`) USING BTREE,
|
||||
KEY `idx_expense_id` (`expense_id`) USING BTREE,
|
||||
KEY `idx_tenant_no` (`tenant_no`) USING BTREE
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='报销-报销申请单';
|
||||
|
||||
-- ----------------------------
|
||||
-- Records of bx_reimburse_apply
|
||||
-- ----------------------------
|
||||
BEGIN;
|
||||
COMMIT;
|
||||
|
||||
-- ----------------------------
|
||||
-- Table structure for bx_reimburse_approval
|
||||
-- ----------------------------
|
||||
DROP TABLE IF EXISTS `bx_reimburse_approval`;
|
||||
CREATE TABLE `bx_reimburse_approval` (
|
||||
`id` varchar(64) NOT NULL COMMENT '主键ID(UUID)',
|
||||
`apply_id` varchar(64) NOT NULL COMMENT '报销申请单ID',
|
||||
`node_order` int(11) NOT NULL COMMENT '节点顺序',
|
||||
`node_name` varchar(128) NOT NULL COMMENT '节点名称',
|
||||
`approver_id` varchar(64) NOT NULL COMMENT '审批人用户ID',
|
||||
`approver_name` varchar(64) NOT NULL COMMENT '审批人姓名',
|
||||
`approval_status` varchar(32) NOT NULL COMMENT '审批结果:approved-通过 rejected-驳回',
|
||||
`approval_opinion` varchar(1024) DEFAULT NULL COMMENT '审批意见',
|
||||
`approval_time` datetime NOT NULL COMMENT '审批时间',
|
||||
`tenant_no` varchar(64) NOT NULL DEFAULT 'shanxia2.0' COMMENT '租户编号',
|
||||
`order_num` int(11) DEFAULT NULL COMMENT '排序号(公共)',
|
||||
`remark` varchar(512) DEFAULT NULL COMMENT '备注',
|
||||
`create_by` varchar(64) DEFAULT NULL COMMENT '创建人',
|
||||
`create_dept_id` varchar(64) NOT NULL DEFAULT '' COMMENT '创建部门',
|
||||
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||
`update_by` varchar(64) DEFAULT NULL COMMENT '更新人',
|
||||
`update_time` datetime DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
||||
`del_flag` smallint(6) NOT NULL DEFAULT '0' COMMENT '删除标记:0-正常 1-已删除',
|
||||
PRIMARY KEY (`id`) USING BTREE,
|
||||
KEY `idx_apply_id` (`apply_id`) USING BTREE,
|
||||
KEY `idx_tenant_no` (`tenant_no`) USING BTREE
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='报销-报销审批记录表';
|
||||
|
||||
-- ----------------------------
|
||||
-- Records of bx_reimburse_approval
|
||||
-- ----------------------------
|
||||
BEGIN;
|
||||
COMMIT;
|
||||
|
||||
-- ----------------------------
|
||||
-- Table structure for bx_reimburse_detail
|
||||
-- ----------------------------
|
||||
DROP TABLE IF EXISTS `bx_reimburse_detail`;
|
||||
CREATE TABLE `bx_reimburse_detail` (
|
||||
`id` varchar(64) NOT NULL COMMENT '主键ID(UUID)',
|
||||
`reimburse_id` varchar(64) NOT NULL COMMENT '报销单ID',
|
||||
`expense_id` varchar(64) NOT NULL COMMENT '费用项目ID',
|
||||
`expense_name` varchar(128) NOT NULL COMMENT '费用项目名称',
|
||||
`amount` decimal(14,2) NOT NULL COMMENT '报销金额',
|
||||
`tenant_no` varchar(64) NOT NULL DEFAULT 'shanxia2.0' COMMENT '租户编号',
|
||||
`order_num` int(11) DEFAULT NULL COMMENT '排序号(公共)',
|
||||
`remark` varchar(512) DEFAULT NULL COMMENT '备注',
|
||||
`create_by` varchar(64) DEFAULT NULL COMMENT '创建人',
|
||||
`create_dept_id` varchar(64) NOT NULL DEFAULT '' COMMENT '创建部门',
|
||||
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||
`update_by` varchar(64) DEFAULT NULL COMMENT '更新人',
|
||||
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
||||
`del_flag` smallint(6) NOT NULL DEFAULT '0' COMMENT '删除标记:0-正常 1-已删除',
|
||||
PRIMARY KEY (`id`) USING BTREE,
|
||||
KEY `idx_reimburse_id` (`reimburse_id`) USING BTREE,
|
||||
KEY `idx_tenant_no` (`tenant_no`) USING BTREE
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='报销-报销明细';
|
||||
|
||||
-- ----------------------------
|
||||
-- Records of bx_reimburse_detail
|
||||
-- ----------------------------
|
||||
BEGIN;
|
||||
COMMIT;
|
||||
|
||||
-- ----------------------------
|
||||
-- Table structure for bx_reimburse_offset
|
||||
-- ----------------------------
|
||||
DROP TABLE IF EXISTS `bx_reimburse_offset`;
|
||||
CREATE TABLE `bx_reimburse_offset` (
|
||||
`id` varchar(64) NOT NULL COMMENT '主键ID(UUID)',
|
||||
`reimburse_id` varchar(64) NOT NULL COMMENT '报销申请单ID',
|
||||
`advance_id` varchar(64) NOT NULL COMMENT '备用金申请单ID',
|
||||
`offset_amount` decimal(14,2) NOT NULL COMMENT '冲抵金额',
|
||||
`tenant_no` varchar(64) NOT NULL DEFAULT 'shanxia2.0' COMMENT '租户编号',
|
||||
`order_num` int(11) DEFAULT NULL COMMENT '排序号(公共)',
|
||||
`remark` varchar(512) DEFAULT NULL COMMENT '备注',
|
||||
`create_by` varchar(64) DEFAULT NULL COMMENT '创建人',
|
||||
`create_dept_id` varchar(64) NOT NULL DEFAULT '' COMMENT '创建部门',
|
||||
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||
`update_by` varchar(64) DEFAULT NULL COMMENT '更新人',
|
||||
`update_time` datetime DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
||||
`del_flag` smallint(6) NOT NULL DEFAULT '0' COMMENT '删除标记:0-正常 1-已删除',
|
||||
PRIMARY KEY (`id`) USING BTREE,
|
||||
KEY `idx_reimburse_id` (`reimburse_id`) USING BTREE,
|
||||
KEY `idx_advance_id` (`advance_id`) USING BTREE,
|
||||
KEY `idx_tenant_no` (`tenant_no`) USING BTREE
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='报销-报销单备用金冲抵关联表';
|
||||
|
||||
-- ----------------------------
|
||||
-- Records of bx_reimburse_offset
|
||||
-- ----------------------------
|
||||
BEGIN;
|
||||
COMMIT;
|
||||
|
||||
-- ----------------------------
|
||||
-- Table structure for bx_workflow_def
|
||||
-- ----------------------------
|
||||
DROP TABLE IF EXISTS `bx_workflow_def`;
|
||||
CREATE TABLE `bx_workflow_def` (
|
||||
`id` varchar(64) NOT NULL COMMENT '主键ID(UUID)',
|
||||
`biz_type` varchar(32) NOT NULL COMMENT '业务类型:advance-备用金 reimburse-报销单',
|
||||
`wf_name` varchar(128) NOT NULL COMMENT '工作流名称',
|
||||
`status` tinyint(4) NOT NULL DEFAULT '1' COMMENT '状态:1-启用 0-禁用',
|
||||
`tenant_no` varchar(64) NOT NULL DEFAULT 'shanxia2.0' COMMENT '租户编号',
|
||||
`order_num` int(11) DEFAULT NULL COMMENT '排序号(公共)',
|
||||
`remark` varchar(512) DEFAULT NULL COMMENT '备注',
|
||||
`create_by` varchar(64) DEFAULT NULL COMMENT '创建人',
|
||||
`create_dept_id` varchar(64) NOT NULL DEFAULT '' COMMENT '创建部门',
|
||||
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||
`update_by` varchar(64) DEFAULT NULL COMMENT '更新人',
|
||||
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
||||
`del_flag` smallint(6) NOT NULL DEFAULT '0' COMMENT '删除标记:0-正常 1-已删除',
|
||||
PRIMARY KEY (`id`) USING BTREE,
|
||||
KEY `idx_biz_type` (`biz_type`) USING BTREE,
|
||||
KEY `idx_tenant_no` (`tenant_no`) USING BTREE
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='报销-工作流定义表';
|
||||
|
||||
-- ----------------------------
|
||||
-- Records of bx_workflow_def
|
||||
-- ----------------------------
|
||||
BEGIN;
|
||||
COMMIT;
|
||||
|
||||
-- ----------------------------
|
||||
-- Table structure for bx_workflow_node
|
||||
-- ----------------------------
|
||||
DROP TABLE IF EXISTS `bx_workflow_node`;
|
||||
CREATE TABLE `bx_workflow_node` (
|
||||
`id` varchar(64) NOT NULL COMMENT '主键ID(UUID)',
|
||||
`wf_id` varchar(64) NOT NULL COMMENT '工作流定义ID',
|
||||
`node_name` varchar(128) NOT NULL COMMENT '节点名称(如:主管审批、财务复核)',
|
||||
`node_order` int(11) NOT NULL DEFAULT '0' COMMENT '节点顺序(从小到大执行)',
|
||||
`approver_id` varchar(64) DEFAULT NULL COMMENT '审批人用户ID',
|
||||
`approver_name` varchar(64) DEFAULT NULL COMMENT '审批人姓名(冗余)',
|
||||
`tenant_no` varchar(64) NOT NULL DEFAULT 'shanxia2.0' COMMENT '租户编号',
|
||||
`order_num` int(11) DEFAULT NULL COMMENT '排序号(公共)',
|
||||
`remark` varchar(512) DEFAULT NULL COMMENT '备注',
|
||||
`create_by` varchar(64) DEFAULT NULL COMMENT '创建人',
|
||||
`create_dept_id` varchar(64) NOT NULL DEFAULT '' COMMENT '创建部门',
|
||||
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||
`update_by` varchar(64) DEFAULT NULL COMMENT '更新人',
|
||||
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
||||
`del_flag` smallint(6) NOT NULL DEFAULT '0' COMMENT '删除标记:0-正常 1-已删除',
|
||||
PRIMARY KEY (`id`) USING BTREE,
|
||||
KEY `idx_wf_id` (`wf_id`) USING BTREE,
|
||||
KEY `idx_tenant_no` (`tenant_no`) USING BTREE
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='报销-工作流节点表';
|
||||
|
||||
-- ----------------------------
|
||||
-- Records of bx_workflow_node
|
||||
-- ----------------------------
|
||||
BEGIN;
|
||||
COMMIT;
|
||||
|
||||
-- ----------------------------
|
||||
-- Table structure for crm_clue
|
||||
-- ----------------------------
|
||||
|
||||
+362
-22
@@ -5,8 +5,8 @@
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/backend/app/main.py": {
|
||||
"mtime": 1780201410.1131313,
|
||||
"ast_hash": "14dee80cbc1a9e3a5a0fc7b5b7f3820c",
|
||||
"mtime": 1780750556.8821394,
|
||||
"ast_hash": "9d2dc014c76287a8e8a4a7f4c4c633cc",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/backend/app/tasks/customer_pool.py": {
|
||||
@@ -40,8 +40,8 @@
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/backend/app/core/config.py": {
|
||||
"mtime": 1780131767.561871,
|
||||
"ast_hash": "650ee00a9cad587e2ca66be4bc583aff",
|
||||
"mtime": 1780750556.8823087,
|
||||
"ast_hash": "b7a28e6af80b6160097dfd7dbdfa5ff6",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/backend/app/core/wechat_pay.py": {
|
||||
@@ -90,8 +90,8 @@
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/backend/app/core/attachment_biz.py": {
|
||||
"mtime": 1780360597.164981,
|
||||
"ast_hash": "69b67b2e72706b20233fdeda283c4576",
|
||||
"mtime": 1780750904.0571795,
|
||||
"ast_hash": "31445f82b9838f6ddcbf08ecedaea351",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/backend/app/core/context.py": {
|
||||
@@ -280,7 +280,7 @@
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/crm/contract.py": {
|
||||
"mtime": 1780743830.220982,
|
||||
"mtime": 1780758461.4052296,
|
||||
"ast_hash": "6553f54ca1fd19086c170095f402a628",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
@@ -395,7 +395,7 @@
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/backend/app/crud/crm/contract_product.py": {
|
||||
"mtime": 1780743830.2274046,
|
||||
"mtime": 1780758461.405257,
|
||||
"ast_hash": "d2e1538af2d36ecc9daf28a3b135bd0f",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
@@ -410,7 +410,7 @@
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/backend/app/crud/crm/contract_approval.py": {
|
||||
"mtime": 1780743830.2537448,
|
||||
"mtime": 1780758461.4052966,
|
||||
"ast_hash": "c9c338510247afdcd733412c10e0ded3",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
@@ -475,7 +475,7 @@
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/backend/app/crud/crm/clue_statistics.py": {
|
||||
"mtime": 1780743830.2298,
|
||||
"mtime": 1780758461.405326,
|
||||
"ast_hash": "9a026c628764467e4d1398900105dc78",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
@@ -495,7 +495,7 @@
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/backend/app/crud/crm/contract.py": {
|
||||
"mtime": 1780743830.2209544,
|
||||
"mtime": 1780758461.4050884,
|
||||
"ast_hash": "3cd90455687d8cc24d4b664d1fd5eaa2",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
@@ -520,7 +520,7 @@
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/backend/app/api/crm_contract_sub_routes.py": {
|
||||
"mtime": 1780743830.2502718,
|
||||
"mtime": 1780758461.4060414,
|
||||
"ast_hash": "c05e2faf142cb664a73975112d26d658",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
@@ -530,8 +530,8 @@
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/backend/app/api/__init__.py": {
|
||||
"mtime": 1780201410.1104653,
|
||||
"ast_hash": "32a1c56ed1b24308513c1ab4f44c72a2",
|
||||
"mtime": 1780750556.8831582,
|
||||
"ast_hash": "f0ed76e504b60330b436160d96753b61",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/backend/app/api/menu.py": {
|
||||
@@ -550,7 +550,7 @@
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/backend/app/api/crm_contract_routes.py": {
|
||||
"mtime": 1780743830.220907,
|
||||
"mtime": 1780758461.4051092,
|
||||
"ast_hash": "e12302586789d2e8cf85469226be2899",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
@@ -2475,8 +2475,8 @@
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/web-admin/src/components/core/layouts/art-menus/art-sidebar-menu/index.vue": {
|
||||
"mtime": 1780201410.1612706,
|
||||
"ast_hash": "e2137fd84ca3a00d18cb546d29df04ca",
|
||||
"mtime": 1780753478.4552467,
|
||||
"ast_hash": "ba265e7f6a3b6b3586d274e7c79ce140",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/web-admin/src/components/core/layouts/art-menus/art-sidebar-menu/widget/SidebarSubmenu.vue": {
|
||||
@@ -2910,7 +2910,7 @@
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/web-admin/src/views/crm/clue/statistics/index.vue": {
|
||||
"mtime": 1780743830.2537415,
|
||||
"mtime": 1780763324.1037285,
|
||||
"ast_hash": "83247d6f2a740c829b7a4d0a296fdf83",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
@@ -3420,8 +3420,8 @@
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/web-admin/src/router/modules/sqxp.ts": {
|
||||
"mtime": 1780242127.0352678,
|
||||
"ast_hash": "145b83a631711ccb3f59d78d5fe34758",
|
||||
"mtime": 1780753257.1643171,
|
||||
"ast_hash": "7752e455e4c11ef368bda42ff9e9f92b",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/web-admin/src/router/modules/index.ts": {
|
||||
@@ -5225,8 +5225,8 @@
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/web-admin/package.json": {
|
||||
"mtime": 1780219620.50469,
|
||||
"ast_hash": "7d7dd80d11cdf382ad2364128145b29c",
|
||||
"mtime": 1780752670.7718465,
|
||||
"ast_hash": "e93877b494638c840d003c67c3f6401a",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/web-admin/tsconfig.json": {
|
||||
@@ -5283,5 +5283,345 @@
|
||||
"mtime": 1780742010.017625,
|
||||
"ast_hash": "c0df54dff6daad2a091db842b3e0c803",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/web-admin/src/utils/bx/expenseItemCode.ts": {
|
||||
"mtime": 1780752613.9072092,
|
||||
"ast_hash": "65d0715cb8d40d23b4df1552f07ca136",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/web-admin/src/utils/bx/format.ts": {
|
||||
"mtime": 1780756590.4817746,
|
||||
"ast_hash": "b96c952649dd029d16f36b6fcb8e4a76",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/web-admin/src/utils/http/bx.ts": {
|
||||
"mtime": 1780752599.942857,
|
||||
"ast_hash": "eb352e21db69cd209062459ec2ba6584",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/web-admin/src/components/bx/template/ListToolbar.vue": {
|
||||
"mtime": 1780752613.8986316,
|
||||
"ast_hash": "8184200c37281fa8875a3ab8286d6d1f",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/web-admin/src/components/bx/template/FilterBlock.vue": {
|
||||
"mtime": 1780752613.893088,
|
||||
"ast_hash": "7a521e6b019db562d13a8f5209bac19c",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/web-admin/src/components/bx/template/DataTablePanel.vue": {
|
||||
"mtime": 1780752613.8926337,
|
||||
"ast_hash": "21d810c4e33ab5c643d6dae8db27cdf9",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/web-admin/src/components/bx/template/ListPageScaffold.vue": {
|
||||
"mtime": 1780752613.89413,
|
||||
"ast_hash": "9281a4b23ca4a6016377a1eeaca1130f",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/web-admin/src/components/bx/base/BaseOpButton.vue": {
|
||||
"mtime": 1780752613.8844402,
|
||||
"ast_hash": "7c721fcfad0a270eaaf5303b057a057f",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/web-admin/src/components/bx/base/BaseSelect.vue": {
|
||||
"mtime": 1780752613.8852646,
|
||||
"ast_hash": "99711a65c38e8d1fff9091af84770da0",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/web-admin/src/components/bx/base/BaseTag.vue": {
|
||||
"mtime": 1780752613.8868194,
|
||||
"ast_hash": "30e0e8e89087099cb4bd0a13a3a0ae4c",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/web-admin/src/components/bx/base/BaseButton.vue": {
|
||||
"mtime": 1780752613.872528,
|
||||
"ast_hash": "81bd26a126797cef57f3d2b4961801f2",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/web-admin/src/components/bx/base/BaseDialog.vue": {
|
||||
"mtime": 1780752613.8741815,
|
||||
"ast_hash": "1c052608fcb18e3cc9d4376a559d2966",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/web-admin/src/components/bx/base/BaseTable.vue": {
|
||||
"mtime": 1780752613.88601,
|
||||
"ast_hash": "32a8d89915b1fb7ba183a00a036450f6",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/web-admin/src/components/bx/base/BaseDetailTableSection.vue": {
|
||||
"mtime": 1780760191.3960986,
|
||||
"ast_hash": "3dd2c900e22a2f38438cbe30ba615331",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/web-admin/src/components/bx/base/BaseInput.vue": {
|
||||
"mtime": 1780752613.8769777,
|
||||
"ast_hash": "73fa5e005cf32338ca6c46b0d7880683",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/web-admin/src/components/bx/base/BaseClampText.vue": {
|
||||
"mtime": 1780752613.873146,
|
||||
"ast_hash": "280acf00d1bbfc6b11eee7e5212f421b",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/web-admin/src/components/bx/base/ApprovalFlowView.vue": {
|
||||
"mtime": 1780758206.8546696,
|
||||
"ast_hash": "d2dde9134386fd15e21a45e8fa1f5882",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/web-admin/src/components/bx/base/WorkflowNodeCell.vue": {
|
||||
"mtime": 1780752653.179815,
|
||||
"ast_hash": "d5c3e9e4a5cefd43e73f7ffc37608feb",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/web-admin/src/hooks/bx/useApproveMenuBadge.ts": {
|
||||
"mtime": 1780752647.2106802,
|
||||
"ast_hash": "924a161edbd72b13e17227292d057401",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/web-admin/src/hooks/bx/useApplicantOptions.ts": {
|
||||
"mtime": 1780752646.1810515,
|
||||
"ast_hash": "b9e2c4cb03ec6299dafceea4a47752e0",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/web-admin/src/hooks/bx/useExpenseItemTree.ts": {
|
||||
"mtime": 1780760526.6676378,
|
||||
"ast_hash": "ef7ab8a134a297d77282009416706a74",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/web-admin/src/hooks/bx/usePagedTable.ts": {
|
||||
"mtime": 1780752613.9877086,
|
||||
"ast_hash": "d455d26313c07aeeacbda18d2e23434b",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/web-admin/src/hooks/bx/useServerPaged.ts": {
|
||||
"mtime": 1780752613.990241,
|
||||
"ast_hash": "66708069c354455b78556c58d5f94771",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/web-admin/src/api/bx/index.ts": {
|
||||
"mtime": 1780757619.4888484,
|
||||
"ast_hash": "6c911937604a39d3f0153eb5def19ae8",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/web-admin/src/views/bx/payment/index.vue": {
|
||||
"mtime": 1780763490.7587097,
|
||||
"ast_hash": "5b5dd01ef0f3561130c293149aa3c8dd",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/web-admin/src/views/bx/advance/apply/index.vue": {
|
||||
"mtime": 1780762665.5609775,
|
||||
"ast_hash": "f61237436c91367499d5f32df088c76c",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/web-admin/src/views/bx/advance/approve/index.vue": {
|
||||
"mtime": 1780757454.7531683,
|
||||
"ast_hash": "447dd94608d177c8f637de6e7f34b36f",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/web-admin/src/views/bx/advance/issue/index.vue": {
|
||||
"mtime": 1780763653.0696034,
|
||||
"ast_hash": "554e505ffb23107026fdfd65957e4fda",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/web-admin/src/views/bx/reimburse/apply/index.vue": {
|
||||
"mtime": 1780763416.0074606,
|
||||
"ast_hash": "d8372ca9957c1b6a552b7e2ee074b434",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/web-admin/src/views/bx/reimburse/approve/index.vue": {
|
||||
"mtime": 1780763428.446719,
|
||||
"ast_hash": "025d09b210a1f6239f46df60dd0c4a08",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/web-admin/src/views/bx/workflow/advance/index.vue": {
|
||||
"mtime": 1780756601.8436413,
|
||||
"ast_hash": "e33c4ad30db3e418d345e96b96f9e814",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/web-admin/src/views/bx/workflow/reimburse/index.vue": {
|
||||
"mtime": 1780756601.8592331,
|
||||
"ast_hash": "bba9ee238816707eba5bfdf60e694dc2",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/web-admin/src/views/bx/view/all/index.vue": {
|
||||
"mtime": 1780760362.8554158,
|
||||
"ast_hash": "2c3af567ddf2fd568441454bef07f745",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/web-admin/src/views/bx/view/todo/index.vue": {
|
||||
"mtime": 1780761403.9424925,
|
||||
"ast_hash": "f29ef9f6eeccc5742671475081b558b4",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/web-admin/src/views/bx/view/mine/index.vue": {
|
||||
"mtime": 1780760362.6476135,
|
||||
"ast_hash": "cf0d49d7921a16a4ef65cda5ad88446e",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/web-admin/src/views/bx/expense-item/index.vue": {
|
||||
"mtime": 1780756601.7798786,
|
||||
"ast_hash": "dbb41e8e7c6b51c0bcf372e09f1e1fc6",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/backend/app/core/bx_auth.py": {
|
||||
"mtime": 1780750556.882335,
|
||||
"ast_hash": "992aca5bcca63b250109f23d36031bdb",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/backend/app/utils/bx_date_range.py": {
|
||||
"mtime": 1780750556.881769,
|
||||
"ast_hash": "c40b659e0b1d8a549e97923a9a536719",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/backend/app/utils/bx_codegen.py": {
|
||||
"mtime": 1780750556.8829591,
|
||||
"ast_hash": "ca25a3c561c4a1bfc566168d85b5f4de",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/backend/app/models/bx_models.py": {
|
||||
"mtime": 1780752873.936801,
|
||||
"ast_hash": "53f1d2880a144b02074b7f734f12d92a",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/bx/reimburse.py": {
|
||||
"mtime": 1780751335.1849163,
|
||||
"ast_hash": "4d040ab00d9288b03a0e5448e54340cd",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/bx/expense_item.py": {
|
||||
"mtime": 1780750595.66133,
|
||||
"ast_hash": "2dcb1f8935122ecc1129d47f41329e2d",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/bx/__init__.py": {
|
||||
"mtime": 1780750556.8817346,
|
||||
"ast_hash": "2cea3812d44c57f24aa7f00648a14412",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/bx/attachment.py": {
|
||||
"mtime": 1780750871.4800005,
|
||||
"ast_hash": "97ee54c0f5e7e6944a6d5edba9959b7b",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/bx/advance.py": {
|
||||
"mtime": 1780757815.2697868,
|
||||
"ast_hash": "d2eeaba820accc122366f244b3e50ef9",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/bx/common.py": {
|
||||
"mtime": 1780750556.882896,
|
||||
"ast_hash": "e97cb788e93cfac0688c0aa4cbd2cf93",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/backend/app/schemas/bx/workflow.py": {
|
||||
"mtime": 1780750597.0023274,
|
||||
"ast_hash": "84a4177765ae7baf25f55b8a7858cffe",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/reimburse.py": {
|
||||
"mtime": 1780758906.744178,
|
||||
"ast_hash": "e6f722a54dcb0a1017d54334e59c731e",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/expense_item.py": {
|
||||
"mtime": 1780750631.6409054,
|
||||
"ast_hash": "ec3143dd9c80ed89ccbdada33af3b048",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/__init__.py": {
|
||||
"mtime": 1780751360.1800659,
|
||||
"ast_hash": "683657a15bc1923bff7a7d60f1dd965d",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/attachment.py": {
|
||||
"mtime": 1780750903.379992,
|
||||
"ast_hash": "c3d0da835eff5f4d08d174741c7faa83",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/advance.py": {
|
||||
"mtime": 1780758906.5070424,
|
||||
"ast_hash": "fd125c07b86418ad454f7b2d9f090aec",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/workflow.py": {
|
||||
"mtime": 1780756089.7304258,
|
||||
"ast_hash": "e13af66a1b3ac92225315a4df38db13f",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/backend/app/api/bx/payment.py": {
|
||||
"mtime": 1780751365.9410522,
|
||||
"ast_hash": "f9e1133888b3bf36e702a6e303623a34",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/reimburse.py": {
|
||||
"mtime": 1780758908.405342,
|
||||
"ast_hash": "2e8ac33bc523284cfea413db1aaeaf6b",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/expense_item.py": {
|
||||
"mtime": 1780750601.2191534,
|
||||
"ast_hash": "a3f9e3f9e03b2b81d048be2fbb995a53",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/__init__.py": {
|
||||
"mtime": 1780750594.045302,
|
||||
"ast_hash": "782178a68c005e9671eeaef56ce8979f",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/attachment.py": {
|
||||
"mtime": 1780750887.666369,
|
||||
"ast_hash": "1534ad3911e5b3da36e09fec5efbb9fc",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/advance.py": {
|
||||
"mtime": 1780758906.8892431,
|
||||
"ast_hash": "b1271ff02969bff61d4190fb50c0d55a",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/storage.py": {
|
||||
"mtime": 1780750869.826924,
|
||||
"ast_hash": "a2549a79ff52c07c21bcdce831ca28f5",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/workflow.py": {
|
||||
"mtime": 1780756089.1444035,
|
||||
"ast_hash": "a58293c795a169f40656222738a22630",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/base.py": {
|
||||
"mtime": 1780750593.8290622,
|
||||
"ast_hash": "1e6a5197afea4b037af84cccf34a884b",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/web-admin/src/views/index/route-parent.vue": {
|
||||
"mtime": 1780753053.641752,
|
||||
"ast_hash": "42ecef008755f2cece85bc0c376ff4e8",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/web-admin/src/components/bx/base/ApprovalHistoryView.vue": {
|
||||
"mtime": 1780758211.63801,
|
||||
"ast_hash": "d8426be908f01e26aa7b3e7f0c1d2418",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/backend/app/services/bx/approval_cycle.py": {
|
||||
"mtime": 1780758200.9048047,
|
||||
"ast_hash": "2147b45ce5131338bdefbf473777e751",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/web-admin/src/utils/bx/attachment.ts": {
|
||||
"mtime": 1780763324.103673,
|
||||
"ast_hash": "acea2f7b9bc88bcf68b6a7d85306a62e",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/web-admin/src/components/bx/base/BxAttachmentReadonly.vue": {
|
||||
"mtime": 1780763385.7825282,
|
||||
"ast_hash": "7928eeef33f1e2df7525bd8b86bb3a07",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"/Users/zlwu/work/00code/shanxia2.0/web-admin/src/components/bx/base/BxAttachmentUpload.vue": {
|
||||
"mtime": 1780763324.103737,
|
||||
"ast_hash": "1b9cd42b0a1e3b7ff74821185d65b432",
|
||||
"semantic_hash": ""
|
||||
}
|
||||
}
|
||||
Loaded 100 of 155 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user