临时提交
diff --git a/src/main/java/com/supwisdom/dlpay/api/domain/TPersondtl.java b/src/main/java/com/supwisdom/dlpay/api/domain/TPersondtl.java
new file mode 100644
index 0000000..deaeaf3
--- /dev/null
+++ b/src/main/java/com/supwisdom/dlpay/api/domain/TPersondtl.java
@@ -0,0 +1,245 @@
+package com.supwisdom.dlpay.api.domain;
+
+import javax.persistence.*;
+
+@Entity
+@Table(name = "TB_PERSONDTL",
+    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")})
+public class TPersondtl {
+
+  @Id
+  @Column(name = "REFNO", nullable = false, length = 32)
+  private String refno; //流水号
+
+  @Column(name = "ACCDATE", length = 8)
+  private String accdate; //记账日期
+
+  @Column(name = "USERID", length = 32)
+  private String userid;  //用户ID,或账号
+
+  @Column(name = "TRANSDATE", length = 8)
+  private String transdate;
+
+  @Column(name = "TRANSTIME", length = 6)
+  private String transtime;
+
+  @Column(name = "STATUS", length = 20)
+  private String status;
+
+  @Column(name = "BEFBAL", precision = 9, scale = 2)
+  private Double befbal;
+
+  @Column(name = "amount", precision = 9, scale = 2)
+  private Double amount; //实际付款金额
+
+  @Column(name = "PAYTYPE", length = 20)
+  private String paytype; //支付方式 balance,wechat,alipay
+
+  @Column(name = "PAYINFO", length = 200)
+  private String payinfo; //记录支付信息备用字段
+
+  @Column(name = "TRANSCODE", precision = 4)
+  private Integer transcode;
+
+  @Column(name = "TRANSDESC", length = 240)
+  private String transdesc; //交易描述
+
+  @Column(name = "OUTTRADENO", length = 60)
+  private String outtradeno; //第三方流水号
+
+  @Column(name = "OPPOSITEACCNO", length = 20)
+  private String oppositeAccNo;
+
+  @Column(name = "OPERID", precision = 9)
+  private Integer operid; //操作员ID
+
+  @Column(name = "REVERSE_FLAG", nullable = false, precision = 1)
+  private String reverseFlag = "none"; //none, cancel, reversed
+
+  @Column(name = "REVERSE_AMOUNT", precision = 9, scale = 2)
+  private Double reverseAmount = 0D; //撤销金额填写
+
+  @Column(name = "TRADEFLAG", nullable = false, precision = 1)
+  private Integer tradeflag; //1-充值;2-消费
+
+  @Column(name = "REMARK", length = 240)
+  private String remark;
+
+  @Column(name = "CREATETIME", length = 14)
+  private String createtime;  //创建时间
+
+  @Column(name = "ENDTIME", length = 14)
+  private String endtime;  //支付结束时间
+
+  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 getUserid() {
+    return userid;
+  }
+
+  public void setUserid(String userid) {
+    this.userid = userid;
+  }
+
+  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 getStatus() {
+    return status;
+  }
+
+  public void setStatus(String status) {
+    this.status = status;
+  }
+
+  public Double getBefbal() {
+    return befbal;
+  }
+
+  public void setBefbal(Double befbal) {
+    this.befbal = befbal;
+  }
+
+  public Double getAmount() {
+    return amount;
+  }
+
+  public void setAmount(Double amount) {
+    this.amount = amount;
+  }
+
+  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 Integer getTranscode() {
+    return transcode;
+  }
+
+  public void setTranscode(Integer transcode) {
+    this.transcode = transcode;
+  }
+
+  public String getTransdesc() {
+    return transdesc;
+  }
+
+  public void setTransdesc(String transdesc) {
+    this.transdesc = transdesc;
+  }
+
+  public String getOuttradeno() {
+    return outtradeno;
+  }
+
+  public void setOuttradeno(String outtradeno) {
+    this.outtradeno = outtradeno;
+  }
+
+  public String getOppositeAccNo() {
+    return oppositeAccNo;
+  }
+
+  public void setOppositeAccNo(String oppositeAccNo) {
+    this.oppositeAccNo = oppositeAccNo;
+  }
+
+  public Integer getOperid() {
+    return operid;
+  }
+
+  public void setOperid(Integer operid) {
+    this.operid = operid;
+  }
+
+  public String getReverseFlag() {
+    return reverseFlag;
+  }
+
+  public void setReverseFlag(String reverseFlag) {
+    this.reverseFlag = reverseFlag;
+  }
+
+  public Double getReverseAmount() {
+    return reverseAmount;
+  }
+
+  public void setReverseAmount(Double reverseAmount) {
+    this.reverseAmount = reverseAmount;
+  }
+
+  public Integer getTradeflag() {
+    return tradeflag;
+  }
+
+  public void setTradeflag(Integer tradeflag) {
+    this.tradeflag = tradeflag;
+  }
+
+  public String getRemark() {
+    return remark;
+  }
+
+  public void setRemark(String remark) {
+    this.remark = remark;
+  }
+
+  public String getCreatetime() {
+    return createtime;
+  }
+
+  public void setCreatetime(String createtime) {
+    this.createtime = createtime;
+  }
+
+  public String getEndtime() {
+    return endtime;
+  }
+
+  public void setEndtime(String endtime) {
+    this.endtime = endtime;
+  }
+}
diff --git a/src/main/java/com/supwisdom/dlpay/api/domain/TShopdtl.java b/src/main/java/com/supwisdom/dlpay/api/domain/TShopdtl.java
new file mode 100644
index 0000000..2649d02
--- /dev/null
+++ b/src/main/java/com/supwisdom/dlpay/api/domain/TShopdtl.java
@@ -0,0 +1,119 @@
+package com.supwisdom.dlpay.api.domain;
+
+import javax.persistence.Column;
+import javax.persistence.Id;
+import javax.persistence.Table;
+
+@Table(name = "TB_SHOPDTL")
+public class TShopdtl {
+  @Id
+  @Column(name = "refno", length = 32, nullable = false)
+  private String refno;
+
+  @Column(name = "accdate", length = 8, nullable = false)
+  private String accdate;
+
+  @Column(name = "shopaccno", length = 10, nullable = false)
+  private String shopaccno;
+
+  @Column(name = "shopname", length = 200)
+  private String shopname;
+
+  @Column(name = "amount", scale = 2, precision = 15)
+  private Double amount;
+
+  @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 = "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 getShopaccno() {
+    return shopaccno;
+  }
+
+  public void setShopaccno(String shopaccno) {
+    this.shopaccno = shopaccno;
+  }
+
+  public String getShopname() {
+    return shopname;
+  }
+
+  public void setShopname(String shopname) {
+    this.shopname = shopname;
+  }
+
+  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 getStatus() {
+    return status;
+  }
+
+  public void setStatus(String status) {
+    this.status = status;
+  }
+}
diff --git a/src/main/kotlin/com/supwisdom/dlpay/api/service/consume_pay_service.kt b/src/main/kotlin/com/supwisdom/dlpay/api/service/consume_pay_service.kt
index 54d8475..9aa7d21 100644
--- a/src/main/kotlin/com/supwisdom/dlpay/api/service/consume_pay_service.kt
+++ b/src/main/kotlin/com/supwisdom/dlpay/api/service/consume_pay_service.kt
@@ -4,12 +4,12 @@
 import org.springframework.transaction.annotation.Transactional
 
 interface ConsumePayService{
-    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = arrayOf(Exception::class))
+    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = [Exception::class])
     fun checkShopPaytype(shopaccno: String, paytype: String, anonymousflag: Boolean? = false): Boolean
 
-    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = arrayOf(Exception::class))
+    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = [Exception::class])
     fun getPaytypeConfig(paytype: String, shopaccno: String, anonymousflag: Boolean? = false, ignoreStatus: Boolean? = false): Map<String, String?>
 
-    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = arrayOf(Exception::class))
+    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = [Exception::class])
     fun getUserdtlExtendParamMap(refno: String): Map<String, String>
 }
\ 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
new file mode 100644
index 0000000..c9e940a
--- /dev/null
+++ b/src/main/kotlin/com/supwisdom/dlpay/api/service/transaction_service.kt
@@ -0,0 +1,8 @@
+package com.supwisdom.dlpay.api.service
+
+import com.supwisdom.dlpay.api.TransactionBuilder
+
+interface TransactionService {
+//    fun
+    fun transaction(builder: TransactionBuilder)
+}
\ 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 32ced96..0a7b86f 100644
--- a/src/main/kotlin/com/supwisdom/dlpay/api/transaction_builder.kt
+++ b/src/main/kotlin/com/supwisdom/dlpay/api/transaction_builder.kt
@@ -1,9 +1,16 @@
 package com.supwisdom.dlpay.api
 
+import com.supwisdom.dlpay.api.domain.TAccount
 import com.supwisdom.dlpay.api.service.AccountUtilServcie
 import com.supwisdom.dlpay.api.service.PersonBalancePayService
+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
@@ -18,6 +25,7 @@
 }
 
 class ShopTransactionBuilder(val parent: TransactionBuilder) {
+    lateinit var shopacc: TShopacc
     var shopaccno: String = ""
     var shopname: String = ""
     var amount: Double = 0.0
@@ -32,6 +40,7 @@
 }
 
 class SubjectTransactionBuilder(val parent: TransactionBuilder) {
+    lateinit var subject: TSubject
     var subjno: String = ""
     var subjName: String = ""
     var amount: Double = 0.0
@@ -42,17 +51,55 @@
     }
 }
 
+class AccountProxy<T>(private val accountObj: T) {
+    fun getAccountNo(): String {
+        return when (accountObj) {
+            is TAccount -> (accountObj as TAccount).accno
+            is TShopacc -> (accountObj as TShopacc).shopaccno
+            is TSubject -> (accountObj as TSubject).subjno
+            else -> throw TransactionCheckException(TradeErrorCode.INPUT_DATA_ERROR,
+                    "不支持的账户类型, $accountObj")
+        }
+    }
+
+    fun getSubjectNo(): String {
+        return when (accountObj) {
+            is TAccount -> (accountObj as TAccount).subjno
+            is TShopacc -> (accountObj as TShopacc).subjno
+            is TSubject -> (accountObj as TSubject).subjno
+            else -> throw TransactionCheckException(TradeErrorCode.INPUT_DATA_ERROR,
+                    "不支持的账户类型, $accountObj")
+        }
+    }
+
+    fun getAccountName(): String {
+        return when (accountObj) {
+            is TAccount -> (accountObj as TAccount).accname
+            is TShopacc -> (accountObj as TShopacc).shopname
+            is TSubject -> (accountObj as TSubject).subjname
+            else -> throw TransactionCheckException(TradeErrorCode.INPUT_DATA_ERROR,
+                    "不支持的账户类型, $accountObj")
+        }
+    }
+}
+
+data class DebitCreditLine(val debit: AccountProxy<*>, val credit: AccountProxy<*>,
+                           val amount: Double, val summary: String,
+                           val seqno: Int)
+
 // 在 constructor 中加入 service 接口
 class TransactionBuilder {
     private lateinit var personBuilder: PersonTranactionBuilder
     private lateinit var shopBuilder: ShopTransactionBuilder
     private lateinit var subjectBuilder: SubjectTransactionBuilder
 
+    private val debitCreditLines = mutableListOf<DebitCreditLine>()
+
     var transDate: String = ""
     var transTime: String = ""
     var transCode: Int = 0 //交易码,各明细流水统一
     var refno: String = ""
-    var outtradeno:String="" //第三方流水号
+    var outtradeno: String = "" //第三方流水号
     val extendMap = mutableMapOf<String, String>() //存调第三方需要的参数信息,存数据库 TB_USERDTL_BUSINESS
     val resultMap = mutableMapOf<String, String>() //存调第三方结果数据
 
@@ -74,6 +121,13 @@
         }
     }
 
+    fun <T, U> addDebitCreditRecord(debit: AccountProxy<T>, credit: AccountProxy<U>,
+                                    amount: Double, summary: String): TransactionBuilder {
+        debitCreditLines.add(DebitCreditLine(debit, credit, amount, summary,
+                debitCreditLines.size + 1))
+        return this
+    }
+
     fun init(transactionService: PersonBalancePayService) {
 
     }
@@ -84,7 +138,7 @@
         fun example(accountUtilServcie: AccountUtilServcie,
                     service: PersonBalancePayService,
                     userid: String, shopid: Int, amount: Int, manageFee: Int,
-                    transDate: String, transTime: String) {
+                    transDate: String, transTime: String, payType: String) {
 
             val person = accountUtilServcie.readAccount(userid)
             val shop = accountUtilServcie.readShopAcc(shopid)
@@ -94,27 +148,49 @@
                 this.transTime = transTime
                 this.transCode = 3001
             }.person().apply {
-                this.userid = userid // 可以再优化,直接用 person 对象
-                this.userName = person.accname
+                this.person = person
                 this.amount = (amount + manageFee) / 100.0 // 金额考虑减和加
                 this.summary = "POS消费"
             }.and().shop().apply {
-                this.shopaccno = shop.shopaccno  // 可以再优化,直接用 shop 对象
-                this.shopname = shop.shopname
+                this.shopacc = shop
                 this.amount = amount / 100.0 // 金额考虑减和加
                 this.summary = "POS消费"
             }.and()
-            if (manageFee > 0) {
-                builder.subject().apply {
+
+            if (payType == "balance") {
+                builder.addDebitCreditRecord(AccountProxy(person), AccountProxy(shop),
+                        amount / 100.0, "POS消费")
+                if (manageFee > 0) {
                     val subject = accountUtilServcie.readSubject("2001")
-                    this.subjno = subject.subjno
-                    this.subjName = subject.subjname
-                    this.amount = manageFee / 100.0 // 金额考虑减和加
-                    this.summary = "POS消费搭伙费"
+                    builder.subject().apply {
+                        this.subject = subject
+                        this.amount = manageFee / 100.0 // 金额考虑减和加
+                        this.summary = "POS消费搭伙费"
+                    }.and().addDebitCreditRecord(AccountProxy(person), AccountProxy(subject), manageFee / 100.0,
+                            "POS消费搭伙费")
                 }
+            } else if (payType == "wechat") {
+                accountUtilServcie.readSubject(Subject.SUBJNO_PAY_WECHAT).also {
+                    builder.addDebitCreditRecord(AccountProxy(it), AccountProxy(person),
+                            (amount + manageFee) / 100.0, "微信转账")
+                            .addDebitCreditRecord(AccountProxy(person), AccountProxy(shop),
+                                    amount / 100.0, "微信支付消费")
+                }
+
+                if (manageFee > 0) {
+                    accountUtilServcie.readSubject("2001").also {
+                        builder.subject().apply {
+                            this.subject = it
+                            this.amount = manageFee / 100.0 // 金额考虑减和加
+                            this.summary = "微信支付消费搭伙费"
+                        }.and().addDebitCreditRecord(AccountProxy(person), AccountProxy(it), manageFee / 100.0,
+                                "微信支付消费搭伙费")
+                    }
+                }
+            } else {
+                throw TransactionCheckException(TradeErrorCode.INPUT_DATA_ERROR, "不支持的支付方式")
             }
             builder.init(service)
-
         }
     }
 }
\ No newline at end of file