前言
在涉及關於金錢的業務系統時,一定要注意資料安全。通常可以把財務相關的資料庫,獨立於其他的業務系統資料庫。從表的設計角度來看。應該紀錄每一步資金的流向,方便資料追蹤下面來開始設計資料表。
1,表設計
這裡主要用到的表有。使用者錢包表,流水紀錄表,充值訂單表,支付紀錄表,提現表。
DROP TABLE IF EXISTS `user_wallet`;
CREATE TABLE `user_wallet` (
`user_uuid` char(32) NOT NULL COMMENT '使用者user_uuid',
`wallet_income` decimal(10,2) unsigned DEFAULT '0.00' COMMENT '錢包總收入額',
`wallet_outcome` decimal(10,2) unsigned DEFAULT '0.00' COMMENT '錢包總支出額',
`balance_fee` decimal(10,2) unsigned DEFAULT '0.00' COMMENT '錢包總可用餘額',
`check_sign` varchar(100) DEFAULT '' COMMENT '用於安全檢查,檢查不通過為異常。',
`update_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新時間',
PRIMARY KEY (`user_uuid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='使用者錢包';
上面的錢包表中,check_sign欄位,是有效保證資料安全,不被輕易篡改的方法。sign欄位的值是當前一條紀錄的資料加密計算值。在每次對這張表進行操作時。都要進行check_sign欄位簽名驗證。通過則繼續。不通過,則可以根據具體情況採取措施。比如傳送通知到相關人員。
DROP TABLE IF EXISTS `user_wallet_log`;
CREATE TABLE `user_wallet_log` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT 'auto id',
`user_uuid` char(32) DEFAULT '' COMMENT '用uuid',
`number` varchar(32) NOT NULL DEFAULT '' COMMENT '流水號',
`target_type` smallint(5) unsigned DEFAULT '0' COMMENT '業務型別,1:充值,2:提現 3:下單',
`target_uuid` char(32) DEFAULT '' COMMENT '來源uuid(如提現uuid)',
`action_type` smallint(5) unsigned DEFAULT '0' COMMENT '操作型別,1:充值,2:提現,3:訂單',
`fee` decimal(10,2) DEFAULT '0.00' COMMENT '變動的金額,正負數。',
`original_account_json` varchar(1000) DEFAULT '賬戶變更前的資料 json儲存',
`dispose_account_json` varchar(1000) DEFAULT '賬戶變更後的資料 json儲存',
`status` smallint(5) unsigned DEFAULT '0' COMMENT '處理狀態1,處理完成,0未完成',
`resultType` smallint(5) unsigned DEFAULT '0' COMMENT '處理結果,0:沒有變更,1:有變更。',
`create_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '建立時間',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='使用者錢包流水記錄表';
流水紀錄表中的original_account_json和dispose_account_json欄位,可以用來排查賬戶異常,方便梳理對帳。
DROP TABLE IF EXISTS `user_top_up_order`;
CREATE TABLE `user_top_up_order` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT 'auto id',
`user_uuid` char(32) NOT NULL DEFAULT '' COMMENT '使用者ID',
`order_num` char(32) NOT NULL COMMENT '訂單號',
`amounts` decimal(10,2) NOT NULL DEFAULT '0.00' COMMENT '訂單總金額',
`currency` varchar(8) NOT NULL DEFAULT 'CNY' COMMENT '貨幣型別',
`pay_fee` decimal(10,2) NOT NULL DEFAULT '0.00' COMMENT '實際支付金額',
`exchange` decimal(10,4) NOT NULL DEFAULT '0.00' COMMENT '匯率',
`status` tinyint(5) NOT NULL DEFAULT '0' COMMENT '支付狀態:0待支付,1已支付,100已取消',
`update_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新時間',
`create_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '建立時間',
`deleted` tinyint(5) NOT NULL DEFAULT '0' COMMENT '0未刪除1已刪除',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='充值訂單';
充值訂單沒什麼好說的
DROP TABLE IF EXISTS `user_withdraw_cash_list`;
CREATE TABLE `user_withdraw_cash_list` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT 'auto id',
`user_uuid` varchar(32) NOT NULL COMMENT '申請使用者uuid',
`withdraw_way` tinyint(1) NOT NULL DEFAULT '1' COMMENT '提現(渠道)方式 1銀行轉賬',
`withdraw_status` smallint(5) unsigned DEFAULT '0' COMMENT '處理狀態。 1發起申請(待稽核理)前臺顯示處理中,2提現成功,3稽核不通過',
`number` char(32) DEFAULT '' COMMENT '提現單號',
`receivable_account` varchar(32) DEFAULT '' COMMENT '收款賬戶',
`name` varchar(30) DEFAULT '' COMMENT '收款人姓名',
`address` varchar(100) DEFAULT '' COMMENT '開戶行地址',
`withdraw_fee` decimal(10,2) DEFAULT '0.00' COMMENT '提現金額',
`content` varchar(500) DEFAULT '' COMMENT '稽核不通過原因',
`verify_user` varchar(32) DEFAULT '' COMMENT '稽核人',
`action_user` varchar(32) DEFAULT '' COMMENT '操作人',
`action_at` datetime DEFAULT NULL COMMENT '稽核時間',
`sent_notice_at` datetime DEFAULT NULL COMMENT '傳送通知時間',
`create_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '建立時間',
`update_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新時間',
`deleted` tinyint(1) NOT NULL DEFAULT '0' COMMENT '是否刪除:0未刪除,1已刪除',
PRIMARY KEY (`uuid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='提現記錄表';
一般來說,有充值,就有提現。很多業務系統中沒有充值,也會有提現場景。最後一張就是支付紀錄表了。
DROP TABLE IF EXISTS `payment_list`;
CREATE TABLE `payment_list` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT 'auto id',
`user_uuid` varchar(32) NOT NULL DEFAULT '' COMMENT '使用者uuid',
`pay_num` bigint(20) unsigned DEFAULT '0' COMMENT '支付號',
`trade_no` varchar(64) COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '第三方付款成功交易號',
`order_type` smallint(5) unsigned DEFAULT '0' COMMENT '訂單型別 1充值 ',
`order_uuid` char(32) DEFAULT '' COMMENT '充值訂單表uuid',
`pay_way` smallint(5) unsigned DEFAULT '0' COMMENT '付款方式 1微信 2支付寶 ',
`pay_status` smallint(5) unsigned DEFAULT '0' COMMENT '支付狀態 1 支付成功,2 支付失敗 ',
`step` smallint(5) unsigned DEFAULT '0' COMMENT '步驟 1 建立支付,2 支付回撥通知',
`post_status` smallint(5) unsigned DEFAULT '0' COMMENT '請求支付狀態,1:成功,2:失敗',
`return_status` smallint(5) unsigned DEFAULT '0' COMMENT '回撥狀態,1:成功,2:失敗',
`total_fee` decimal(10,2) unsigned DEFAULT '0.00' COMMENT '支付價格',
`result_code` varchar(30) DEFAULT '' COMMENT '第三方返回錯誤碼',
`err_code_str` varchar(255) DEFAULT '' COMMENT '第三方返回的錯誤記錄',
`currency` varchar(8) NOT NULL DEFAULT 'HKD' COMMENT '貨幣型別',
`ip2long` int(10) unsigned DEFAULT '0' COMMENT 'ip2long',
`post_json` varchar(2000) DEFAULT '' COMMENT '提交post json 資料',
`return_json` varchar(2000) DEFAULT '' COMMENT '回撥post return data json',
`create_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '建立時間',
`update_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新時間',
`success_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '支付成功時間',
`procedure_kb mediumint(8) unsigned DEFAULT '0' COMMENT '手續費比例,千位比。6/1000',
`procedure_fee` decimal(10,2) unsigned DEFAULT '0.00' COMMENT '支付渠道收取手續費金額',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='支付記錄列表';
以上,使用者錢包功能所需表就設計好了。之前一篇提到的支付紀錄表也面世了。因為很多公司並沒有這張表,或者說只有一張簡單的表紀錄第三方交易單號的資訊和訂單資訊。而且後臺管理系統沒有頁面展示。導致客服運營等人員,經常反饋支付失敗的問題。很多時候只是網路延時導致訂單回撥不及時,而沒有修改訂單狀態。而我們開發則不得不停下手中的活,去排查相關的問題。
2 簡要流程
這裡就不畫流程圖和時序圖了。簡單說下步驟
1.何時建立使用者錢包紀錄?。新使用者在註冊時可建立。老使用者寫指令碼建立。
2.建立使用者錢包紀錄根據用的錢包紀錄資訊生產一個sign。並同時建立一條流水紀錄。
3.操作錢包表時,要先獲取一條紀錄。生產一個sign值,然後根據紀錄的sign值進行對比。相同則繼續走正常的步驟。不同時,則應該終止後續操作,併發通知給相關人員進行排查異常。
4.重新生成sign值,並正常更新資料,紀錄流水紀錄。
5.支付紀錄表,應該是每發起一次支付,就要生成一條支付紀錄。同一個訂單對應多個支付紀錄。
3,check_sign欄位生成
public function updateSign($walletInfo)
{
unset($walletInfo['check_sign']);
unset($walletInfo['update_at']);
$walletCheckKey = config('bill.walletCheckKey');
$checkSign = $this->encode_HMAC($walletInfo, $walletCheckKey);
$update['check_sign'] = $checkSign;
$this->walletRepository->saveTransaction($walletInfo['id'], $update);
}
public function walletSignCheck($walletInfo)
{
$walletCheckKey = config('bill.walletCheckKey');
$check = false;
$checkSignDB = $walletInfo['check_sign'];
unset($walletInfo['check_sign']);
unset($walletInfo['update_at']);
$checkSign = $this->encode_HMAC($walletInfo, $walletCheckKey);
if ($checkSignDB == $checkSign) {
$check = true;
}
return $check;
}
protected function encode_HMAC($data, $walletCheckKey)
{
if (empty($data) || !is_array($data)) {
_writeBizException(json_encode([$data]), __FUNCTION__, class_basename(__CLASS__));
}
ksort($data);
$str = "";
foreach ($data as $k => $v) {
$str = $str . "&" . $k . "=" . $v;
}
$str = trim($str, "&");
$str = $str . "&key=" . $walletCheckKey;
$re = strtoupper(hash_hmac("sha256", $str, $walletCheckKey));
return $re;
}
本作品採用《CC 協議》,轉載必須註明作者和本文連結