pos_order_omg_attempt采用追加式支付尝试表。创建时保存订单、商户和凭证快照;付款结果回调在同一行追加网关最终事实,不覆盖历史尝试。
| Column | Type | Null | Meaning |
|---|---|---|---|
id |
BIGINT |
No | 自增主键 |
dd_id |
VARCHAR(64) |
No | pos_order.dd_id |
merchant_trade_no |
VARCHAR(20) ASCII binary |
No | OMG MerchantTradeNo,全局唯一 |
store_id |
BIGINT |
No | 创建时订单门店快照 |
merchant_id |
VARCHAR(10) ASCII binary |
No | 创建时门店 MerchantID 快照 |
amount |
INT |
No | 创建时整数 TWD 金额快照 |
hash_key_snapshot |
VARCHAR(64) |
No | 创建时 HashKey 快照,仅用于该尝试验签 |
hash_iv_snapshot |
VARCHAR(64) |
No | 创建时 HashIV 快照,仅用于该尝试验签 |
attempt_status |
TINYINT |
No | 0=CREATED, 1=PAID, 2=FAILED, 3=SUPERSEDED |
active_dd_id |
VARCHAR(64) generated |
Yes | status=0 时等于 dd_id,否则 NULL |
trade_no |
VARCHAR(20) ASCII binary |
Yes | OMG 金流交易编号,非空时全局唯一 |
rtn_code |
INT |
Yes | OMG 原始交易状态码 |
rtn_msg |
VARCHAR(200) |
Yes | OMG 原始交易说明 |
payment_type |
VARCHAR(20) ASCII |
Yes | OMG 回覆付款方式 |
payment_date |
DATETIME |
Yes | OMG 付款时间 |
trade_date |
DATETIME |
Yes | OMG 订单成立时间 |
payment_type_charge_fee |
INT |
Yes | OMG 回传手续费 |
simulate_paid |
TINYINT |
Yes | 0=一般付款, 1=模拟付款 |
last_notify_time |
DATETIME |
Yes | 最近一次合法通知处理时间 |
create_time |
DATETIME |
No | 本地创建时间 |
update_time |
DATETIME |
No | 本地更新时间 |
updatesql/sql.md-- 保存创建事实、凭证快照与最终付款结果;不保存完整创建表单。
-- 本 SQL 只登记,由开发者手动执行;实现过程禁止直接执行 DDL。
CREATE TABLE pos_order_omg_attempt (
id BIGINT NOT NULL AUTO_INCREMENT COMMENT '本地支付尝试主键',
dd_id VARCHAR(64) NOT NULL COMMENT '关联 pos_order.dd_id',
merchant_trade_no VARCHAR(20) CHARACTER SET ascii COLLATE ascii_bin NOT NULL COMMENT 'OMG MerchantTradeNo',
store_id BIGINT NOT NULL COMMENT '创建时订单门店快照',
merchant_id VARCHAR(10) CHARACTER SET ascii COLLATE ascii_bin NOT NULL COMMENT '创建时 OMG MerchantID 快照',
amount INT NOT NULL COMMENT '创建时整数 TWD 金额快照',
hash_key_snapshot VARCHAR(64) NOT NULL COMMENT '创建时 HashKey 快照',
hash_iv_snapshot VARCHAR(64) NOT NULL COMMENT '创建时 HashIV 快照',
attempt_status TINYINT NOT NULL DEFAULT 0 COMMENT '本地状态:0=CREATED,1=PAID,2=FAILED,3=SUPERSEDED',
active_dd_id VARCHAR(64)
GENERATED ALWAYS AS (IF(attempt_status = 0, dd_id, NULL)) VIRTUAL
COMMENT '单订单单活跃尝试唯一键载体',
trade_no VARCHAR(20) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL COMMENT 'OMG 金流交易编号',
rtn_code INT DEFAULT NULL COMMENT 'OMG 原始结果码',
rtn_msg VARCHAR(200) DEFAULT NULL COMMENT 'OMG 原始结果说明',
payment_type VARCHAR(20) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL COMMENT 'OMG 回覆付款方式',
payment_date DATETIME DEFAULT NULL COMMENT 'OMG 付款时间',
trade_date DATETIME DEFAULT NULL COMMENT 'OMG 订单成立时间',
payment_type_charge_fee INT DEFAULT NULL COMMENT 'OMG 回传手续费',
simulate_paid TINYINT DEFAULT NULL COMMENT '0一般付款,1模拟付款',
last_notify_time DATETIME DEFAULT NULL COMMENT '最近合法通知处理时间',
create_time DATETIME NOT NULL COMMENT '创建时间',
update_time DATETIME NOT NULL COMMENT '更新时间',
PRIMARY KEY (id),
UNIQUE KEY uk_omg_attempt_trade_no (merchant_trade_no),
UNIQUE KEY uk_omg_attempt_gateway_trade_no (trade_no),
UNIQUE KEY uk_omg_attempt_active_dd (active_dd_id),
KEY idx_omg_attempt_dd_time (dd_id, create_time, id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='OMG AIO 新支付创建尝试';
merchant_trade_no 只含大写 ASCII 英数字且长度不超过 20。amount > 0、store_id 和 merchant_id 均在插入前校验。attempt_status=0 的行通过生成列唯一索引保证每个 dd_id 最多一条。PAID 不可降级;FAILED 可被后续合法成功通知升级为 PAID。ipn_log;完整回调内容只来自 HTTP 请求本身,不拼入数据库密钥。OmgPaymentAttemptpublic class OmgPaymentAttempt {
private Long id;
private String ddId;
private String merchantTradeNo;
private Long storeId;
private String merchantId;
private Integer amount;
private String hashKeySnapshot;
private String hashIvSnapshot;
private Integer attemptStatus;
private String activeDdId;
private String tradeNo;
private Integer rtnCode;
private String rtnMsg;
private String paymentType;
private Date paymentDate;
private Date tradeDate;
private BigDecimal paymentTypeChargeFee;
private Integer simulatePaid;
private Date lastNotifyTime;
private Date createTime;
private Date updateTime;
}
OmgPaymentOrderSnapshot只承载锁定订单时创建支付所需字段,不暴露到 Controller:
public class OmgPaymentOrderSnapshot {
private Long id;
private String ddId;
private String parentDdId;
private Long storeId;
private Long userId;
private Integer amount;
private Long state;
private Long payStatus;
private String payType;
}
OmgPaymentOrderSnapshot selectOrderForUpdate(String ddId);
OmgPaymentAttempt selectActiveByDdId(String ddId);
OmgPaymentAttempt selectByMerchantTradeNoForUpdate(String merchantTradeNo);
int insertCreated(OmgPaymentAttempt attempt);
int markPaid(OmgPaymentAttempt attempt);
int markFailed(OmgPaymentAttempt attempt);
int supersedeOtherCreated(String ddId, Long paidAttemptId);
int markOrderPaid(String ddId);
selectOrderForUpdate 与 selectByMerchantTradeNoForUpdate 必须在事务中使用 SELECT ... FOR UPDATE。insertCreated 必须显式列出插入列并排除生成列 active_dd_id。状态更新必须带当前状态条件,保证 PAID 不可降级。
ipn_log不新增字段。每个 HTTP 回调独立新增一行:
| Column | Value |
|---|---|
ip |
请求来源 IP |
cretim |
本地接收时间 |
ipn_log |
完整原始 form-urlencoded 请求体 |
type |
固定 omg |