价格风险管理平台审批角色配置与权限矩阵设计

在大宗商品贸易企业的点价业务中,审批流程的合理设计直接影响交易效率与风控合规。客户自助点价、额度校验、容忍度审批、夜盘自动处理等场景,均需要精细化的角色权限配置。本文从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权限模型,结合动态审批流引擎实现条件路由,通过客商维度隔离保障数据安全,并以完整的审计日志满足合规要求。整套机制使点价业务在效率与风控之间取得平衡。如需了解更多点价业务的权限配置实践,可参考快期-点价宝的系统配置文档。

相关推荐
麦聪聊数据1 小时前
后端不再是瓶颈:如何通过“API 编排协作”重塑数据交付流程?
数据库·sql·mysql
莫叫石榴姐1 小时前
用SQL实现三次指数平滑预测:递归与非递归两种解法详解
大数据·数据库·sql
步步为营DotNet1 小时前
深度剖析.NET 中CancellationToken:精准控制异步操作的关键
java·前端·.net
thinkQuadratic1 小时前
CSS给文本添加背景颜色等效果
前端·css
ONLYOFFICE1 小时前
ONLYOFFICE 桌面编辑器现已推出 Linux ARM 版本
linux·运维·arm开发
guygg881 小时前
MATLAB利用CVX求解半定规划(SDP)波束成形矩阵的设计与实现
开发语言·matlab·矩阵
Ydwlcloud1 小时前
面向全球用户的网站,AWS是唯一选择吗?
大数据·服务器·人工智能·云计算·aws
以太浮标1 小时前
华为eNSP模拟器综合实验之- 端口安全MAC地址表
网络
波波鱼દ ᵕ̈ ૩1 小时前
AJAX(1)
前端·javascript·ajax