public interface AccountDao extends JpaRepository<TAccount, String> {
@Lock(LockModeType.PESSIMISTIC_WRITE)
- //@Query("select a from taccount a where a.accno = ?1")
- TAccount getByAccno(String accno);
+ @Query("select a from TAccount a where a.accno = ?1")
+ TAccount getByAccnoForUpdate(String accno);
+
TAccount findByUserid(String userid);
}
"where b.status='success' and b.accdate=:settledate " +
"group by a.drsubjno,a.draccno,a.crsubjno,a.craccno,a.summary ", nativeQuery = true)
List<VoucherTemp> getVoucherData(@RequestParam("settledate") String settledate);
+
+
+ List<TDebitCreditDtl> findByRefno(String refno);
}
package com.supwisdom.dlpay.consume.domain;
+import com.supwisdom.dlpay.framework.util.MD5;
+import com.supwisdom.dlpay.framework.util.MoneyUtil;
import org.hibernate.annotations.GenericGenerator;
import javax.persistence.*;
public void setClosedate(String closedate) {
this.closedate = closedate;
}
+
+ public String generateTac(){
+ String data = this.accno+ MoneyUtil.YuanToFen(this.availbal)+MoneyUtil.YuanToFen(this.balance)+MoneyUtil.YuanToFen(this.frozebal);
+ return MD5.generatePassword(data, this.accno);
+ }
+
+ public boolean tacCheck(){
+ String tac_c = generateTac();
+ if (tac_c.equalsIgnoreCase(this.tac)||this.tac==null) {
+ return true;
+ }
+ return false;
+ }
+
+ public void addAmount(double amount) {
+ this.balance = this.balance + amount;
+ this.availbal = this.availbal + amount;
+ this.tac = this.generateTac();
+ }
+
+ public boolean checkOverflow(){
+ if(null!=this.maxbal && this.maxbal>0){
+ if(MoneyUtil.moneyCompare(this.balance,this.maxbal)>0){
+ return true; //超出账户最大值
+ }
+ }
+ return false;
+ }
+
+ public boolean checkOverdraft() {
+ if (MoneyUtil.moneyCompare(this.balance, 0) < 0) {
+ return true; //欠费透支
+ }
+ return false;
+ }
+
+ public boolean checkOverdraft(double limit) {
+ if (MoneyUtil.moneyCompare(this.balance, limit) < 0) {
+ return true; //余额低于某阀值
+ }
+ return false;
+ }
}
public TPerson() {
}
- public TPerson(String userid, String name, String sex, String idtype, String idno, String country, String nation,
- String email, String tel, String mobile, String addr, String zipcode, String lastsaved,
- String thirdUniqueIdenty) {
- this.userid = userid;
+ public TPerson(String name, String sex, String status, String idtype, String idno, String country, String nation, String email, String tel, String mobile, String addr, String zipcode, String lastsaved, String thirdUniqueIdenty) {
this.name = name;
this.sex = sex;
this.status = status;
--- /dev/null
+package com.supwisdom.dlpay.framework.util;
+
+import java.security.MessageDigest;
+
+public class MD5 {
+ //十六进制下数字到字符的映射数组
+ private final static String[] hexDigits = {"0", "1", "2", "3", "4",
+ "5", "6", "7", "8", "9", "a", "b", "c", "d", "e", "f"};
+
+ /** * 把inputString加密 */
+ public static String generatePassword(String data, String salt){
+ String enyptString = data+"{"+salt+"}";
+ return encodeByMD5(enyptString);
+ }
+
+ /**
+ * 验证输入的密码是否正确
+ * @param password 加密后的密码
+ * @param inputString 输入的字符串
+ * @return 验证结果,TRUE:正确 FALSE:错误
+ */
+ public static boolean validatePassword(String password, String inputString){
+ if(password.equals(encodeByMD5(inputString))){
+ return true;
+ } else{
+ return false;
+ }
+ }
+ /** 对字符串进行MD5加密 */
+ public static String encodeByMD5(String originString){
+ if (originString != null){
+ try{
+ //创建具有指定算法名称的信息摘要
+ MessageDigest md = MessageDigest.getInstance("MD5");
+ //使用指定的字节数组对摘要进行最后更新,然后完成摘要计算
+ byte[] results = md.digest(originString.getBytes("UTF-8"));
+ //将得到的字节数组变成字符串返回
+ String resultString = byteArrayToHexString(results);
+ return resultString.toUpperCase();
+ } catch(Exception ex){
+ ex.printStackTrace();
+ }
+ }
+ return null;
+ }
+
+ /**
+ * 转换字节数组为十六进制字符串
+ * @param 字节数组
+ * @return 十六进制字符串
+ */
+ private static String byteArrayToHexString(byte[] b){
+ StringBuffer resultSb = new StringBuffer();
+ for (int i = 0; i < b.length; i++){
+ resultSb.append(byteToHexString(b[i]));
+ }
+ return resultSb.toString();
+ }
+
+ /** 将一个字节转化成十六进制形式的字符串 */
+ private static String byteToHexString(byte b){
+ int n = b;
+ if (n < 0)
+ n = 256 + n;
+ int d1 = n / 16;
+ int d2 = n % 16;
+ return hexDigits[d1] + hexDigits[d2];
+ }
+
+}
* */
public static final int SUBJECT_NOT_EXISTS = 10008;
+ /**
+ * 外部流水号重复
+ * */
+ public static final int OUTTRADENO_ALREADY_EXISTS = 10009;
+
+ /**
+ * 账户TAC校验异常
+ * */
+ public static final int ACCOUNT_TAC_ERROR = 10010;
+
+ /**
+ * 账户余额超上限
+ * */
+ public static final int OVERFLOW_BALANCE_ERROR = 10011;
+
+ /**
+ * 未指定明确的交易结束状态
+ * */
+ public static final int TRANSDTL_STATUS_ERROR = 10012;
+
+ /**
+ * 非初始化流水
+ * */
+ public static final int TRANSDTL_STATUS_NOT_INIT = 10013;
}
\r
public class MoneyUtil {\r
\r
- public static int YuanToFen(double yuan) {\r
- return (int) (Math.round(yuan * 100));\r
- }\r
-\r
- public static boolean moneyCompare(double x1, double x2) {\r
- return YuanToFen(x1) == YuanToFen(x2);\r
- }\r
- public static double formatYuan(double yuan) {\r
- DecimalFormat df = new DecimalFormat("##0.00");\r
- double money = ((double) YuanToFen(yuan)) / 100;\r
- return Double.valueOf(df.format(money));\r
- }\r
-\r
- public static double FenToYuan(int fen) {\r
- return formatYuan(fen / 100.0);\r
- }\r
- public static String format(double num,String format) {\r
- DecimalFormat df = new DecimalFormat(format);\r
- return df.format(num);\r
- }\r
+ public static int YuanToFen(double yuan) {\r
+ return (int) (Math.round(yuan * 100));\r
+ }\r
+\r
+ public static boolean moneyCompare(double x1, double x2) {\r
+ return YuanToFen(x1) == YuanToFen(x2);\r
+ }\r
+\r
+ public static double formatYuan(double yuan) {\r
+ DecimalFormat df = new DecimalFormat("##0.00");\r
+ double money = ((double) YuanToFen(yuan)) / 100;\r
+ return Double.valueOf(df.format(money));\r
+ }\r
+\r
+ public static double FenToYuan(int fen) {\r
+ return formatYuan(fen / 100.0);\r
+ }\r
+\r
+ public static String format(double num, String format) {\r
+ DecimalFormat df = new DecimalFormat(format);\r
+ return df.format(num);\r
+ }\r
}\r
import com.supwisdom.dlpay.framework.domain.TShopacc
import com.supwisdom.dlpay.framework.domain.TSubject
import com.supwisdom.dlpay.framework.domain.TTranstype
-import com.supwisdom.dlpay.framework.util.TradeDict
-import com.supwisdom.dlpay.framework.util.TradeErrorCode
-import com.supwisdom.dlpay.framework.util.Tradetype
-import org.springframework.beans.factory.annotation.Autowired
+import com.supwisdom.dlpay.framework.util.*
class AccountHolder<T> private constructor(val accountId: String, val idType: Int) {
companion object {
lateinit var person: TPerson
lateinit var tradetype:Tradetype
+ var transcode = 0
+
var transDate = ""
var transTime = ""
/**
var overdraft = false
var description = ""
-
// 内部参数,不需要调用者处理
val details = mutableListOf<TransDetail>()
var amount: Double = 0.0
var accountUtil = accUitl
+
/**
* 支付方式
* */
- var paytype = ""
+ var paytype = "" //枚举?
var payinfo = ""
/**
* 外部流水号
* */
- var outtradeno = ""
+ var outtradeno = "" //发起支付系统的流水号(对接系统根据此流水号查询本地流水对账)
+
fun setOwner(per: TPerson): PersonTransBuilder {
this.person = per
return this
}
+ fun setTransinfo(transcode: Int, description: String): PersonTransBuilder {
+ this.transcode = transcode
+ this.description = description
+ return this
+ }
+
fun selectPaytype(paytype: String, payinfo: String): PersonTransBuilder {
this.paytype = paytype
this.payinfo = payinfo
return this
}
- fun chooseTradetype(tradetype: Tradetype) {
+ fun chooseTradetype(tradetype: Tradetype): PersonTransBuilder {
this.tradetype = tradetype
+ return this
+ }
+
+ fun setTradeno(outtradeno: String): PersonTransBuilder {
+ this.outtradeno = outtradeno
+ return this
}
private fun prepareData() {
- if (null == this.person) {
- throw TransactionCheckException(TradeErrorCode.INPUT_DATA_ERROR, "未指定交易用户")
+ if (null == this.tradetype) {
+ throw TransactionCheckException(TradeErrorCode.INPUT_DATA_ERROR, "未指定交易类型")
+ }
+ if(transcode==0){
+ throw TransactionCheckException(TradeErrorCode.INPUT_DATA_ERROR, "未指定交易码")
+ }
+
+ when(this.tradetype){
+ //充值必须指明用户和支付方式
+ Tradetype.RECHARGE -> {
+ if (null == this.person)
+ throw TransactionCheckException(TradeErrorCode.INPUT_DATA_ERROR, "未指定充值账户")
+
+ if (StringUtil.isEmpty(this.paytype))
+ throw TransactionCheckException(TradeErrorCode.INPUT_DATA_ERROR, "未指定充值方式")
+ }
+
+ //消费
+ Tradetype.CONSUME ->{
+ if (StringUtil.isEmpty(this.paytype))
+ this.paytype = TradeDict.PAYTYPE_BALANCE //默认余额支付
+ }
}
amount = 0.0
- if(this.details.size<1){
+ if (this.details.size < 1) {
throw TransactionCheckException(TradeErrorCode.INPUT_DATA_ERROR, "未指定交易明细")
}
+ if (null != this.person) {
+ var buyer = accountUtil.readAccount(person.userid) //判断是一个人的流水
+ for (detail in details) {
+ if (detail.debitSubjNo.equals(buyer.subjno) && !detail.debitAccNo.equals(buyer.accno))
+ throw throw TransactionCheckException(TradeErrorCode.INPUT_DATA_ERROR, "交易明细用户错误")
+
+ if (detail.creditSubjNo.equals(buyer.subjno) && !detail.creditAccNo.equals(buyer.accno))
+ throw throw TransactionCheckException(TradeErrorCode.INPUT_DATA_ERROR, "交易明细用户错误")
+ }
+ }
amount = this.details.sumByDouble { it.amount }
+ if (!StringUtil.isEmpty(this.transDate) && !DateUtil.checkDatetimeValid(this.transDate, "yyyyMMdd")) {
+ throw TransactionCheckException(TradeErrorCode.INPUT_DATA_ERROR, "交易日期格式错误[yyyyMMdd]")
+ }
+ if (!StringUtil.isEmpty(this.transTime) && !DateUtil.checkDatetimeValid(this.transTime, "HHmmss")) {
+ throw TransactionCheckException(TradeErrorCode.INPUT_DATA_ERROR, "交易时间格式错误[HHmmss]")
+ }
-
-
-
+ if(StringUtil.isEmpty(this.outtradeno)){
+ throw TransactionCheckException(TradeErrorCode.INPUT_DATA_ERROR, "未传递外部流水号")
+ }
}
private fun preCheckAccount() {
-
- when(person.status){
- TradeDict.STATUS_CLOSED -> throw TransactionCheckException(TradeErrorCode.PERSON_STATUS_ERROR, "用户已注销")
- TradeDict.STATUS_LOCKED -> throw TransactionCheckException(TradeErrorCode.PERSON_STATUS_ERROR, "用户已冻结锁定")
+ if (null != this.person) {
+ when (person.status) {
+ TradeDict.STATUS_CLOSED -> throw TransactionCheckException(TradeErrorCode.PERSON_STATUS_ERROR, "用户已注销")
+ TradeDict.STATUS_LOCKED -> throw TransactionCheckException(TradeErrorCode.PERSON_STATUS_ERROR, "用户已冻结锁定")
+ }
}
}
* @param status - 完成交易状态,见 TradeDict.DTL_STATUS_FAIL
*/
fun done(paydtl: TUserdtl, status: String, service: PersonBalancePayService): TUserdtl {
- return service.finish(paydtl, status, this)
+ return service.finish(paydtl, status, null)
}
fun done(refno: String, status: String, service: PersonBalancePayService): TUserdtl {
- return service.finish(refno, status, this)
+ return service.finish(refno, status, null)
}
}
\ No newline at end of file
import com.supwisdom.dlpay.consume.PersonTransBuilder
import com.supwisdom.dlpay.consume.dao.AccountDao
+import com.supwisdom.dlpay.consume.dao.DebitCreditDtlDao
import com.supwisdom.dlpay.consume.dao.UserdtlDao
import com.supwisdom.dlpay.consume.domain.TAccount
+import com.supwisdom.dlpay.consume.domain.TDebitCreditDtl
import com.supwisdom.dlpay.consume.domain.TUserdtl
import com.supwisdom.dlpay.consume.service.AccountUtilServcie
import com.supwisdom.dlpay.consume.service.PersonBalancePayService
import com.supwisdom.dlpay.framework.domain.TSubject
import com.supwisdom.dlpay.framework.domain.TTranstype
import com.supwisdom.dlpay.framework.service.SystemUtilService
+import com.supwisdom.dlpay.framework.util.StringUtil
import com.supwisdom.dlpay.framework.util.TradeDict
import com.supwisdom.dlpay.framework.util.TradeErrorCode
import com.supwisdom.dlpay.framework.util.Tradetype
override fun readAccountForUpdate(userid: String, nowait: Boolean): TAccount {
- //TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
+ //TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
return accountDao.findByUserid(userid);
}
}
override fun readShopAccForUpdate(shopId: Int, nowait: Boolean): TShopacc {
- // TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
+ // TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
return shopaccDao.findByShopid(shopId)
}
class PersonBalancePayServiceImpl : PersonBalancePayService {
@Autowired
lateinit var userdtlDao: UserdtlDao
+ @Autowired
+ lateinit var debitCreditDtlDao: DebitCreditDtlDao
@Autowired
lateinit var accountDao: AccountDao
lateinit var systemUtilService: SystemUtilService
- private fun lockAccount(builder: PersonTransBuilder): TAccount {
- TODO("")
+ private fun getlockAccount(accno: String): TAccount {
+ //TODO 等待锁
+ return accountDao.getOne(accno)
+ }
+
+ private fun getlockAccountNowait(accno: String): TAccount {
+ //TODO 等待锁
+ return accountDao.getOne(accno)
+ }
+
+ private fun getLockUserdtlNowait(refno: String): TUserdtl {
+ //TODO 加锁,非等待
+ userdtlDao.findByRefno(refno).let {
+ if (null != it) {
+ return it
+ }
+ throw TransactionProcessException(TradeErrorCode.TRANSACTION_NOT_EXISTS, "交易参考号<$refno>不存在")
+ }
+ }
+
+ private fun getLockUserdtl(refno: String): TUserdtl {
+ //TODO 加锁,等待
+ return userdtlDao.findByRefno(refno)
+ }
+
+ private fun checkOuttradenoExist(outtradeno: String): Boolean {
+// TODO("判断 outtradeno 重复发起")
+ return false
+ }
+
+ private fun doDealAccount(accno: String, amount: Double, overdraft: Boolean): TAccount {
+ var account = getlockAccount(accno)
+ if (account.tacCheck())
+ throw TransactionProcessException(TradeErrorCode.ACCOUNT_TAC_ERROR, "账户<$accno>tac校验异常")
+
+ account.addAmount(amount) //入账
+ if (account.checkOverflow())
+ throw TransactionProcessException(TradeErrorCode.OVERFLOW_BALANCE_ERROR, "账户<$accno>已超最大余额限制")
+
+ if (!overdraft && account.checkOverdraft())
+ throw TransactionProcessException(TradeErrorCode.SHORT_BALANCE_ERROR, "账户<$accno>余额不足")
+
+ return accountDao.save(account) //入库更新
+ }
+
+ private fun doDealShopacc(shopaccno: String, amount: Double) {
+ TODO("商户更新余额逻辑")
}
override fun process(builder: PersonTransBuilder): TUserdtl {
- TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
+ return finish(init(builder), TradeDict.DTL_STATUS_SUCCESS, null)
}
override fun init(builder: PersonTransBuilder): TUserdtl {
+ var userdtl = TUserdtl()
+ userdtl.refno = systemUtilService.refno
+ userdtl.accdate = systemUtilService.accdate
+ userdtl.userid = builder.person?.userid
+ if (StringUtil.isEmpty(builder.transDate)) {
+ userdtl.transdate = systemUtilService.sysdatetime.hostdate
+ } else {
+ userdtl.transdate = builder.transDate
+ }
+ if (StringUtil.isEmpty(builder.transTime)) {
+ userdtl.transdate = systemUtilService.sysdatetime.hosttime
+ } else {
+ userdtl.transtime = builder.transTime
+ }
+ userdtl.paytype = builder.paytype
+ userdtl.payinfo = builder.payinfo
+ userdtl.transcode = builder.transcode
+ if (StringUtil.isEmpty(builder.description)) {
+ userdtl.transdesc = systemUtilService.getTranscodeName(builder.transcode, null);
+ } else {
+ userdtl.transdesc = builder.description
+ }
+ userdtl.outtradeno = builder.outtradeno
+// userdtl.operid =
+ when (builder.tradetype) {
+ Tradetype.RECHARGE -> userdtl.tradeflag = 1
+ Tradetype.CONSUME -> userdtl.tradeflag = 2
+ }
+ userdtl.createtime = systemUtilService.sysdatetime.hostdatetime
+ if (checkOuttradenoExist(userdtl.outtradeno)) {
+ throw TransactionProcessException(TradeErrorCode.OUTTRADENO_ALREADY_EXISTS, "外部流水号重复")
+ }
- val userdtl = TUserdtl()
- val refno = systemUtilService.refno
- val systemtime = systemUtilService.sysdatetime
- userdtl.refno = refno
userdtl.amount = builder.amount
- userdtl.createtime = systemtime.hostdatetime
userdtl.status = TradeDict.DTL_STATUS_INIT
- userdtl.transdate = builder.transDate
- userdtl.transtime = builder.transTime
- userdtl.userid = builder.person?.userid
- userdtl.outtradeno = builder.outtradeno
- userdtl.payinfo = builder.payinfo
- userdtl.paytype = builder.paytype
- userdtl.tradeflag = 2
userdtlDao.save(userdtl)
+
+ for (detail in builder.details) {
+ var dtl = TDebitCreditDtl()
+ dtl.refno = userdtl.refno
+ dtl.seqno = detail.rowno
+ dtl.drsubjno = detail.debitSubjNo
+ dtl.draccno = detail.debitAccNo
+ dtl.crsubjno = detail.creditSubjNo
+ dtl.craccno = detail.creditAccNo
+ dtl.amount = detail.amount
+ dtl.summary = detail.summary
+ debitCreditDtlDao.save(dtl)
+ }
return userdtl
}
- override fun wip(paydtl: TUserdtl, builder: PersonTransBuilder): TUserdtl {
- TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
+ override fun finish(paydtl: TUserdtl, status: String, businessData: Map<String, String>?): TUserdtl {
+ return finish(paydtl.refno, status, businessData)
}
- override fun wip(refno: String, builder: PersonTransBuilder): TUserdtl {
- TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
- }
+ override fun finish(refno: String, status: String, businessData: Map<String, String>?): TUserdtl {
+ var userdtl = getLockUserdtl(refno)
+ when (status) {
+ TradeDict.DTL_STATUS_FAIL -> {
+ //失败
+ if (TradeDict.DTL_STATUS_SUCCESS == userdtl.status)
+ throw TransactionProcessException(TradeErrorCode.TRANSACTION_IS_FINISHED, "流水已经交易成功")
+ userdtl.status = TradeDict.DTL_STATUS_FAIL
+ userdtl.endtime = systemUtilService.sysdatetime.hostdatetime
+ userdtl.remark = businessData?.get("errmsg")
+ return userdtlDao.save(userdtl)
+ }
- override fun finish(paydtl: TUserdtl, status: String, builder: PersonTransBuilder): TUserdtl {
- if(paydtl.status==TradeDict.DTL_STATUS_SUCCESS){
- return paydtl
- }
- paydtl.status = status
- if(status==TradeDict.DTL_STATUS_SUCCESS){
- //TODO 更新商户余额,科目余额,账户支付的需要更新余额
- }
- val systemtime = systemUtilService.sysdatetime
- paydtl.endtime = systemtime.hostdatetime
- userdtlDao.save(paydtl)
- return paydtl
- }
+ TradeDict.DTL_STATUS_SUCCESS -> {
+ //成功
+ if (TradeDict.DTL_STATUS_SUCCESS == userdtl.status)
+ return userdtl //已成功直接返回
- override fun finish(refno: String, status: String, builder: PersonTransBuilder): TUserdtl {
- userdtlDao.findById(refno).let {
- if (it.isPresent) {
- return finish(it.get(), status, builder)
+ for (detail in debitCreditDtlDao.findByRefno(userdtl.refno)) {
+ //个人账户入账
+ if (TradeDict.SUBJNO_ACCOUNT == detail.drsubjno) {
+ doDealAccount(detail.drsubjno, -1 * detail.amount, false) //借方消费
+ }
+ if (TradeDict.SUBJNO_ACCOUNT == detail.crsubjno) {
+ doDealAccount(detail.drsubjno, detail.amount, false) //贷方充值
+ }
+
+ //商户入账
+ if (TradeDict.SUBJNO_SHOP == detail.drsubjno) {
+ doDealShopacc(detail.draccno, -1 * detail.amount)
+ }
+ if (TradeDict.SUBJNO_SHOP == detail.crsubjno) {
+ doDealShopacc(detail.draccno, detail.amount)
+ }
+ }
+
+ userdtl.status = TradeDict.DTL_STATUS_SUCCESS
+ userdtl.accdate = systemUtilService.accdate //入账成功时更新
+ userdtl.endtime = systemUtilService.sysdatetime.hostdatetime
+ //TODO 存储一些业务参数
+ return userdtlDao.save(userdtl)
}
- throw TransactionProcessException(TradeErrorCode.TRANSACTION_NOT_EXISTS, "交易参考号<$refno>不存在")
+
+ else -> throw TransactionProcessException(TradeErrorCode.TRANSDTL_STATUS_ERROR, "未指定明确的交易结束状态")
}
}
+ override fun wip(paydtl: TUserdtl, builder: PersonTransBuilder): TUserdtl {
+ return wip(paydtl.refno, builder)
+ }
+
+ override fun wip(refno: String, builder: PersonTransBuilder): TUserdtl {
+ var userdtl = getLockUserdtlNowait(refno)
+ if (TradeDict.DTL_STATUS_INIT != userdtl.status)
+ throw TransactionProcessException(TradeErrorCode.TRANSDTL_STATUS_NOT_INIT, "交易参考号<$refno>非初始化流水")
+ userdtl.status = TradeDict.DTL_STATUS_WIP //待支付
+ return userdtlDao.save(userdtl)
+ }
}
\ No newline at end of file
*/
fun init(builder: PersonTransBuilder): TUserdtl
+ /**
+ * 两步交易,完成交易过程,包括更新交易状态(成功、失败),更新借贷双方余额
+ */
+ fun finish(paydtl: TUserdtl, status: String, businessData: Map<String, String>?): TUserdtl
+
+ fun finish(refno: String, status: String, businessData: Map<String, String>?): TUserdtl
+
/**
* 两步交易,交易过程中判断交易状态,并更新交易状态为 wip
*/
fun wip(refno: String, builder: PersonTransBuilder): TUserdtl
- /**
- * 两步交易,完成交易过程,包括更新交易状态(成功、失败),更新借贷双方余额
- */
- fun finish(paydtl: TUserdtl, status: String, builder: PersonTransBuilder): TUserdtl
- fun finish(refno: String, status: String, builder: PersonTransBuilder): TUserdtl
}
\ No newline at end of file