From: Xia Kaixiang Date: Fri, 12 Apr 2019 07:15:23 +0000 (+0800) Subject: 消费初步实现 X-Git-Tag: 1.0.0^2~303 X-Git-Url: https://source.supwisdom.com/gerrit/gitweb?a=commitdiff_plain;h=2df023f9c48795aa43bf8dc9f1762c71167a2dc1;p=epayment%2Ffood_payapi.git 消费初步实现 --- diff --git a/src/main/java/com/supwisdom/dlpay/consume/dao/AccountDao.java b/src/main/java/com/supwisdom/dlpay/consume/dao/AccountDao.java index e82cb110..b2a78922 100644 --- a/src/main/java/com/supwisdom/dlpay/consume/dao/AccountDao.java +++ b/src/main/java/com/supwisdom/dlpay/consume/dao/AccountDao.java @@ -11,8 +11,9 @@ import javax.persistence.LockModeType; public interface AccountDao extends JpaRepository { @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); } diff --git a/src/main/java/com/supwisdom/dlpay/consume/dao/DebitCreditDtlDao.java b/src/main/java/com/supwisdom/dlpay/consume/dao/DebitCreditDtlDao.java index d841c709..220ff83d 100644 --- a/src/main/java/com/supwisdom/dlpay/consume/dao/DebitCreditDtlDao.java +++ b/src/main/java/com/supwisdom/dlpay/consume/dao/DebitCreditDtlDao.java @@ -18,4 +18,7 @@ public interface DebitCreditDtlDao extends JpaRepository getVoucherData(@RequestParam("settledate") String settledate); + + + List findByRefno(String refno); } diff --git a/src/main/java/com/supwisdom/dlpay/consume/domain/TAccount.java b/src/main/java/com/supwisdom/dlpay/consume/domain/TAccount.java index cdb9cabd..9dd87c10 100644 --- a/src/main/java/com/supwisdom/dlpay/consume/domain/TAccount.java +++ b/src/main/java/com/supwisdom/dlpay/consume/domain/TAccount.java @@ -1,5 +1,7 @@ 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.*; @@ -230,4 +232,46 @@ public class TAccount { 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; + } } diff --git a/src/main/java/com/supwisdom/dlpay/consume/domain/TPerson.java b/src/main/java/com/supwisdom/dlpay/consume/domain/TPerson.java index 8a2cb713..c5bceb60 100644 --- a/src/main/java/com/supwisdom/dlpay/consume/domain/TPerson.java +++ b/src/main/java/com/supwisdom/dlpay/consume/domain/TPerson.java @@ -61,10 +61,7 @@ public class TPerson { 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; diff --git a/src/main/java/com/supwisdom/dlpay/framework/util/MD5.java b/src/main/java/com/supwisdom/dlpay/framework/util/MD5.java new file mode 100644 index 00000000..4d5ba843 --- /dev/null +++ b/src/main/java/com/supwisdom/dlpay/framework/util/MD5.java @@ -0,0 +1,70 @@ +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]; + } + +} diff --git a/src/main/java/com/supwisdom/dlpay/framework/util/TradeErrorCode.java b/src/main/java/com/supwisdom/dlpay/framework/util/TradeErrorCode.java index 6c89ce0b..1c4e0469 100644 --- a/src/main/java/com/supwisdom/dlpay/framework/util/TradeErrorCode.java +++ b/src/main/java/com/supwisdom/dlpay/framework/util/TradeErrorCode.java @@ -49,5 +49,29 @@ public class TradeErrorCode { * */ 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; } diff --git a/src/main/java/com/supwisdom/dlpay/util/MoneyUtil.java b/src/main/java/com/supwisdom/dlpay/util/MoneyUtil.java index 2fb8b73a..fac8ed41 100644 --- a/src/main/java/com/supwisdom/dlpay/util/MoneyUtil.java +++ b/src/main/java/com/supwisdom/dlpay/util/MoneyUtil.java @@ -5,24 +5,26 @@ import java.text.DecimalFormat; public class MoneyUtil { - public static int YuanToFen(double yuan) { - return (int) (Math.round(yuan * 100)); - } - - public static boolean moneyCompare(double x1, double x2) { - return YuanToFen(x1) == YuanToFen(x2); - } - public static double formatYuan(double yuan) { - DecimalFormat df = new DecimalFormat("##0.00"); - double money = ((double) YuanToFen(yuan)) / 100; - return Double.valueOf(df.format(money)); - } - - public static double FenToYuan(int fen) { - return formatYuan(fen / 100.0); - } - public static String format(double num,String format) { - DecimalFormat df = new DecimalFormat(format); - return df.format(num); - } + public static int YuanToFen(double yuan) { + return (int) (Math.round(yuan * 100)); + } + + public static boolean moneyCompare(double x1, double x2) { + return YuanToFen(x1) == YuanToFen(x2); + } + + public static double formatYuan(double yuan) { + DecimalFormat df = new DecimalFormat("##0.00"); + double money = ((double) YuanToFen(yuan)) / 100; + return Double.valueOf(df.format(money)); + } + + public static double FenToYuan(int fen) { + return formatYuan(fen / 100.0); + } + + public static String format(double num, String format) { + DecimalFormat df = new DecimalFormat(format); + return df.format(num); + } } diff --git a/src/main/kotlin/com/supwisdom/dlpay/consume/comsume_builder.kt b/src/main/kotlin/com/supwisdom/dlpay/consume/comsume_builder.kt index 8243a78d..67257c6d 100644 --- a/src/main/kotlin/com/supwisdom/dlpay/consume/comsume_builder.kt +++ b/src/main/kotlin/com/supwisdom/dlpay/consume/comsume_builder.kt @@ -9,10 +9,7 @@ import com.supwisdom.dlpay.exception.TransactionCheckException 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 private constructor(val accountId: String, val idType: Int) { companion object { @@ -70,6 +67,8 @@ class PersonTransBuilder private constructor(accUitl: AccountUtilServcie) { lateinit var person: TPerson lateinit var tradetype:Tradetype + var transcode = 0 + var transDate = "" var transTime = "" /** @@ -78,22 +77,23 @@ class PersonTransBuilder private constructor(accUitl: AccountUtilServcie) { var overdraft = false var description = "" - // 内部参数,不需要调用者处理 val details = mutableListOf() 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 @@ -111,6 +111,12 @@ class PersonTransBuilder private constructor(accUitl: AccountUtilServcie) { 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 @@ -122,32 +128,75 @@ class PersonTransBuilder private constructor(accUitl: AccountUtilServcie) { 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, "用户已冻结锁定") + } } } @@ -217,10 +266,10 @@ class PersonTransBuilder private constructor(accUitl: AccountUtilServcie) { * @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 diff --git a/src/main/kotlin/com/supwisdom/dlpay/consume/service/impl/pay_service_impl.kt b/src/main/kotlin/com/supwisdom/dlpay/consume/service/impl/pay_service_impl.kt index 8ce1108f..44c0a564 100644 --- a/src/main/kotlin/com/supwisdom/dlpay/consume/service/impl/pay_service_impl.kt +++ b/src/main/kotlin/com/supwisdom/dlpay/consume/service/impl/pay_service_impl.kt @@ -2,8 +2,10 @@ package com.supwisdom.dlpay.consume.service.impl 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 @@ -14,6 +16,7 @@ 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.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 @@ -36,7 +39,7 @@ class AccountUtilServcieImpl : AccountUtilServcie { 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); } @@ -50,7 +53,7 @@ class AccountUtilServcieImpl : AccountUtilServcie { } 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) } @@ -87,6 +90,8 @@ class AccountUtilServcieImpl : AccountUtilServcie { class PersonBalancePayServiceImpl : PersonBalancePayService { @Autowired lateinit var userdtlDao: UserdtlDao + @Autowired + lateinit var debitCreditDtlDao: DebitCreditDtlDao @Autowired lateinit var accountDao: AccountDao @@ -98,64 +103,173 @@ class PersonBalancePayServiceImpl : PersonBalancePayService { 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?): 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?): 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 diff --git a/src/main/kotlin/com/supwisdom/dlpay/consume/service/pay_service.kt b/src/main/kotlin/com/supwisdom/dlpay/consume/service/pay_service.kt index d3d99334..8bfc9009 100644 --- a/src/main/kotlin/com/supwisdom/dlpay/consume/service/pay_service.kt +++ b/src/main/kotlin/com/supwisdom/dlpay/consume/service/pay_service.kt @@ -33,6 +33,13 @@ interface PersonBalancePayService { */ fun init(builder: PersonTransBuilder): TUserdtl + /** + * 两步交易,完成交易过程,包括更新交易状态(成功、失败),更新借贷双方余额 + */ + fun finish(paydtl: TUserdtl, status: String, businessData: Map?): TUserdtl + + fun finish(refno: String, status: String, businessData: Map?): TUserdtl + /** * 两步交易,交易过程中判断交易状态,并更新交易状态为 wip */ @@ -40,10 +47,5 @@ interface PersonBalancePayService { 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