在大宗商品贸易企业的点价业务中,审批流程的合理设计直接影响交易效率与风控合规。客户自助点价、额度校验、容忍度审批、夜盘自动处理等场景,均需要精细化的角色权限配置。本文从RBAC权限模型出发,结合点价业务的实际流程,解析价格风险管理平台(Pricing Risk Management Platform)的审批角色体系、权限矩阵设计与动态审批流引擎的技术实现。
一、点价业务角色模型与职责边界
点价业务涉及销售、交易、风控、财务多个角色的协同。基于RBAC(Role-Based Access Control)模型,角色定义需映射到实际业务职责:
python
from enum import Enum, auto
from dataclasses import dataclass, field
from typing import Set, List, Optional
from decimal import Decimal
class Permission(Enum):
"""点价业务权限枚举"""
# 点价操作权限
PRICE_CREATE = auto() # 创建点价单
PRICE_MODIFY = auto() # 修改点价单
PRICE_CANCEL = auto() # 取消点价单
PRICE_APPROVE = auto() # 审批点价单
# 额度管理权限
QUOTA_VIEW = auto() # 查看额度
QUOTA_MODIFY = auto() # 调整额度
QUOTA_APPROVE = auto() # 审批额度调整
# 容忍度配置权限
TOLERANCE_CONFIG = auto() # 配置容忍度阈值
TOLERANCE_OVERRIDE = auto() # 超限强制通过
# 风控权限
RISK_VIEW = auto() # 查看风险敞口
RISK_ALERT_CONFIG = auto() # 配置风险预警
TRADE_SUSPEND = auto() # 暂停交易权限
# 报表权限
REPORT_VIEW = auto() # 查看报表
REPORT_EXPORT = auto() # 导出报表
class Role(Enum):
"""业务角色定义"""
CUSTOMER = "客户" # 客户自助点价
SALES = "销售经理" # 创建合同、管理客商
TRADER = "交易员" # 执行交易、管理持仓
RISK_OFFICER = "风控专员" # 风险监控、预警配置
RISK_MANAGER = "风控经理" # 审批超限、暂停交易
FINANCE = "财务专员" # 结算对账、报表导出
ADMIN = "系统管理员" # 全量权限
# 角色-权限映射矩阵
ROLE_PERMISSIONS: dict[Role, Set[Permission]] = {
Role.CUSTOMER: {
Permission.PRICE_CREATE,
Permission.PRICE_MODIFY,
Permission.PRICE_CANCEL,
Permission.QUOTA_VIEW,
},
Role.SALES: {
Permission.PRICE_CREATE,
Permission.PRICE_MODIFY,
Permission.PRICE_CANCEL,
Permission.QUOTA_VIEW,
Permission.REPORT_VIEW,
},
Role.TRADER: {
Permission.PRICE_APPROVE,
Permission.QUOTA_VIEW,
Permission.RISK_VIEW,
Permission.REPORT_VIEW,
},
Role.RISK_OFFICER: {
Permission.RISK_VIEW,
Permission.RISK_ALERT_CONFIG,
Permission.QUOTA_VIEW,
Permission.TOLERANCE_CONFIG,
Permission.REPORT_VIEW,
Permission.REPORT_EXPORT,
},
Role.RISK_MANAGER: {
Permission.PRICE_APPROVE,
Permission.QUOTA_MODIFY,
Permission.QUOTA_APPROVE,
Permission.TOLERANCE_OVERRIDE,
Permission.RISK_VIEW,
Permission.RISK_ALERT_CONFIG,
Permission.TRADE_SUSPEND,
Permission.REPORT_VIEW,
Permission.REPORT_EXPORT,
},
Role.ADMIN: set(Permission), # 全部权限
}
@dataclass
class User:
"""用户实体"""
user_id: str
name: str
roles: Set[Role]
customer_scope: Optional[List[str]] = None # 可访问的客商列表
contract_scope: Optional[List[str]] = None # 可访问的合同列表
def has_permission(self, permission: Permission) -> bool:
"""检查用户是否拥有指定权限"""
for role in self.roles:
if permission in ROLE_PERMISSIONS.get(role, set()):
return True
return False
def get_all_permissions(self) -> Set[Permission]:
"""获取用户所有权限"""
permissions = set()
for role in self.roles:
permissions.update(ROLE_PERMISSIONS.get(role, set()))
return permissions
# 使用示例
trader = User(
user_id="U001",
name="张三",
roles={Role.TRADER, Role.RISK_OFFICER},
customer_scope=["CUST_A", "CUST_B"]
)
print(f"用户权限: {[p.name for p in trader.get_all_permissions()]}")
print(f"是否可审批点价: {trader.has_permission(Permission.PRICE_APPROVE)}")
print(f"是否可暂停交易: {trader.has_permission(Permission.TRADE_SUSPEND)}")
该模型支持多角色叠加,用户可同时具备交易员与风控专员身份,权限自动合并。
二、动态审批流引擎与条件路由
点价业务的审批流需根据金额、客户信用等级、超限情况动态路由。以贸易公司点价审批为例,小额常规点价自动通过,超额度或超容忍度需逐级审批:
python
from dataclasses import dataclass
from typing import Callable, List, Optional
from decimal import Decimal
from enum import Enum
class ApprovalStatus(Enum):
PENDING = "待审批"
APPROVED = "已通过"
REJECTED = "已拒绝"
AUTO_APPROVED = "自动通过"
@dataclass
class PricingRequest:
"""点价申请"""
request_id: str
customer_id: str
contract_id: str
commodity: str
quantity: Decimal # 点价数量(吨)
target_price: Decimal # 目标价格
current_quota: Decimal # 当前剩余额度
tolerance: Decimal # 容忍度阈值(%)
price_deviation: Decimal # 价格偏离度(%)
customer_credit: str # 客户信用等级: A/B/C/D
is_night_session: bool # 是否夜盘
@property
def request_value(self) -> Decimal:
"""点价金额"""
return self.quantity * self.target_price
@dataclass
class ApprovalRule:
"""审批规则"""
rule_id: str
name: str
condition: Callable[[PricingRequest], bool]
required_role: Role
priority: int # 优先级,数字越小越先匹配
auto_approve: bool = False # 是否自动审批
class ApprovalEngine:
"""动态审批流引擎"""
def __init__(self):
self.rules: List[ApprovalRule] = []
self._init_default_rules()
def _init_default_rules(self):
"""初始化默认审批规则"""
# 规则1: 夜盘+A级客户+额度内+容忍度内 → 自动通过
self.rules.append(ApprovalRule(
rule_id="R001",
name="夜盘自动审批",
condition=lambda r: (
r.is_night_session and
r.customer_credit == "A" and
r.request_value <= r.current_quota and
r.price_deviation <= r.tolerance
),
required_role=Role.TRADER, # 系统代为审批
priority=1,
auto_approve=True
))
# 规则2: 超额度 → 需风控经理审批
self.rules.append(ApprovalRule(
rule_id="R002",
name="超额度审批",
condition=lambda r: r.request_value > r.current_quota,
required_role=Role.RISK_MANAGER,
priority=2
))
# 规则3: 超容忍度 → 需风控经理审批
self.rules.append(ApprovalRule(
rule_id="R003",
name="超容忍度审批",
condition=lambda r: r.price_deviation > r.tolerance,
required_role=Role.RISK_MANAGER,
priority=3
))
# 规则4: C/D级客户 → 需风控专员审批
self.rules.append(ApprovalRule(
rule_id="R004",
name="低信用客户审批",
condition=lambda r: r.customer_credit in ("C", "D"),
required_role=Role.RISK_OFFICER,
priority=4
))
# 规则5: 默认 → 交易员审批
self.rules.append(ApprovalRule(
rule_id="R999",
name="常规审批",
condition=lambda r: True, # 兜底规则
required_role=Role.TRADER,
priority=999
))
# 按优先级排序
self.rules.sort(key=lambda r: r.priority)
def route(self, request: PricingRequest) -> List[ApprovalRule]:
"""路由审批流程,返回匹配的审批规则链"""
matched_rules = []
for rule in self.rules:
if rule.condition(request):
matched_rules.append(rule)
if rule.auto_approve:
break # 自动通过则终止
if rule.priority < 100: # 非兜底规则继续匹配
continue
break
return matched_rules
# 审批流测试
engine = ApprovalEngine()
# 场景1: 夜盘A级客户常规点价
request1 = PricingRequest(
request_id="PR001", customer_id="CUST_A", contract_id="C001",
commodity="铜", quantity=Decimal("100"), target_price=Decimal("75000"),
current_quota=Decimal("10000000"), tolerance=Decimal("2.0"),
price_deviation=Decimal("0.5"), customer_credit="A", is_night_session=True
)
# 场景2: 超额度申请
request2 = PricingRequest(
request_id="PR002", customer_id="CUST_B", contract_id="C002",
commodity="铝", quantity=Decimal("500"), target_price=Decimal("20000"),
current_quota=Decimal("5000000"), tolerance=Decimal("1.5"),
price_deviation=Decimal("0.8"), customer_credit="B", is_night_session=False
)
for req in [request1, request2]:
rules = engine.route(req)
print(f"\n请求 {req.request_id}:")
for rule in rules:
auto_tag = "[自动]" if rule.auto_approve else ""
print(f" → {rule.name} {auto_tag} 需要角色: {rule.required_role.value}")
审批引擎支持规则热加载,业务人员可通过配置界面调整规则条件,无需代码变更。
三、客商维度权限隔离与数据边界
点价业务涉及敏感的客商信息与交易数据,需实现严格的数据隔离。基于属性的访问控制(ABAC)扩展实现细粒度权限:
python
from dataclasses import dataclass
from typing import List, Set, Optional
from functools import wraps
@dataclass
class DataScope:
"""数据访问范围"""
customers: Set[str] # 可访问客商
contracts: Set[str] # 可访问合同
commodities: Set[str] # 可访问品种
regions: Set[str] # 可访问区域
def can_access_customer(self, customer_id: str) -> bool:
return "*" in self.customers or customer_id in self.customers
def can_access_contract(self, contract_id: str) -> bool:
return "*" in self.contracts or contract_id in self.contracts
class DataAccessControl:
"""数据访问控制器"""
def __init__(self, user: User, scope: DataScope):
self.user = user
self.scope = scope
def filter_pricing_requests(
self,
requests: List[PricingRequest]
) -> List[PricingRequest]:
"""过滤用户可见的点价申请"""
return [
r for r in requests
if self.scope.can_access_customer(r.customer_id)
and self.scope.can_access_contract(r.contract_id)
]
def check_operation(
self,
permission: Permission,
customer_id: Optional[str] = None,
contract_id: Optional[str] = None
) -> bool:
"""检查用户是否可执行指定操作"""
# 功能权限检查
if not self.user.has_permission(permission):
return False
# 数据权限检查
if customer_id and not self.scope.can_access_customer(customer_id):
return False
if contract_id and not self.scope.can_access_contract(contract_id):
return False
return True
def require_permission(permission: Permission):
"""权限校验装饰器"""
def decorator(func):
@wraps(func)
def wrapper(self, *args, **kwargs):
customer_id = kwargs.get('customer_id')
contract_id = kwargs.get('contract_id')
if not self.access_control.check_operation(
permission, customer_id, contract_id
):
raise PermissionError(
f"用户 {self.access_control.user.name} "
f"无权执行 {permission.name}"
)
return func(self, *args, **kwargs)
return wrapper
return decorator
# 业务服务示例
class PricingService:
def __init__(self, access_control: DataAccessControl):
self.access_control = access_control
@require_permission(Permission.PRICE_APPROVE)
def approve_request(
self,
request_id: str,
customer_id: str = None,
contract_id: str = None
) -> dict:
"""审批点价申请"""
return {"status": "approved", "request_id": request_id}
# 测试权限隔离
scope = DataScope(
customers={"CUST_A", "CUST_B"},
contracts={"C001", "C002", "C003"},
commodities={"*"},
regions={"华东", "华南"}
)
access_ctrl = DataAccessControl(trader, scope)
service = PricingService(access_ctrl)
try:
result = service.approve_request("PR001", customer_id="CUST_A")
print(f"审批成功: {result}")
except PermissionError as e:
print(f"权限拒绝: {e}")
快期-点价宝通过客商维度授权机制,确保销售只能查看和操作自己负责的客户点价单。
四、审批日志与合规审计追踪
所有审批操作需完整留痕,满足内部审计与监管要求:
python
from datetime import datetime
from dataclasses import dataclass
from typing import Optional
import json
@dataclass
class ApprovalLog:
"""审批日志"""
log_id: str
request_id: str
action: str # APPROVE/REJECT/ESCALATE
operator_id: str
operator_name: str
operator_role: str
timestamp: datetime
decision: str
reason: Optional[str]
ip_address: str
previous_status: str
new_status: str
def to_audit_record(self) -> dict:
"""转换为审计记录格式"""
return {
"事件类型": "点价审批",
"操作时间": self.timestamp.isoformat(),
"操作人": f"{self.operator_name}({self.operator_role})",
"操作类型": self.action,
"申请单号": self.request_id,
"审批结果": self.decision,
"备注": self.reason or "",
"状态变更": f"{self.previous_status} → {self.new_status}",
"IP地址": self.ip_address
}
class AuditLogger:
"""审计日志记录器"""
def __init__(self):
self.logs: List[ApprovalLog] = []
def log_approval(
self,
request_id: str,
user: User,
action: str,
decision: str,
reason: str = None,
ip_address: str = "127.0.0.1"
) -> ApprovalLog:
"""记录审批操作"""
log = ApprovalLog(
log_id=f"LOG{datetime.now().strftime('%Y%m%d%H%M%S%f')}",
request_id=request_id,
action=action,
operator_id=user.user_id,
operator_name=user.name,
operator_role=",".join(r.value for r in user.roles),
timestamp=datetime.now(),
decision=decision,
reason=reason,
ip_address=ip_address,
previous_status="PENDING",
new_status="APPROVED" if decision == "通过" else "REJECTED"
)
self.logs.append(log)
return log
def export_audit_report(self, start_date: datetime, end_date: datetime) -> str:
"""导出审计报告"""
filtered = [
log for log in self.logs
if start_date <= log.timestamp <= end_date
]
records = [log.to_audit_record() for log in filtered]
return json.dumps(records, ensure_ascii=False, indent=2)
# 记录审批日志
logger = AuditLogger()
log = logger.log_approval(
request_id="PR001",
user=trader,
action="APPROVE",
decision="通过",
reason="额度充足,价格在容忍度范围内"
)
print(json.dumps(log.to_audit_record(), ensure_ascii=False, indent=2))
总结
价格风险管理平台的审批角色配置需构建清晰的RBAC权限模型,结合动态审批流引擎实现条件路由,通过客商维度隔离保障数据安全,并以完整的审计日志满足合规要求。整套机制使点价业务在效率与风控之间取得平衡。如需了解更多点价业务的权限配置实践,可参考快期-点价宝的系统配置文档。