临时提交
diff --git a/src/main/java/com/supwisdom/dlpay/api/dao/AccountDao.java b/src/main/java/com/supwisdom/dlpay/api/dao/AccountDao.java
index 806b049..8d3130d 100644
--- a/src/main/java/com/supwisdom/dlpay/api/dao/AccountDao.java
+++ b/src/main/java/com/supwisdom/dlpay/api/dao/AccountDao.java
@@ -1,25 +1,22 @@
package com.supwisdom.dlpay.api.dao;
import com.supwisdom.dlpay.api.domain.TAccount;
-import com.supwisdom.dlpay.api.domain.TPerson;
+import com.supwisdom.dlpay.api.repositories.TAccountRepository;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
-import org.springframework.data.jpa.repository.JpaRepository;
-import org.springframework.data.jpa.repository.Lock;
-import org.springframework.data.jpa.repository.Query;
-import org.springframework.data.jpa.repository.QueryHints;
+import org.springframework.data.jpa.repository.*;
import javax.persistence.LockModeType;
import javax.persistence.QueryHint;
-public interface AccountDao extends JpaRepository<TAccount, String> {
+public interface AccountDao extends JpaRepository<TAccount, String>, TAccountRepository {
@Lock(LockModeType.PESSIMISTIC_WRITE)
@Query("select a from TAccount a where a.accno = ?1")
TAccount getByAccnoForUpdate(String accno);
@Lock(LockModeType.PESSIMISTIC_WRITE)
- @QueryHints({@QueryHint(name = "javax.persistence.lock.timeout", value ="0")})
+ @QueryHints({@QueryHint(name = "javax.persistence.lock.timeout", value = "0")})
@Query("select a from TAccount a where a.accno = ?1")
TAccount getByAccnoForUpdateNowait(String accno);
@@ -37,5 +34,9 @@
@Query("select a from TAccount a where a.userid = ?1 and a.subjno=?2")
TAccount findByUseridAndSubjno(String userid, String subjno);
+ @Modifying
+ @Query("update TAccount t set t.availbal=t.availbal-?3 , t.balance=t.balance-?3 where t.accno=?1 and t.availbal=?2")
+ int updateAccountBalance(String accno, Double availbal, Double amount);
+
Page<TAccount> findAllByAccnameContaining(String accname, Pageable pageable);
}
diff --git a/src/main/java/com/supwisdom/dlpay/api/dao/PersondtlDao.java b/src/main/java/com/supwisdom/dlpay/api/dao/PersondtlDao.java
new file mode 100644
index 0000000..2ee4550
--- /dev/null
+++ b/src/main/java/com/supwisdom/dlpay/api/dao/PersondtlDao.java
@@ -0,0 +1,7 @@
+package com.supwisdom.dlpay.api.dao;
+
+import com.supwisdom.dlpay.api.domain.TPersondtl;
+import org.springframework.data.repository.CrudRepository;
+
+public interface PersondtlDao extends CrudRepository<TPersondtl, String> {
+}
diff --git a/src/main/java/com/supwisdom/dlpay/api/dao/ShopdtlDao.java b/src/main/java/com/supwisdom/dlpay/api/dao/ShopdtlDao.java
new file mode 100644
index 0000000..42f928f
--- /dev/null
+++ b/src/main/java/com/supwisdom/dlpay/api/dao/ShopdtlDao.java
@@ -0,0 +1,7 @@
+package com.supwisdom.dlpay.api.dao;
+
+import com.supwisdom.dlpay.api.domain.TShopdtl;
+import org.springframework.data.repository.CrudRepository;
+
+public interface ShopdtlDao extends CrudRepository<TShopdtl, String> {
+}
diff --git a/src/main/java/com/supwisdom/dlpay/api/dao/SubjectdtlDao.java b/src/main/java/com/supwisdom/dlpay/api/dao/SubjectdtlDao.java
new file mode 100644
index 0000000..968a031
--- /dev/null
+++ b/src/main/java/com/supwisdom/dlpay/api/dao/SubjectdtlDao.java
@@ -0,0 +1,7 @@
+package com.supwisdom.dlpay.api.dao;
+
+import com.supwisdom.dlpay.api.domain.TSubjectdtl;
+import org.springframework.data.repository.CrudRepository;
+
+public interface SubjectdtlDao extends CrudRepository<TSubjectdtl, String> {
+}
diff --git a/src/main/java/com/supwisdom/dlpay/api/dao/TransactionMainDao.java b/src/main/java/com/supwisdom/dlpay/api/dao/TransactionMainDao.java
new file mode 100644
index 0000000..649758d
--- /dev/null
+++ b/src/main/java/com/supwisdom/dlpay/api/dao/TransactionMainDao.java
@@ -0,0 +1,18 @@
+package com.supwisdom.dlpay.api.dao;
+
+import com.supwisdom.dlpay.api.domain.TTransactionMain;
+import org.springframework.data.jpa.repository.Lock;
+import org.springframework.data.jpa.repository.Query;
+import org.springframework.data.jpa.repository.QueryHints;
+import org.springframework.data.repository.CrudRepository;
+
+import javax.persistence.LockModeType;
+import javax.persistence.QueryHint;
+
+public interface TransactionMainDao extends CrudRepository<TTransactionMain, String> {
+
+ @Lock(LockModeType.PESSIMISTIC_WRITE)
+ @QueryHints({@QueryHint(name = "javax.persistence.lock.timeout", value = "0")})
+ @Query(value = "select t from TTransactionMain t where t.refno = ?1")
+ TTransactionMain findByRefnoForUpdate(String refno);
+}
diff --git a/src/main/java/com/supwisdom/dlpay/api/domain/TDebitCreditDtl.java b/src/main/java/com/supwisdom/dlpay/api/domain/TDebitCreditDtl.java
index dc5a9a9..85bac09 100644
--- a/src/main/java/com/supwisdom/dlpay/api/domain/TDebitCreditDtl.java
+++ b/src/main/java/com/supwisdom/dlpay/api/domain/TDebitCreditDtl.java
@@ -12,9 +12,12 @@
private String refno;
@Id
- @Column(name = "SEQNO", nullable = false, precision = 1)
+ @Column(name = "SEQNO", nullable = false, precision = 2)
private Integer seqno;
+ @Column(name = "accdate", nullable = false, length = 8)
+ private String accdate;
+
@Column(name = "DRSUBJNO", length = 10)
private String drsubjno; //借方科目
@@ -97,4 +100,12 @@
public void setSummary(String summary) {
this.summary = summary;
}
+
+ public String getAccdate() {
+ return accdate;
+ }
+
+ public void setAccdate(String accdate) {
+ this.accdate = accdate;
+ }
}
diff --git a/src/main/java/com/supwisdom/dlpay/api/domain/TPersondtl.java b/src/main/java/com/supwisdom/dlpay/api/domain/TPersondtl.java
index deaeaf3..0e37a32 100644
--- a/src/main/java/com/supwisdom/dlpay/api/domain/TPersondtl.java
+++ b/src/main/java/com/supwisdom/dlpay/api/domain/TPersondtl.java
@@ -7,8 +7,7 @@
indexes = {@Index(name = "prsndtl_transdate_idx", columnList = "transdate"),
@Index(name = "prsndtl_accdate_idx", columnList = "accdate"),
@Index(name = "prsndtl_status_idx", columnList = "status"),
- @Index(name = "prsndtl_reverse_idx", columnList = "REVERSE_FLAG"),
- @Index(name = "prsndtl_outtradeno_uk", unique = true, columnList = "outtradeno,shopaccno")})
+ @Index(name = "prsndtl_reverse_idx", columnList = "REVERSE_FLAG")})
public class TPersondtl {
@Id
@@ -21,6 +20,12 @@
@Column(name = "USERID", length = 32)
private String userid; //用户ID,或账号
+ @Column(name = "acccno", length = 32)
+ private String accountNo;
+
+ @Column(name = "USERNAME", length = 200)
+ private String userName;
+
@Column(name = "TRANSDATE", length = 8)
private String transdate;
@@ -54,10 +59,13 @@
@Column(name = "OPPOSITEACCNO", length = 20)
private String oppositeAccNo;
+ @Column(name = "OPPOSITEACCNAME", length = 200)
+ private String oppositeAccName;
+
@Column(name = "OPERID", precision = 9)
private Integer operid; //操作员ID
- @Column(name = "REVERSE_FLAG", nullable = false, precision = 1)
+ @Column(name = "REVERSE_FLAG", nullable = false, length = 10)
private String reverseFlag = "none"; //none, cancel, reversed
@Column(name = "REVERSE_AMOUNT", precision = 9, scale = 2)
@@ -242,4 +250,28 @@
public void setEndtime(String endtime) {
this.endtime = endtime;
}
+
+ public String getUserName() {
+ return userName;
+ }
+
+ public void setUserName(String userName) {
+ this.userName = userName;
+ }
+
+ public String getOppositeAccName() {
+ return oppositeAccName;
+ }
+
+ public void setOppositeAccName(String oppositeAccName) {
+ this.oppositeAccName = oppositeAccName;
+ }
+
+ public String getAccountNo() {
+ return accountNo;
+ }
+
+ public void setAccountNo(String accountNo) {
+ this.accountNo = accountNo;
+ }
}
diff --git a/src/main/java/com/supwisdom/dlpay/api/domain/TShopdtl.java b/src/main/java/com/supwisdom/dlpay/api/domain/TShopdtl.java
index 2649d02..ad43a2f 100644
--- a/src/main/java/com/supwisdom/dlpay/api/domain/TShopdtl.java
+++ b/src/main/java/com/supwisdom/dlpay/api/domain/TShopdtl.java
@@ -1,10 +1,12 @@
package com.supwisdom.dlpay.api.domain;
-import javax.persistence.Column;
-import javax.persistence.Id;
-import javax.persistence.Table;
+import javax.persistence.*;
-@Table(name = "TB_SHOPDTL")
+@Entity
+@Table(name = "TB_SHOPDTL",
+ indexes = {@Index(name = "shopdtl_accdate", columnList = "accdate"),
+ @Index(name = "shopdtl_shopaccno", columnList = "shopaccno"),
+ @Index(name = "shopdtl_transdate", columnList = "transdate")})
public class TShopdtl {
@Id
@Column(name = "refno", length = 32, nullable = false)
@@ -28,6 +30,9 @@
@Column(name = "transtime", length = 6)
private String transTime;
+ @Column(name = "tradecode", precision = 8)
+ private Integer tradeCode;
+
@Column(name = "paytype", length = 20)
private String payType;
@@ -37,6 +42,12 @@
@Column(name = "status", length = 20)
private String status;
+ @Column(name = "OPPOSITEACCNO", length = 20)
+ private String oppositeAccNo;
+
+ @Column(name = "OPPOSITEACCNAME", length = 200)
+ private String oppositeAccName;
+
public String getRefno() {
return refno;
}
@@ -116,4 +127,28 @@
public void setStatus(String status) {
this.status = status;
}
+
+ public String getOppositeAccNo() {
+ return oppositeAccNo;
+ }
+
+ public void setOppositeAccNo(String oppositeAccNo) {
+ this.oppositeAccNo = oppositeAccNo;
+ }
+
+ public String getOppositeAccName() {
+ return oppositeAccName;
+ }
+
+ public void setOppositeAccName(String oppositeAccName) {
+ this.oppositeAccName = oppositeAccName;
+ }
+
+ public Integer getTradeCode() {
+ return tradeCode;
+ }
+
+ public void setTradeCode(Integer tradeCode) {
+ this.tradeCode = tradeCode;
+ }
}
diff --git a/src/main/java/com/supwisdom/dlpay/api/domain/TSubjectdtl.java b/src/main/java/com/supwisdom/dlpay/api/domain/TSubjectdtl.java
new file mode 100644
index 0000000..dc3fe04
--- /dev/null
+++ b/src/main/java/com/supwisdom/dlpay/api/domain/TSubjectdtl.java
@@ -0,0 +1,153 @@
+package com.supwisdom.dlpay.api.domain;
+
+import javax.persistence.*;
+
+@Entity
+@Table(name = "TB_SUBJECtDTL",
+ indexes = {@Index(name = "subjdtl_accdate", columnList = "accdate"),
+ @Index(name = "subjdtl_subjno", columnList = "subjno")})
+public class TSubjectdtl {
+ @Id
+ @Column(name = "refno", length = 32, nullable = false)
+ private String refno;
+
+ @Column(name = "accdate", length = 8, nullable = false)
+ private String accdate;
+
+ @Column(name = "subjno", length = 10, nullable = false)
+ private String subjectno;
+
+ @Column(name = "subjname", length = 200)
+ private String subjectName;
+
+ @Column(name = "amount", scale = 2, precision = 15)
+ private Double amount;
+
+ @Column(name = "tradecode", precision = 8)
+ private Integer tradeCode;
+
+ @Column(name = "transdate", length = 8)
+ private String transDate;
+
+ @Column(name = "transtime", length = 6)
+ private String transTime;
+
+ @Column(name = "paytype", length = 20)
+ private String payType;
+
+ @Column(name = "payinfo", length = 200)
+ private String payInfo;
+
+ @Column(name = "OPPOSITEACCNO", length = 20)
+ private String oppositeAccNo;
+
+ @Column(name = "OPPOSITEACCNAME", length = 200)
+ private String oppositeAccName;
+
+ @Column(name = "status", length = 20)
+ private String status;
+
+ public String getRefno() {
+ return refno;
+ }
+
+ public void setRefno(String refno) {
+ this.refno = refno;
+ }
+
+ public String getAccdate() {
+ return accdate;
+ }
+
+ public void setAccdate(String accdate) {
+ this.accdate = accdate;
+ }
+
+ public String getSubjectno() {
+ return subjectno;
+ }
+
+ public void setSubjectno(String subjectno) {
+ this.subjectno = subjectno;
+ }
+
+ public String getSubjectName() {
+ return subjectName;
+ }
+
+ public void setSubjectName(String subjectName) {
+ this.subjectName = subjectName;
+ }
+
+ public Double getAmount() {
+ return amount;
+ }
+
+ public void setAmount(Double amount) {
+ this.amount = amount;
+ }
+
+ public String getTransDate() {
+ return transDate;
+ }
+
+ public void setTransDate(String transDate) {
+ this.transDate = transDate;
+ }
+
+ public String getTransTime() {
+ return transTime;
+ }
+
+ public void setTransTime(String transTime) {
+ this.transTime = transTime;
+ }
+
+ public String getPayType() {
+ return payType;
+ }
+
+ public void setPayType(String payType) {
+ this.payType = payType;
+ }
+
+ public String getPayInfo() {
+ return payInfo;
+ }
+
+ public void setPayInfo(String payInfo) {
+ this.payInfo = payInfo;
+ }
+
+ public String getOppositeAccNo() {
+ return oppositeAccNo;
+ }
+
+ public void setOppositeAccNo(String oppositeAccNo) {
+ this.oppositeAccNo = oppositeAccNo;
+ }
+
+ public String getOppositeAccName() {
+ return oppositeAccName;
+ }
+
+ public void setOppositeAccName(String oppositeAccName) {
+ this.oppositeAccName = oppositeAccName;
+ }
+
+ public String getStatus() {
+ return status;
+ }
+
+ public void setStatus(String status) {
+ this.status = status;
+ }
+
+ public Integer getTradeCode() {
+ return tradeCode;
+ }
+
+ public void setTradeCode(Integer tradeCode) {
+ this.tradeCode = tradeCode;
+ }
+}
diff --git a/src/main/java/com/supwisdom/dlpay/api/domain/TTransactionMain.java b/src/main/java/com/supwisdom/dlpay/api/domain/TTransactionMain.java
new file mode 100644
index 0000000..dba7948
--- /dev/null
+++ b/src/main/java/com/supwisdom/dlpay/api/domain/TTransactionMain.java
@@ -0,0 +1,136 @@
+package com.supwisdom.dlpay.api.domain;
+
+import com.supwisdom.dlpay.framework.domain.TSubject;
+
+import javax.persistence.*;
+
+import static javax.persistence.FetchType.LAZY;
+
+@Entity
+@Table(name = "TB_TRANSACTIONMAIN",
+ indexes = {@Index(name = "transmain_accdate", columnList = "accdate"),
+ @Index(name = "transmain_status", columnList = "status"),
+ @Index(name = "transmain_outtrade", unique = true, columnList = "outid, outtradeno")})
+public class TTransactionMain {
+ @Id
+ @Column(name = "refno", nullable = false, length = 32)
+ private String refno;
+
+ @Column(name = "accdate", nullable = false, length = 8)
+ private String accdate;
+
+ @Column(name = "person")
+ private Boolean person = false;
+
+ @Column(name = "shop")
+ private Boolean shop = false;
+
+ @Column(name = "subject")
+ private Boolean subject = false;
+
+ @Column(name = "status", length = 20)
+ private String status = "none";
+
+ @Column(name = "outtradeno", length = 60)
+ private String outTradeNo = "";
+
+ @Column(name = "outid", length = 60)
+ private String outId;
+
+ @Column(name = "reverse_flag", nullable = false, length = 10)
+ private String reverseFlag = "none";
+
+ @OneToOne(targetEntity = TPersondtl.class, mappedBy = "refno", fetch = LAZY)
+ private TPersondtl personDtl;
+
+ @OneToOne(targetEntity = TShopdtl.class, mappedBy = "refno", fetch = LAZY)
+ private TShopdtl shopDtl;
+
+ @OneToOne(targetEntity = TSubjectdtl.class, mappedBy = "refno", fetch = LAZY)
+ private TSubjectdtl subjectDtl;
+
+ public String getRefno() {
+ return refno;
+ }
+
+ public void setRefno(String refno) {
+ this.refno = refno;
+ }
+
+ public String getAccdate() {
+ return accdate;
+ }
+
+ public void setAccdate(String accdate) {
+ this.accdate = accdate;
+ }
+
+
+ public Boolean getPerson() {
+ return person;
+ }
+
+ public void setPerson(Boolean person) {
+ this.person = person;
+ }
+
+ public Boolean getShop() {
+ return shop;
+ }
+
+ public void setShop(Boolean shop) {
+ this.shop = shop;
+ }
+
+ public Boolean getSubject() {
+ return subject;
+ }
+
+ public void setSubject(Boolean subject) {
+ this.subject = subject;
+ }
+
+ public String getStatus() {
+ return status;
+ }
+
+ public void setStatus(String status) {
+ this.status = status;
+ }
+
+ public String getOutTradeNo() {
+ return outTradeNo;
+ }
+
+ public void setOutTradeNo(String outTradeNo) {
+ this.outTradeNo = outTradeNo;
+ }
+
+ public String getOutId() {
+ return outId;
+ }
+
+ public void setOutId(String outId) {
+ this.outId = outId;
+ }
+
+ public String getReverseFlag() {
+ return reverseFlag;
+ }
+
+ public void setReverseFlag(String reverseFlag) {
+ this.reverseFlag = reverseFlag;
+ }
+
+ public TPersondtl getPersonDtl() {
+ return personDtl;
+ }
+
+ public TShopdtl getShopDtl() {
+ return shopDtl;
+ }
+
+ public TSubjectdtl getSubjectDtl() {
+ return subjectDtl;
+ }
+}
diff --git a/src/main/java/com/supwisdom/dlpay/api/repositories/TAccountRepository.java b/src/main/java/com/supwisdom/dlpay/api/repositories/TAccountRepository.java
new file mode 100644
index 0000000..d999a27
--- /dev/null
+++ b/src/main/java/com/supwisdom/dlpay/api/repositories/TAccountRepository.java
@@ -0,0 +1,5 @@
+package com.supwisdom.dlpay.api.repositories;
+
+public interface TAccountRepository {
+ int updateAccountBalance(String accno, Double avaibal, Double amount);
+}
diff --git a/src/main/java/com/supwisdom/dlpay/api/repositories/impl/TAccountRepositoryImpl.java b/src/main/java/com/supwisdom/dlpay/api/repositories/impl/TAccountRepositoryImpl.java
new file mode 100644
index 0000000..029e85f
--- /dev/null
+++ b/src/main/java/com/supwisdom/dlpay/api/repositories/impl/TAccountRepositoryImpl.java
@@ -0,0 +1,31 @@
+package com.supwisdom.dlpay.api.repositories.impl;
+
+import com.supwisdom.dlpay.api.domain.TAccount;
+import com.supwisdom.dlpay.api.repositories.TAccountRepository;
+import org.springframework.stereotype.Repository;
+import org.springframework.transaction.annotation.Transactional;
+
+import javax.persistence.EntityManager;
+import javax.persistence.PersistenceContext;
+import javax.persistence.Query;
+
+@Repository
+@Transactional
+public class TAccountRepositoryImpl implements TAccountRepository {
+
+ @PersistenceContext
+ private EntityManager em;
+
+ @Override
+ public int updateAccountBalance(String accno, Double avaibal, Double amount) {
+
+ TAccount account = em.find(TAccount.class, accno);
+ if (account == null) {
+ return 0;
+ }
+
+
+
+ return 0;
+ }
+}
diff --git a/src/main/java/com/supwisdom/dlpay/framework/util/TradeDict.java b/src/main/java/com/supwisdom/dlpay/framework/util/TradeDict.java
index 7bec421..8769f1f 100644
--- a/src/main/java/com/supwisdom/dlpay/framework/util/TradeDict.java
+++ b/src/main/java/com/supwisdom/dlpay/framework/util/TradeDict.java
@@ -31,6 +31,7 @@
public static final String DTL_STATUS_FAIL = "fail";
public static final String DTL_STATUS_CANCEL = "cancel";
public static final String DTL_STATUS_WIP = "wip";
+ public static final String DTL_STATUS_NONE = "none";
/**
* 交易借方
diff --git a/src/main/kotlin/com/supwisdom/dlpay/api/service/impl/transaction_service_impl.kt b/src/main/kotlin/com/supwisdom/dlpay/api/service/impl/transaction_service_impl.kt
new file mode 100644
index 0000000..4359f7f
--- /dev/null
+++ b/src/main/kotlin/com/supwisdom/dlpay/api/service/impl/transaction_service_impl.kt
@@ -0,0 +1,282 @@
+package com.supwisdom.dlpay.api.service.impl
+
+import com.supwisdom.dlpay.api.TransactionBuilder
+import com.supwisdom.dlpay.api.TransactionResult
+import com.supwisdom.dlpay.api.dao.*
+import com.supwisdom.dlpay.api.domain.*
+import com.supwisdom.dlpay.api.service.TransactionService
+import com.supwisdom.dlpay.exception.TransactionProcessException
+import com.supwisdom.dlpay.framework.util.Subject
+import com.supwisdom.dlpay.framework.util.TradeDict
+import com.supwisdom.dlpay.framework.util.TradeErrorCode
+import org.springframework.beans.factory.annotation.Autowired
+import org.springframework.data.repository.findByIdOrNull
+import org.springframework.stereotype.Service
+import java.sql.SQLException
+
+@Service
+class TransactionServiceImpl : TransactionService {
+
+ companion object {
+ val INIT_DTL_STATUS = setOf(TradeDict.DTL_STATUS_INIT, TradeDict.DTL_STATUS_WIP)
+ }
+
+ @Autowired
+ lateinit var transactionMainDao: TransactionMainDao
+
+ @Autowired
+ lateinit var accoutDao: AccountDao
+
+ @Autowired
+ lateinit var persondtlDao: PersondtlDao
+
+ @Autowired
+ lateinit var shopdtlDao: ShopdtlDao
+
+ @Autowired
+ lateinit var subjectdtlDao: SubjectdtlDao
+
+ @Autowired
+ lateinit var debitCreditDtlDao: DebitCreditDtlDao
+
+ private fun builderRecords(builder: TransactionBuilder, status: String): TransactionResult {
+ // 记录三方的交易流水(个人,商户,科目)
+ try {
+ val result = TransactionResult("20000000000001", "20190520")
+ val transaction = TTransactionMain().apply {
+ this.refno = result.refno
+ this.accdate = result.accdate
+ }
+
+ if (builder.hasPerson()) {
+ TPersondtl().apply {
+ this.refno = result.refno
+ this.accdate = result.accdate
+ userid = builder.person().person.userid
+ userName = builder.person().person.accname
+ transdate = builder.transDate
+ transtime = builder.transTime
+ befbal = builder.person().person.availbal
+ amount = builder.person().amount
+ paytype = builder.person().paytype
+ payinfo = builder.person().payinfo
+ transcode = builder.transCode
+ oppositeAccNo = builder.person().opposite.getAccountNo()
+ oppositeAccName = builder.person().opposite.getAccountName()
+ this.status = status
+ }.also {
+ // save persondtl
+ persondtlDao.save(it)
+ result.persondtl = it
+ transaction.person = true
+ }
+ }
+ if (builder.hasShop()) {
+ TShopdtl().apply {
+ this.refno = result.refno
+ this.accdate = result.accdate
+ this.amount = builder.shop().amount
+ this.payInfo = builder.shop().payinfo
+ this.payType = builder.shop().paytype
+ this.transDate = builder.transDate
+ this.transTime = builder.transTime
+ this.tradeCode = builder.transCode
+ this.shopaccno = builder.shop().shopacc.shopaccno
+ this.shopname = builder.shop().shopacc.shopname
+ this.oppositeAccNo = builder.shop().opposite.getAccountNo()
+ this.oppositeAccName = builder.shop().opposite.getAccountName()
+ this.status = status
+ }.also {
+ // save shopdtl
+ shopdtlDao.save(it)
+ result.shopdtl = it
+ transaction.shop = true
+ }
+ }
+ if (builder.hasSubject()) {
+ // save subjectdtl
+ TSubjectdtl().apply {
+ this.refno = result.refno
+ this.accdate = result.accdate
+ this.amount = builder.subject().amount
+ this.payInfo = builder.subject().payinfo
+ this.payType = builder.subject().paytype
+ this.tradeCode = builder.transCode
+ this.transDate = builder.transDate
+ this.transTime = builder.transTime
+ this.oppositeAccNo = builder.subject().opposite.getAccountNo()
+ this.oppositeAccName = builder.subject().opposite.getAccountName()
+ this.status = status
+ }.also {
+ subjectdtlDao.save(it)
+ result.subjectdtl = it
+ transaction.subject = true
+ }
+ }
+
+ builder.getAllDetails().forEach { line ->
+ TDebitCreditDtl().apply {
+ this.refno = result.refno
+ this.accdate = result.accdate
+ this.seqno = line.seqno
+ this.draccno = line.debit.getAccountNo()
+ this.drsubjno = line.debit.getSubjectNo()
+ this.craccno = line.credit.getAccountNo()
+ this.crsubjno = line.credit.getSubjectNo()
+ this.amount = line.amount
+ this.summary = line.summary
+ }.also {
+ debitCreditDtlDao.save(it)
+ result.debitCreditLines.add(it)
+ }
+ }
+
+ val details = debitCreditDtlDao.findByRefno(result.refno)
+
+ if (builder.hasPerson()) {
+ sumBalanceFromDetails(details, builder.person().person.accno,
+ Subject.SUBJNO_PERSONAL_DEPOSIT).also {
+ if (result.persondtl.amount != it) {
+ throw TransactionProcessException(TradeErrorCode.INPUT_DATA_ERROR,
+ "输入金额错误,个人余额不符<${result.persondtl.amount}>")
+ }
+ }
+ }
+
+ if (builder.hasShop()) {
+ sumBalanceFromDetails(details, builder.shop().shopacc.shopaccno,
+ Subject.SUBJNO_MACHANT_INCOME).also {
+ if (result.shopdtl.amount != it) {
+ throw TransactionProcessException(TradeErrorCode.INPUT_DATA_ERROR,
+ "输入金额错误,商户余额不符<${result.shopdtl.amount}>")
+ }
+ }
+ }
+
+ if (builder.hasSubject()) {
+ sumBalanceFromDetails(details, builder.subject().subject.subjno,
+ result.subjectdtl.subjectno).also {
+ if (result.subjectdtl.amount != it) {
+ throw TransactionProcessException(TradeErrorCode.INPUT_DATA_ERROR,
+ "输入金额错误,科目余额不符<${result.subjectdtl.amount}>")
+ }
+ }
+ }
+
+ transactionMainDao.save(transaction)
+ return result
+ } catch (ex: SQLException) {
+ throw TransactionProcessException(TradeErrorCode.BUSINESS_DEAL_ERROR, ex.message)
+ }
+ }
+
+ override fun init(builder: TransactionBuilder): TransactionResult {
+ return builderRecords(builder, TradeDict.DTL_STATUS_INIT)
+ }
+
+ override fun wip(builder: TransactionBuilder): TransactionResult {
+ return builderRecords(builder, TradeDict.DTL_STATUS_WIP)
+ }
+
+ private fun sumBalanceFromDetails(details: List<TDebitCreditDtl>,
+ accno: String, subjno: String): Double {
+ return details.sumByDouble { line ->
+ if (line.crsubjno == subjno && line.craccno == accno) {
+ line.amount
+ } else if (line.crsubjno == subjno && line.craccno == accno) {
+ -line.amount
+ } else {
+ 0.0
+ }
+ }
+ }
+
+ override fun wip(refno: String) {
+ val transaction = transactionMainDao.findById(refno).let {
+ if (it.isPresent) it.get() else null
+ } ?: throw TransactionProcessException(TradeErrorCode.TRANSACTION_IS_FINISHED, "流水<$refno>参考号错误")
+
+ if (transaction.status != TradeDict.DTL_STATUS_INIT) {
+ throw TransactionProcessException(TradeErrorCode.TRANSACTION_IS_FINISHED, "流水<$refno>状态错误")
+ }
+ if (transaction.person) {
+ persondtlDao.findById(refno).let {
+ if (!it.isPresent) it.get() else null
+ }?.also {
+ if (it.status != TradeDict.DTL_STATUS_INIT) {
+ throw TransactionProcessException(TradeErrorCode.TRANSACTION_IS_FINISHED, "个人流水<$refno>状态错误")
+ }
+ it.status = TradeDict.DTL_STATUS_WIP
+ persondtlDao.save(it)
+ } ?: throw TransactionProcessException(TradeErrorCode.TRANSACTION_NOT_EXISTS, "个人流水<$refno>不存在")
+ }
+
+ if (transaction.shop) {
+ shopdtlDao.findById(refno).let {
+ if (it.isPresent) it.get() else null
+ }?.also {
+ if (it.status != TradeDict.DTL_STATUS_INIT) {
+ throw TransactionProcessException(TradeErrorCode.TRANSACTION_IS_FINISHED, "商户流水<$refno>状态错误")
+ }
+ it.status = TradeDict.DTL_STATUS_WIP
+ shopdtlDao.save(it)
+ } ?: throw TransactionProcessException(TradeErrorCode.TRANSACTION_NOT_EXISTS, "商户流水<$refno>不存在")
+ }
+
+ if (transaction.subject) {
+ subjectdtlDao.findById(refno).let {
+ if (it.isPresent) it.get() else null
+ }?.also {
+ if (it.status != TradeDict.DTL_STATUS_INIT) {
+ throw TransactionProcessException(TradeErrorCode.TRANSACTION_IS_FINISHED, "科目流水<$refno>状态错误")
+ }
+ it.status = TradeDict.DTL_STATUS_WIP
+ subjectdtlDao.save(it)
+ } ?: throw TransactionProcessException(TradeErrorCode.TRANSACTION_NOT_EXISTS, "科目流水<$refno>不存在")
+ }
+ transactionMainDao.save(transaction)
+ }
+
+ override fun fail(refno: String) {
+ val transaction = transactionMainDao.findByRefnoForUpdate(refno)
+ ?: throw TransactionProcessException(TradeErrorCode.TRANSACTION_IS_FINISHED, "流水<$refno>参考号错误")
+
+ val errorStatus = setOf(TradeDict.DTL_STATUS_SUCCESS, TradeDict.DTL_STATUS_CANCEL)
+ if (transaction.status in errorStatus) {
+ throw TransactionProcessException(TradeErrorCode.TRANSACTION_IS_FINISHED, "流水<$refno>状态错误")
+ }
+
+ transaction.status = TradeDict.DTL_STATUS_FAIL
+ transactionMainDao.save(transaction)
+ }
+
+ private fun decreseAccountBalance(account: TAccount, amount: Double) {
+
+ }
+
+ override fun success(refno: String) {
+ val transaction = transactionMainDao.findByRefnoForUpdate(refno)
+ ?: throw TransactionProcessException(TradeErrorCode.TRANSACTION_IS_FINISHED, "流水<$refno>参考号错误")
+
+ val errorStatus = setOf(TradeDict.DTL_STATUS_SUCCESS, TradeDict.DTL_STATUS_CANCEL)
+ if (transaction.status in errorStatus) {
+ throw TransactionProcessException(TradeErrorCode.TRANSACTION_IS_FINISHED, "流水<$refno>状态错误")
+ }
+ transaction.status = TradeDict.DTL_STATUS_FAIL
+ if (transaction.person) {
+ // update account balance
+ transaction.personDtl?.let {
+ accoutDao.updateAccountBalance("", 0.0, transaction.personDtl.amount)
+ } ?: throw TransactionProcessException(TradeErrorCode.TRANSACTION_NOT_EXISTS,
+ "个人<${transaction.personDtl.userid}>不存在")
+ }
+ if (transaction.shop) {
+ // update shop balance
+ }
+
+ if (transaction.subject) {
+ // update subject balance
+ }
+ transactionMainDao.save(transaction)
+ }
+}
\ No newline at end of file
diff --git a/src/main/kotlin/com/supwisdom/dlpay/api/service/transaction_service.kt b/src/main/kotlin/com/supwisdom/dlpay/api/service/transaction_service.kt
index c9e940a..b4407c1 100644
--- a/src/main/kotlin/com/supwisdom/dlpay/api/service/transaction_service.kt
+++ b/src/main/kotlin/com/supwisdom/dlpay/api/service/transaction_service.kt
@@ -1,8 +1,23 @@
package com.supwisdom.dlpay.api.service
import com.supwisdom.dlpay.api.TransactionBuilder
+import com.supwisdom.dlpay.api.TransactionResult
+import org.springframework.transaction.annotation.Propagation
+import org.springframework.transaction.annotation.Transactional
interface TransactionService {
-// fun
- fun transaction(builder: TransactionBuilder)
+ @Transactional(propagation = Propagation.REQUIRED, rollbackFor = [Exception::class])
+ fun init(builder: TransactionBuilder): TransactionResult
+
+ @Transactional(propagation = Propagation.REQUIRED, rollbackFor = [Exception::class])
+ fun wip(refno: String)
+
+ @Transactional(propagation = Propagation.REQUIRED, rollbackFor = [Exception::class])
+ fun wip(builder: TransactionBuilder): TransactionResult
+
+ @Transactional(propagation = Propagation.REQUIRED, rollbackFor = [Exception::class])
+ fun fail(refno: String)
+
+ @Transactional(propagation = Propagation.REQUIRED, rollbackFor = [Exception::class])
+ fun success(refno: String)
}
\ No newline at end of file
diff --git a/src/main/kotlin/com/supwisdom/dlpay/api/transaction_builder.kt b/src/main/kotlin/com/supwisdom/dlpay/api/transaction_builder.kt
index 0a7b86f..68c639a 100644
--- a/src/main/kotlin/com/supwisdom/dlpay/api/transaction_builder.kt
+++ b/src/main/kotlin/com/supwisdom/dlpay/api/transaction_builder.kt
@@ -1,54 +1,51 @@
package com.supwisdom.dlpay.api
-import com.supwisdom.dlpay.api.domain.TAccount
+import com.supwisdom.dlpay.api.domain.*
import com.supwisdom.dlpay.api.service.AccountUtilServcie
-import com.supwisdom.dlpay.api.service.PersonBalancePayService
+import com.supwisdom.dlpay.api.service.TransactionService
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.util.Subject
import com.supwisdom.dlpay.framework.util.TradeErrorCode
-class PersonTranactionBuilder(val parent: TransactionBuilder) {
- lateinit var person: TAccount
- var userid: String = ""
- var userName: String = ""
- var amount: Double = 0.0
- var summary: String = ""
- var oppositeAccno: String = ""
- var oppositeName: String = ""
- var oppositeType: String = ""
+open class SubTransactionBuilder(val parent: TransactionBuilder) {
+ var paytype: String = ""
+ get() {
+ return if (field.isEmpty()) parent.paytype else field
+ }
+
+ var payinfo: String = ""
+ get() {
+ return if (field.isEmpty()) parent.payinfo else field
+ }
fun and(): TransactionBuilder {
return parent
}
}
-class ShopTransactionBuilder(val parent: TransactionBuilder) {
- lateinit var shopacc: TShopacc
- var shopaccno: String = ""
- var shopname: String = ""
+class PersonTranactionBuilder(parent: TransactionBuilder, val person: TAccount)
+ : SubTransactionBuilder(parent) {
var amount: Double = 0.0
var summary: String = ""
- var oppositeAccno: String = ""
- var oppositeName: String = ""
- var oppositeType: String = ""
+ lateinit var opposite: AccountProxy<*>
- fun and(): TransactionBuilder {
- return parent
- }
}
-class SubjectTransactionBuilder(val parent: TransactionBuilder) {
- lateinit var subject: TSubject
- var subjno: String = ""
- var subjName: String = ""
+class ShopTransactionBuilder(parent: TransactionBuilder, val shopacc: TShopacc)
+ : SubTransactionBuilder(parent) {
var amount: Double = 0.0
var summary: String = ""
+ lateinit var opposite: AccountProxy<*>
+}
- fun and(): TransactionBuilder {
- return parent
- }
+class SubjectTransactionBuilder(parent: TransactionBuilder, val subject: TSubject)
+ : SubTransactionBuilder(parent) {
+ var amount: Double = 0.0
+ var summary: String = ""
+ lateinit var opposite: AccountProxy<*>
+
}
class AccountProxy<T>(private val accountObj: T) {
@@ -81,6 +78,10 @@
"不支持的账户类型, $accountObj")
}
}
+
+ fun get(): T {
+ return accountObj
+ }
}
data class DebitCreditLine(val debit: AccountProxy<*>, val credit: AccountProxy<*>,
@@ -99,26 +100,64 @@
var transTime: String = ""
var transCode: Int = 0 //交易码,各明细流水统一
var refno: String = ""
+ var paytype: String = ""
+ var payinfo: String = ""
var outtradeno: String = "" //第三方流水号
val extendMap = mutableMapOf<String, String>() //存调第三方需要的参数信息,存数据库 TB_USERDTL_BUSINESS
val resultMap = mutableMapOf<String, String>() //存调第三方结果数据
fun person(): PersonTranactionBuilder {
- return PersonTranactionBuilder(this).also {
- this.personBuilder = it
+ return this.personBuilder
+ }
+
+ fun person(account: TAccount): PersonTranactionBuilder {
+ return if (!this::personBuilder.isInitialized) {
+ PersonTranactionBuilder(this, account).also {
+ this.personBuilder = it
+ }
+ } else {
+ this.personBuilder
}
}
+ fun hasPerson(): Boolean {
+ return this::personBuilder.isInitialized
+ }
+
fun shop(): ShopTransactionBuilder {
- return ShopTransactionBuilder(this).also {
- this.shopBuilder = it
+ return this.shopBuilder
+ }
+
+ fun shop(shopacc: TShopacc): ShopTransactionBuilder {
+ return if (!this::shopBuilder.isInitialized) {
+ ShopTransactionBuilder(this, shopacc).also {
+ this.shopBuilder = it
+ }
+ } else {
+ this.shopBuilder
+ }
+ }
+
+ fun hasShop(): Boolean {
+ return this::shopBuilder.isInitialized
+ }
+
+ fun subject(acc: TSubject): SubjectTransactionBuilder {
+ return if (!this::subjectBuilder.isInitialized) {
+ SubjectTransactionBuilder(this, acc).also {
+ this.subjectBuilder = it
+ }
+ } else {
+ this.subjectBuilder
}
}
fun subject(): SubjectTransactionBuilder {
- return SubjectTransactionBuilder(this).also {
- this.subjectBuilder = it
- }
+ return this.subjectBuilder
+ }
+
+ fun hasSubject(): Boolean {
+ return this::subjectBuilder.isInitialized
}
fun <T, U> addDebitCreditRecord(debit: AccountProxy<T>, credit: AccountProxy<U>,
@@ -128,17 +167,36 @@
return this
}
- fun init(transactionService: PersonBalancePayService) {
-
+ fun getAllDetails(): List<DebitCreditLine> {
+ return debitCreditLines.toList()
}
+
+ fun init(transactionService: TransactionService): TransactionResult {
+ return transactionService.init(this)
+ }
+
+ fun wip(transactionService: TransactionService): TransactionResult {
+ return transactionService.wip(this)
+ }
+}
+
+class TransactionResult(val refno: String, val accdate: String) {
+
+ lateinit var persondtl: TPersondtl
+
+ lateinit var shopdtl: TShopdtl
+
+ lateinit var subjectdtl: TSubjectdtl
+
+ var debitCreditLines = mutableListOf<TDebitCreditDtl>()
}
class TransactionExample {
companion object {
- fun example(accountUtilServcie: AccountUtilServcie,
- service: PersonBalancePayService,
- userid: String, shopid: Int, amount: Int, manageFee: Int,
- transDate: String, transTime: String, payType: String) {
+ fun exampleInit(accountUtilServcie: AccountUtilServcie,
+ service: TransactionService,
+ userid: String, shopid: Int, amount: Int, manageFee: Int,
+ transDate: String, transTime: String, payType: String) {
val person = accountUtilServcie.readAccount(userid)
val shop = accountUtilServcie.readShopAcc(shopid)
@@ -147,14 +205,16 @@
this.transDate = transDate
this.transTime = transTime
this.transCode = 3001
- }.person().apply {
- this.person = person
+ this.payinfo = "POS消费"
+ this.paytype = payType
+ }.person(person).apply {
this.amount = (amount + manageFee) / 100.0 // 金额考虑减和加
this.summary = "POS消费"
- }.and().shop().apply {
- this.shopacc = shop
+ this.opposite = AccountProxy(shop)
+ }.and().shop(shop).apply {
this.amount = amount / 100.0 // 金额考虑减和加
this.summary = "POS消费"
+ this.opposite = AccountProxy(person)
}.and()
if (payType == "balance") {
@@ -162,10 +222,10 @@
amount / 100.0, "POS消费")
if (manageFee > 0) {
val subject = accountUtilServcie.readSubject("2001")
- builder.subject().apply {
- this.subject = subject
+ builder.subject(subject).apply {
this.amount = manageFee / 100.0 // 金额考虑减和加
this.summary = "POS消费搭伙费"
+ this.opposite = AccountProxy(person)
}.and().addDebitCreditRecord(AccountProxy(person), AccountProxy(subject), manageFee / 100.0,
"POS消费搭伙费")
}
@@ -179,10 +239,10 @@
if (manageFee > 0) {
accountUtilServcie.readSubject("2001").also {
- builder.subject().apply {
- this.subject = it
+ builder.subject(it).apply {
this.amount = manageFee / 100.0 // 金额考虑减和加
this.summary = "微信支付消费搭伙费"
+ this.opposite = AccountProxy(person)
}.and().addDebitCreditRecord(AccountProxy(person), AccountProxy(it), manageFee / 100.0,
"微信支付消费搭伙费")
}
@@ -190,7 +250,12 @@
} else {
throw TransactionCheckException(TradeErrorCode.INPUT_DATA_ERROR, "不支持的支付方式")
}
- builder.init(service)
+ val result = builder.init(service)
+ println(result.refno)
+ }
+
+ fun exampleConfirm(refno: String, transactionService: TransactionService) {
+ transactionService.success(refno)
}
}
}
\ No newline at end of file