第三方支付-手续费系统设计与实现
1、手續費中的概念
1.1 手續費的定義
????????根據百度百科的定義,“手續費:辦事過程中所產生的費用”,“手續費”可以這樣解釋:為代理他人辦理有關事項所收取的一種勞務補償;或對委托人來講,是屬于因他人代為辦理有關事項,而支付的相應報酬。如:證券交易手續費、代辦機票手續費、代扣代繳費用手續費、國債代辦手續費等等。
? ? ? ? 根據以上的概念可以得知,在支付系統中,手續費是支付平臺向在進行資金轉移的過程中,支付系統的使用方向支付平臺支付的“報酬”,也可以稱為服務費。
1.2 手續費賬戶
? ? ? ? 支付系統的用戶或者商戶將支付的手續費最終支付的賬戶,稱為手續費收益賬戶。
2、手續費的業務模型設計
2.1 收款手續費
收款過程中收取的手續費,資金流的方向是商戶賬戶到手續費賬戶。收款是從銀行卡充值到支付系統中。
2.2?付款手續費
付款是將錢從支付系統的賬戶中體現到銀行卡的過程。手續費的資金流是從商戶賬戶到手續費賬戶。
2.3 交易買賣方手續費
一筆交易是從商戶a到商戶b的支付賬戶中。這筆交易過程可能對商戶a買方和商戶b買方收取手續費。手續費的資金流是商戶a到手續費賬戶,商戶b到手續費賬戶。
3、以交易為例手續費資金流說明
????????本例中買方和賣方都需要支付交易的手續費。商戶a支付100元給商戶b,需要賣方商戶a支付2元手續費,則商戶a共支付102元,商戶b支付3元交易手續費,則商戶b共收到97元。
?偽代碼如下:
/** 創建交易 */public abstract Response createTransaction(Request request);/** 支付交易 */public abstract Response payTransaction(Request request);/** 確認交易 */public abstract Response confirmTransaction(Request request);????????注意手續費金額單位可以是元也可以是分,為了保證減少小數計算對計算準確度的干擾,推薦使用單位分來作為單位。數據庫中amount的單位是分。存儲100分,記為1元。Java中金額計算必須要用Bigdecimal 類型,但是如果保證系統中不出現小數,可以使用long來表示金額。
4、手續費的四種計算方式
4.1 按單筆固定金額收取費用
單筆固定金額收費,無論交易金額的大小,比如設置每一筆交易的收費為5毛,那么不管交易額為10元,還是100元,收費均為5毛。
4.2?按比例收取費用
按比例收取費用代表每一筆交易固定比例手續費,比如每筆交易收取5%的手續費,100元則收取5元。
4.3?按固定周期收取費用
按固定周期收取費用,比如按年收費,按月收費,按日收費等;比如按年交易額為1000元,固定收取一次手續費1000元。
4.4 按組合收取費用
按組合收取手續費,比如設置1000元以下的交易額時,按5毛一筆收費,大于1000元時,按百分比收費。
5、手續費相關的數據庫設計
????????一筆交易的手續費涉及買賣雙方的手續費,我們將手續費信息存儲在交易表中。交易表中的手續費信息設計的字段如下:
| 字段名稱 | 類型 | 說明 |
| id | varchar | 主鍵 |
| fee_buy_amount | bigint | 買方手續費 |
| fee_buy_user_id | bigint | 買方手續費賬戶 |
| fee_buy_account_type | smallint | 買方手續費賬戶類型 |
| fee_sell_amount | bigint | 賣方手續費 |
| fee_sell_user_id | bigint | 賣方手續費賬戶 |
| fee_sell_account_type | smallint | 賣方手續費賬戶類型 |
6、手續費記賬代碼實現
/**創建交易時將手續費計算出來*/@Overridepublic Response createTransaction(Request request) {//買方賬戶String buyUserId = request.getUserId();//交易類型:到卡、到賬戶Integer feeType = request.getFeeType();//對公、對私Integer payType = request.getPayType();//交易金額Long amount = request.getAmount();//交易的單號String transactionId = request.getTransactionId();//獲取交易手續費信息FeeInfo payFeeInfo = feeService.getPayFeeInfo(buyUserId, feeType, payType, amount, transactionId);if(!payFeeInfo.getErrno().equals(SUCCESS)){return new Response(ERR_UNKNOWN);}//創建交易單Response trans = payTransService.createTrans(payFeeInfo);if(!trans.getErrno().equals(SUCCESS)){return new Response(ERR_UNKNOWN);}//支付交易單Response payTrans = payTransService.payTrans(payFeeInfo);if(!trans.getErrno().equals(SUCCESS)){return new Response(ERR_UNKNOWN);}return new Response(SUCCESS);}實現注意的地方:
1) 調用第三方服務超時可以重試,通過框架實現重試(基于guava-retrying實現或者spring-retry),也可以通過業務實現重試,將調用接口通過消息隊列實現,只有獲取明確的結果報文才停止調用。
2)保證單號的唯一:同一單號在上下游的系統里保證唯一,可以加交易單號設置成唯一索引或者一個中間映射表的主鍵。
3) 保證服務的冪等性:如果下游沒有落單,并發請求可能拿到不同的影響結果,不能保證接口的冪等性。比如交易賬戶被凍結,并發兩筆請求,第一次請求結果返回交易成功,第二次請求返回賬戶被凍結,剛好覆蓋第一次的請求結果。可以通過分布式鎖保證交易結果并發情況下拿到唯一的結果。
4)涉及到多張表的修改:同一數據庫開啟本地事務即可,分布式數據庫開啟分布式事務,比如TCC。
總結
以上是生活随笔為你收集整理的第三方支付-手续费系统设计与实现的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 不同page页面选择不同页面模板的方法
- 下一篇: java信息管理系统总结_java实现科