消费初步实现
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 e82cb11..b2a7892 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 @@
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);
}
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 d841c70..220ff83 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 @@
"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);
}
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 cdb9cab..9dd87c1 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 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 8a2cb71..c5bceb6 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 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 0000000..4d5ba84
--- /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 6c89ce0..1c4e046 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 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 2fb8b73..fac8ed4 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 @@
public class MoneyUtil {
- public static int YuanToFen(double yuan) {
- return (int) (Math.round(yuan * 100));
- }
+ 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 boolean moneyCompare(double x1, double x2) {
+ return YuanToFen(x1) == YuanToFen(x2);
+ }
- 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 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 8243a78..67257c6 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.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 {
@@ -70,6 +67,8 @@
lateinit var person: TPerson
lateinit var tradetype:Tradetype
+ var transcode = 0
+
var transDate = ""
var transTime = ""
/**
@@ -78,22 +77,23 @@
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
@@ -111,6 +111,12 @@
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 @@
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 @@
* @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 8ce1108..44c0a56 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 @@
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.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 @@
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 @@
}
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 PersonBalancePayServiceImpl : PersonBalancePayService {
@Autowired
lateinit var userdtlDao: UserdtlDao
+ @Autowired
+ lateinit var debitCreditDtlDao: DebitCreditDtlDao
@Autowired
lateinit var accountDao: AccountDao
@@ -98,64 +103,173 @@
lateinit var systemUtilService: SystemUtilService
- private fun lockAccount(builder: PersonTransBuilder): TAccount {
- TODO("")
+ private fun getlockAccount(accno: String): TAccount {
+ //TODO 等待锁
+ return accountDao.getOne(accno)
}
- override fun process(builder: PersonTransBuilder): TUserdtl {
- TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
+ private fun getlockAccountNowait(accno: String): TAccount {
+ //TODO 等待锁
+ return accountDao.getOne(accno)
}
- override fun init(builder: PersonTransBuilder): TUserdtl {
-
- 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)
- 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 wip(refno: String, builder: PersonTransBuilder): TUserdtl {
- TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
- }
-
- 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
- }
-
- override fun finish(refno: String, status: String, builder: PersonTransBuilder): TUserdtl {
- userdtlDao.findById(refno).let {
- if (it.isPresent) {
- return finish(it.get(), status, builder)
+ 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 {
+ 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, "外部流水号重复")
+ }
+
+ userdtl.amount = builder.amount
+ userdtl.status = TradeDict.DTL_STATUS_INIT
+ 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 finish(paydtl: TUserdtl, status: String, businessData: Map<String, String>?): TUserdtl {
+ return finish(paydtl.refno, status, businessData)
+ }
+
+ 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)
+ }
+
+ TradeDict.DTL_STATUS_SUCCESS -> {
+ //成功
+ if (TradeDict.DTL_STATUS_SUCCESS == userdtl.status)
+ return userdtl //已成功直接返回
+
+ 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)
+ }
+
+ 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 d3d9933..8bfc900 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
@@ -34,16 +34,18 @@
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(paydtl: TUserdtl, builder: PersonTransBuilder): TUserdtl
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