EKOK 业务流程全景图

从「销售卖一张机票」到「Commission 结清 + 供应商账单结清」
最后更新:2026-05-18 · 角色:Sales / Finance / Admin

整体流程图

① 销售出单 Sales · /bookings/new 3-Step ② 客户付款 Customer · /pay/:token 支付方式? 6 种 银行转账 其他 5 种 银行转账 → 上传截图 payment.status = pending 网关自动 confirmed WeChat / Alipay / UnionPay / CC ... ③ Sales Confirm Sales · 对照自家银行流水 ✓ Booking PAID commissionAmount 自动算 + audit_log Commission Lane Finance · 月底 Supplier Lane Finance · 按账单到达 ④ Commission Payable 勾单 → Create Payout (DRAFT) Bank Batch CSV 导出 → 网银批量代发 Mark Paid + 🔒 锁定 booking 财务字段不能改 ⑤ Supplier Statements Import + 逐行核对 + Approve Pay Supplier 实际付款给供应商 Bank Reconciliation 银行流水 ↔ 系统对账
Sales 销售
Customer 客户
分支判断
需人工 Confirm
自动 confirmed
关键合流节点
Commission lane (Finance)
Supplier lane (Finance)

1 销售出单 Sales

  1. 1.1
    客户来询价
    Amadeus外部系统
  2. 1.2
    出 PNR / 拿到票价
    Amadeus外部
  3. 1.3
    建 booking
    /bookings/new3-Step 向导,系统自动生成 EKOK No. (例 000017)
  4. 1.4
    Step 1 上传
    OCR Uploader 自动解析 PDF 行程单,或手工 Manual Form
  5. 1.5
    Step 2 Review
    检查乘客 / 航段 / 金额,字段校验
  6. 1.6
    Step 3 Collect Payment
    大 QR 显示 + 复制付款链接(链接自动到剪贴板)
完成后状态
bookings.payment_status = 'unpaid' · branch_id = 销售所属 · sales_id = 销售 user.id · commission_amount = 0(未付款不算提成)

2 客户付款 Customer

  1. 2.1
    客户收到付款链接
    微信 / 邮件
  2. 2.2
    点开公开付款页
    /pay/:token显示 branch 配置的方式(最多 6 种)
  3. 2.3
    选支付方式 + 付款
    见下方 6 种行为

6 种付款方式

需上传截图

Bank Transfer

手机网银手工转账 → 截图上传
pending 等 Sales Confirm
自动

WeChat Pay

扫 QR → 第三方回调
confirmed
自动

Alipay

扫 QR → 第三方回调
confirmed
自动

UnionPay

跳转网关
confirmed
自动

Credit Card

Stripe / 2C2P 流程
confirmed
自动

Online Banking

跳转网银
confirmed
关键差异
银行转账 = 真正的线下流程,商家没法主动知道钱到账 → 必须客户截图 + 人工 confirm。
其他方式 = 第三方网关已验证 → 直接 confirmed,跳过人工审核。

3 银行转账 Confirm Sales

业务规则
bank-transfer 的 Confirm 是销售员自己的活,不是财务。销售员持有自家门店的银行 App,对照流水核对客户上传的截图。
  1. 3.1
    看到自家这单 pending
    /paymentsbooking 详情 Payment Received tab自动 scope 到 sales_id
  2. 3.2
    对照自家门店银行流水
    自家网银 App,看钱有没有真的到账
  3. 3.3
    点 Confirm
    操作列 ✓ 按钮 → payment.status='confirmed'
  4. 3.4
    (金额对不上)Reject
    操作列 ✗ 按钮 → status='rejected' + 必填原因,客户能看到

权限

角色能 Confirm / Reject 谁的
Sales只能 confirm/reject 自己 booking 的 payment(service 层 BadRequestException 拦截跨人)
Finance / Admin任何 payment(Payment Audit 页保留作为兜底 / 跨员工审计路径)
Confirm 后系统自动
1. 累计所有 confirmed payments
2. 若 ≥ totalAmount → payment_status='paid'
3. 若 paid 且产品有 commission → commissionAmount = profit × rate(机票 50% / 旅游定额 / 保险按 product.commPercent)
4. 触发 audit log payment.confirm

4 月底结算 Commission Finance

4.1 创建 Payout

  1. 4.1.1
    看本月 Commission Payable
    /finance/commission-payable选时间范围 → Summary 看总额
  2. 4.1.2
    切到 Details 模式
    看每张单子明细
  3. 4.1.3
    勾选同一销售的行
    系统强制只能勾同一销售(disable 其他人的 checkbox)
  4. 4.1.4
    点 Create Payout
    顶部蓝色按钮 → 跳到 /finance/commission-payouts
生成的数据
commission_payouts 多一条 draft · commission_payout_items 关联多张 booking + 当时的 commissionAmount 快照(防止后续改单影响历史)

4.2 实际打款

  1. 4.2.1
    Export Bank Batch CSV (draft)
    一次性导出所有 draft 的 NZ Direct Credit 5 列 CSV
  2. 4.2.2
    上传到网银
    ANZ Direct / ASB FastNet 批量代发
  3. 4.2.3
    钱到账后逐条 Mark Paid
    弹窗填 reference + 时间
Mark Paid 后系统自动
1. commission_payouts.status='paid',记 paid_at / paid_by / reference
2. 关联的所有 booking 🔒 LOCKED
3. 改这些 booking 的 totalAmount / costAmount / commissionRate / commissionAmount / grossAmount / taxAmount → 400 Booking is locked
4. 触发 audit log payout.paid

4.3 Sales 拿到提成

5 供应商账单结算 Finance

5.1 收到账单 + 导入

  1. 5.1.1
    BSP / 航司发来周/月结清单
    邮件 / 网站下载
  2. 5.1.2
    进 Supplier Statements 页
    /finance/supplier-statements
  3. 5.1.3
    点 Import Statement
    选 supplier / 填 period / reference
  4. 5.1.4
    粘贴 raw text
    BSP 文本或 CSV
  5. 5.1.5
    提交
    系统按 ticket# 自动匹配 booking
5 种 line 状态
🟢 matched(金额一致)· 🟠 amount_diff(找到 booking 但金额不对)· 🔵 paid_in_full(已付过)· 🔴 no_booking / no_amount

5.2 逐行核对

  1. 5.2.1
    点行 View → Modal
    展开 lines 表
  2. 5.2.2
    matched 行 Confirm
    line.matchStatus → confirmed
  3. 5.2.3
    amount_diff / no_booking 处理
    Dispute + note → line.disputeStatus = pending
  4. 5.2.4
    dispute 谈妥 Resolve
    disputeStatus → resolved
  5. 5.2.5
    ADM / ACM 标记
    type Dropdown:ticket / ADM / ACM / fee / other
  6. 5.2.6
    全部处理完 → Approve
    statement.status → approved(pending dispute 阻塞)

5.3 Pay Supplier

  1. 5.3.1
    去 Pay Supplier
    /finance/pay-purchase选 supplier
  2. 5.3.2
    勾选要付的 booking
    自动列出 unsettled
  3. 5.3.3
    输金额 + method + reference
  4. 5.3.4
    提交
    生成 supplier_payment + supplier_payment_applications
  5. 5.3.5
    实际去网银付钱
    银行 App

5.4 Bank Reconciliation 对账

  1. 5.4.1
    收到银行流水 CSV
    网银导出
  2. 5.4.2
    上传到 Bank Reconciliation
    /finance/bank-recon
  3. 5.4.3
    系统自动匹配
    按金额 + 日期窗口
  4. 5.4.4
    红色不匹配行手动配对
    标记成「无对应订单」或配对到 payment

单张 EKOK 完整生命周期

[Sales 出单]
booking: { paymentStatus: 'unpaid', commissionAmount: 0 }

[客户银行转账上传截图]
+ payment: { status: 'pending', source: 'customer', method: 'bank_transfer' }

[Sales Confirm]
payment: { status: 'confirmed' }
booking: { paymentStatus: 'paid', commissionAmount: 150 }
audit_log: 'payment.confirm'

[客户 WeChat/Alipay 等付款](替代路径)
+ payment: { status: 'confirmed', source: 'customer', confirmedById: null }
booking: 同上

[财务 Create Payout]
commission_payout: { status: 'draft', total: 150 }
commission_payout_item: { booking_id: 16, amount: 150 }
audit_log: 'create'

[财务 Mark Paid]
commission_payout: { status: 'paid', paidAt: ..., reference: 'ANZ-001' }
booking: 🔒 financial fields locked
audit_log: 'payout.paid'

[供应商账单到]
supplier_statement_line: { booking_id: 16, match_status: 'matched' }
[Confirm + Approve]
supplier_statement: { status: 'approved' }

[Pay Supplier]
supplier_payment + supplier_payment_application: { booking_id: 16, amount: 1000 }

[Bank Recon]
✓ 系统已收 1300,已付 1000,提成 150,留存 150

业务红线(系统强制)

规则实现位置
销售只能看 / 改自己的 bookingbookings.findAll/findOne + salesId scope,findOne 403 拦截
销售只能 Confirm / Reject 自己 booking 的 paymentpayments.service.confirm/reject 内 userRole==='sales' 校验
销售只能删 Unpaid bookingbookings.controller.delete 校验
全款付清才算 commissionrecomputeBookingPaymentStatus 内置
Payout 已发后 booking 锁定BookingsService.update 检测 isLockedByPayout
Supplier Statement 有 pending dispute 不能 Approveapprove() 内置检查
Payout 一旦 PAID 不能取消cancel() 仅允许 DRAFT
同一 booking 只能进一个 paid payoutcommission_payout_items.booking_id UNIQUE
万国签证机票都是虚订Sales 自觉走 IEPJ → XI 流程,系统不强制

痛点 → 页面 速查表

痛点去哪谁
「我要催款」/follow-upSales
「客户银行转账要审」/payments · booking 详情Sales
「这单提成发了没」booking 详情 My Commission 卡
/finance/commission-payouts 搜 EKOK
Sales / Finance
「钱该催谁」/finance/ar-agingFinance
「钱到账了系统没记」/finance/bank-reconFinance
「这单赚多少 / 钱链路」/finance/payment-trace?bookingId=N
booking 详情顶部 Trace 按钮
Finance
「今天付哪个供应商」/finance/ap-aging → /finance/pay-purchaseFinance
「BSP 账单来了」/finance/supplier-statementsFinance
「月底发提成」/finance/commission-payable → /finance/commission-payoutsFinance
「老板要月报」/finance/reports · /finance/branch-plFinance
「税务季报」/finance/gstFinance
「客户/供应商对账争议」/finance/payment-traceFinance
「财务一天的入口」/finance/dashboard(finance 登录默认页)Finance

主要数据模型

表主要字段关系
bookingsekok_number / sales_id / branch_id / payment_status / commission_amount / total_amount / cost_amount→ customer / product / branch / payments
paymentsbooking_id / amount / status (pending / confirmed / rejected) / source (customer/sales) / payment_method / confirmed_by→ booking
commission_payoutssales_id / status (draft / paid / cancelled) / total_amount / paid_at / reference→ items
commission_payout_itemspayout_id / booking_id UNIQUE / amount→ booking
supplier_statementssupplier_id / period / status (reconciling / approved / paid / disputed / closed) / total_amount→ lines
supplier_statement_linesstatement_id / ticket_no / amount / type (ticket/ADM/ACM/fee) / match_status / dispute_status→ booking
supplier_payments + supplier_payment_applications一付多核销关联表→ booking
audit_logsentity_type / entity_id / action / field / old_value / new_value / user_id—
branchesname / code / bankName / accountName / accountNumber / bankSwift / wechatQrUrl / alipayQrUrl / 等→ bookings / users
ai_usageprovider / model / purpose / tokens / cost_usd / cache hits—

未做(待用户提)