实现qrcode聚合支付框架
diff --git a/payapi/src/main/java/com/supwisdom/dlpay/agent/AgentCode.java b/payapi/src/main/java/com/supwisdom/dlpay/agent/AgentCode.java
index 66c1579..950f338 100644
--- a/payapi/src/main/java/com/supwisdom/dlpay/agent/AgentCode.java
+++ b/payapi/src/main/java/com/supwisdom/dlpay/agent/AgentCode.java
@@ -9,6 +9,7 @@
   REQUIRE_QUERY("require_query", "交易未完成,请查询"),
   WAIT_NOTIFY("wait_notify", "交易已发起,等待通知"),
   SHORT_OF_BALANCE("short_of_balance", "余额不足"),
+  NOT_SUPPORT("not_support", "不支持功能"),
   COMMON_ERROR("common_error", "其它错误");
 
   AgentCode(String code, String msg) {
diff --git a/payapi/src/main/java/com/supwisdom/dlpay/agent/AgentPayService.java b/payapi/src/main/java/com/supwisdom/dlpay/agent/AgentPayService.java
index 5ba80d6..9b10dfc 100644
--- a/payapi/src/main/java/com/supwisdom/dlpay/agent/AgentPayService.java
+++ b/payapi/src/main/java/com/supwisdom/dlpay/agent/AgentPayService.java
@@ -3,6 +3,8 @@
 import com.supwisdom.dlpay.api.domain.TTransactionMain;
 
 public interface AgentPayService {
+  AgentResponse auth(String agentid, String billno);
+
   AgentResponse pay(TTransactionMain transaction);
 
   AgentResponse cancel(TTransactionMain transaction);
diff --git a/payapi/src/main/java/com/supwisdom/dlpay/agent/dao/QrcodePatternDao.java b/payapi/src/main/java/com/supwisdom/dlpay/agent/dao/QrcodePatternDao.java
index 54da64e..d63e9d0 100644
--- a/payapi/src/main/java/com/supwisdom/dlpay/agent/dao/QrcodePatternDao.java
+++ b/payapi/src/main/java/com/supwisdom/dlpay/agent/dao/QrcodePatternDao.java
@@ -3,5 +3,8 @@
 import com.supwisdom.dlpay.agent.domain.QrcodePattern;
 import org.springframework.data.repository.CrudRepository;
 
+import java.util.List;
+
 public interface QrcodePatternDao extends CrudRepository<QrcodePattern, Integer> {
+  List<QrcodePattern> findByTenantid(String tenantid);
 }
diff --git a/payapi/src/main/java/com/supwisdom/dlpay/agent/dao/QrcodePayTransDao.java b/payapi/src/main/java/com/supwisdom/dlpay/agent/dao/QrcodePayTransDao.java
index 1db85a8..9cc6730 100644
--- a/payapi/src/main/java/com/supwisdom/dlpay/agent/dao/QrcodePayTransDao.java
+++ b/payapi/src/main/java/com/supwisdom/dlpay/agent/dao/QrcodePayTransDao.java
@@ -9,5 +9,8 @@
 public interface QrcodePayTransDao extends CrudRepository<QrcodePayTrans, String> {
   QrcodePayTrans findByRefnoAndTenantid(String refno, String tenantid);
 
+  QrcodePayTrans findByAgentMerchIdAndHostdateAndBillnoAAndTenantid(String mechid, String host,
+                                                                    String billno, String tenantid);
+
   void deleteByRefnoAndTenantid(String refno, String tenantid);
 }
diff --git a/payapi/src/main/java/com/supwisdom/dlpay/agent/domain/QrcodePattern.java b/payapi/src/main/java/com/supwisdom/dlpay/agent/domain/QrcodePattern.java
index 2949c61..c74bbd3 100644
--- a/payapi/src/main/java/com/supwisdom/dlpay/agent/domain/QrcodePattern.java
+++ b/payapi/src/main/java/com/supwisdom/dlpay/agent/domain/QrcodePattern.java
@@ -20,6 +20,10 @@
   @NotNull
   private String pattern;
 
+  @Column(name = "tenantid", length = 20)
+  @NotNull
+  private String tenantid;
+
   public Integer getId() {
     return id;
   }
@@ -43,4 +47,12 @@
   public void setPattern(String pattern) {
     this.pattern = pattern;
   }
+
+  public String getTenantid() {
+    return tenantid;
+  }
+
+  public void setTenantid(String tenantid) {
+    this.tenantid = tenantid;
+  }
 }
diff --git a/payapi/src/main/java/com/supwisdom/dlpay/agent/domain/QrcodePayTrans.java b/payapi/src/main/java/com/supwisdom/dlpay/agent/domain/QrcodePayTrans.java
index e5ccb69..a6619a4 100644
--- a/payapi/src/main/java/com/supwisdom/dlpay/agent/domain/QrcodePayTrans.java
+++ b/payapi/src/main/java/com/supwisdom/dlpay/agent/domain/QrcodePayTrans.java
@@ -7,26 +7,59 @@
 @Entity
 @Table(name = "tb_qrcode_pay_trans",
     indexes = {@Index(name = "qrcode_pay_trans_idx", columnList = "qrcode, sourcetype"),
-        @Index(name = "qrcode_pay_trans_idx2", columnList = "tenantid")})
+        @Index(name = "qrcode_pay_trans_idx2", columnList = "agent_merch_id, billno, tenantid", unique = true),
+        @Index(name = "qrcode_pay_trans_idx3", columnList = "agent_merch_id, billno")})
 public class QrcodePayTrans {
   @Id
+  @SequenceGenerator(name = "qrcode_pay_trans_id", sequenceName = "SEQ_QRCODE_PAY_TRANS", allocationSize = 1, initialValue = 1)
+  @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "qrcode_pay_trans_id")
+  @Column(name = "id")
+  private int id;
+
+  @Column(name = "agent_merch_id", length = 30)
   @NotNull
+  private String agentMerchId;
+
+  @Column(name = "billno", length = 32)
+  @NotNull
+  private String billno;
+
+  @Column(name = "hostdate", length = 8)
+  @NotNull
+  private String hostdate;
+
+  @Column(name = "refno", length = 32)
   private String refno;
+
   @Column(name = "agent_user_id", length = 200)
   private String agentUserId;
+
   @Column(name = "qrcode", length = 256)
   @NotNull
   private String qrcode;
+
+  @Column(name = "anonymous")
+  @NotNull
+  private boolean anonymous;
+
   @Column(name = "sourcetype", length = 30)
   @NotNull
   private String sourceType;
+
+  @Column(name = "userid", length = 40)
+  private String userid;
+
   @NotNull
   @Column(name = "create_time")
   private Timestamp create_time;
+
   @NotNull
   @Column(name = "tenantid", length = 20)
   private String tenantid;
 
+  public QrcodePayTrans() {
+  }
+
   public String getRefno() {
     return refno;
   }
@@ -74,4 +107,52 @@
   public void setSourceType(String sourceType) {
     this.sourceType = sourceType;
   }
+
+  public int getId() {
+    return id;
+  }
+
+  public void setId(int id) {
+    this.id = id;
+  }
+
+  public String getAgentMerchId() {
+    return agentMerchId;
+  }
+
+  public void setAgentMerchId(String agentMerchId) {
+    this.agentMerchId = agentMerchId;
+  }
+
+  public String getBillno() {
+    return billno;
+  }
+
+  public void setBillno(String billno) {
+    this.billno = billno;
+  }
+
+  public String getHostdate() {
+    return hostdate;
+  }
+
+  public void setHostdate(String hostdate) {
+    this.hostdate = hostdate;
+  }
+
+  public boolean isAnonymous() {
+    return anonymous;
+  }
+
+  public void setAnonymous(boolean anonymous) {
+    this.anonymous = anonymous;
+  }
+
+  public String getUserid() {
+    return userid;
+  }
+
+  public void setUserid(String userid) {
+    this.userid = userid;
+  }
 }
diff --git a/payapi/src/main/java/com/supwisdom/dlpay/agent/service/AgentServiceProxy.java b/payapi/src/main/java/com/supwisdom/dlpay/agent/service/AgentServiceProxy.java
index d3fb4f4..37b76cd 100644
--- a/payapi/src/main/java/com/supwisdom/dlpay/agent/service/AgentServiceProxy.java
+++ b/payapi/src/main/java/com/supwisdom/dlpay/agent/service/AgentServiceProxy.java
@@ -3,6 +3,7 @@
 import com.supwisdom.dlpay.agent.dao.QrcodePayTransDao;
 import com.supwisdom.dlpay.agent.domain.QrcodePattern;
 import com.supwisdom.dlpay.agent.domain.QrcodePayTrans;
+import com.supwisdom.dlpay.framework.service.SystemUtilService;
 import com.supwisdom.dlpay.framework.tenant.TenantContext;
 import org.springframework.stereotype.Service;
 
@@ -14,28 +15,32 @@
 
 @Service
 public class AgentServiceProxy {
-  private final QrcodePayTransDao alipayTransDao;
+  private final QrcodePayTransDao qrcodeTransDao;
   private final QrcodePatternService qrcodePatternService;
+  private final SystemUtilService systemUtilService;
 
-  public AgentServiceProxy(QrcodePayTransDao alipayTransDao,
-                           QrcodePatternService qrcodePatternService) {
-    this.alipayTransDao = alipayTransDao;
+  public AgentServiceProxy(QrcodePayTransDao qrcodeTransDao,
+                           QrcodePatternService qrcodePatternService,
+                           SystemUtilService systemUtilService) {
+    this.qrcodeTransDao = qrcodeTransDao;
     this.qrcodePatternService = qrcodePatternService;
+    this.systemUtilService = systemUtilService;
   }
 
   public QrcodePayTrans qrcodePayTransFindByRefno(String refno) {
-    return alipayTransDao.findByRefnoAndTenantid(refno, TenantContext.getTenantSchema());
+    return qrcodeTransDao.findByRefnoAndTenantid(refno, TenantContext.getTenantSchema());
+  }
+
+  public QrcodePayTrans qrcodePayTransFindByMerchIdAndBillno(String merchid, String billno) {
+    return qrcodeTransDao.findByAgentMerchIdAndHostdateAndBillnoAAndTenantid(merchid,
+        systemUtilService.getSysdatetime().getHostdate(), billno, TenantContext.getTenantSchema());
   }
 
   public QrcodePayTrans qrcodePayTransSaveOrUpdate(QrcodePayTrans bean) {
     if (bean.getTenantid().isEmpty()) {
       bean.setTenantid(TenantContext.getTenantSchema());
     }
-    return alipayTransDao.save(bean);
-  }
-
-  public void qrcodePayTransDelete(String refno) {
-    alipayTransDao.deleteByRefnoAndTenantid(refno, TenantContext.getTenantSchema());
+    return qrcodeTransDao.save(bean);
   }
 
   public QrcodePattern qrcodeMatch(String code) {
diff --git a/payapi/src/main/java/com/supwisdom/dlpay/agent/service/impl/QrcodePatternServiceImpl.java b/payapi/src/main/java/com/supwisdom/dlpay/agent/service/impl/QrcodePatternServiceImpl.java
index d2ad391..2d7ad9f 100644
--- a/payapi/src/main/java/com/supwisdom/dlpay/agent/service/impl/QrcodePatternServiceImpl.java
+++ b/payapi/src/main/java/com/supwisdom/dlpay/agent/service/impl/QrcodePatternServiceImpl.java
@@ -3,11 +3,11 @@
 import com.supwisdom.dlpay.agent.dao.QrcodePatternDao;
 import com.supwisdom.dlpay.agent.domain.QrcodePattern;
 import com.supwisdom.dlpay.agent.service.QrcodePatternService;
+import com.supwisdom.dlpay.framework.tenant.TenantContext;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.cache.annotation.Cacheable;
 import org.springframework.stereotype.Service;
 
-import java.util.ArrayList;
 import java.util.List;
 
 @Service
@@ -16,10 +16,8 @@
   private QrcodePatternDao qrcodePatternDao;
 
   @Override
-  @Cacheable(cacheNames = "qrcode_pattern_cache")
+  @Cacheable(cacheNames = "qrcode_pattern_cache", key = "@tenantHolder.genKey('qrcode_pattern')")
   public List<QrcodePattern> getAllQrCodePattern() {
-    List<QrcodePattern> list = new ArrayList<>();
-    qrcodePatternDao.findAll().forEach(list::add);
-    return list;
+    return qrcodePatternDao.findByTenantid(TenantContext.getTenantSchema());
   }
 }
diff --git a/payapi/src/main/kotlin/com/supwisdom/dlpay/agent/service/alipay_service.kt b/payapi/src/main/kotlin/com/supwisdom/dlpay/agent/service/alipay_service.kt
index e32f7d8..a89e2e1 100644
--- a/payapi/src/main/kotlin/com/supwisdom/dlpay/agent/service/alipay_service.kt
+++ b/payapi/src/main/kotlin/com/supwisdom/dlpay/agent/service/alipay_service.kt
@@ -1,5 +1,6 @@
 package com.supwisdom.dlpay.agent.service
 
+import com.supwisdom.dlpay.agent.AgentCode
 import com.supwisdom.dlpay.agent.AgentPayService
 import com.supwisdom.dlpay.agent.AgentResponse
 import com.supwisdom.dlpay.api.domain.TTransactionMain
@@ -7,6 +8,12 @@
 
 @Component("alipayAgent")
 class AlipayAgentService : AgentPayService {
+    override fun auth(shopaccno: String?, billno: String?): AgentResponse {
+        return AgentResponse().apply {
+            this.code = AgentCode.NOT_SUPPORT
+        }
+    }
+
     override fun pay(transaction: TTransactionMain): AgentResponse {
         TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
     }
diff --git a/payapi/src/main/kotlin/com/supwisdom/dlpay/agent/service/balance_service.kt b/payapi/src/main/kotlin/com/supwisdom/dlpay/agent/service/balance_service.kt
index 592153a..6852f9b 100644
--- a/payapi/src/main/kotlin/com/supwisdom/dlpay/agent/service/balance_service.kt
+++ b/payapi/src/main/kotlin/com/supwisdom/dlpay/agent/service/balance_service.kt
@@ -15,6 +15,12 @@
         agentRefno = ""
     }
 
+    override fun auth(shopaccno: String?, billno: String?): AgentResponse {
+        return AgentResponse().apply {
+            this.code = AgentCode.NOT_SUPPORT
+        }
+    }
+
     override fun pay(transaction: TTransactionMain): AgentResponse {
         return responseCode
     }
diff --git a/payapi/src/main/kotlin/com/supwisdom/dlpay/agent/service/citizencard_service.kt b/payapi/src/main/kotlin/com/supwisdom/dlpay/agent/service/citizencard_service.kt
index 7497567..5136d37 100644
--- a/payapi/src/main/kotlin/com/supwisdom/dlpay/agent/service/citizencard_service.kt
+++ b/payapi/src/main/kotlin/com/supwisdom/dlpay/agent/service/citizencard_service.kt
@@ -43,6 +43,12 @@
                 YnrccRespCode(code, msg ?: "未知"))
     }
 
+    override fun auth(shopaccno: String?, billno: String?): AgentResponse {
+        return AgentResponse().apply {
+            this.code = AgentCode.NOT_SUPPORT
+        }
+    }
+
     override fun pay(transaction: TTransactionMain): AgentResponse {
         val resp = citizencardPayService.cardPay(transaction.shopDtl.shopaccno, transaction.personDtl.userid, transaction.accdate,
                 MoneyUtil.YuanToFen(transaction.personDtl.amount), transaction.refno)
diff --git a/payapi/src/main/kotlin/com/supwisdom/dlpay/agent/service/swykt_service.kt b/payapi/src/main/kotlin/com/supwisdom/dlpay/agent/service/swykt_service.kt
index 7f96f22..165c4c7 100644
--- a/payapi/src/main/kotlin/com/supwisdom/dlpay/agent/service/swykt_service.kt
+++ b/payapi/src/main/kotlin/com/supwisdom/dlpay/agent/service/swykt_service.kt
@@ -1,5 +1,6 @@
 package com.supwisdom.dlpay.agent.service
 
+import com.supwisdom.dlpay.agent.AgentCode
 import com.supwisdom.dlpay.agent.AgentPayService
 import com.supwisdom.dlpay.agent.AgentResponse
 import com.supwisdom.dlpay.api.bean.BaseResp
@@ -33,6 +34,12 @@
 
 @Component("swyktv5Agent")
 class SWYktV5AgentService : AgentPayService {
+    override fun auth(shopaccno: String?, billno: String?): AgentResponse {
+        return AgentResponse().apply {
+            this.code = AgentCode.NOT_SUPPORT
+        }
+    }
+
     override fun pay(transaction: TTransactionMain?): AgentResponse {
         TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
     }
diff --git a/payapi/src/main/kotlin/com/supwisdom/dlpay/agent/service/wanxiao_service.kt b/payapi/src/main/kotlin/com/supwisdom/dlpay/agent/service/wanxiao_service.kt
index 06aa907..eb77875 100644
--- a/payapi/src/main/kotlin/com/supwisdom/dlpay/agent/service/wanxiao_service.kt
+++ b/payapi/src/main/kotlin/com/supwisdom/dlpay/agent/service/wanxiao_service.kt
@@ -1,5 +1,6 @@
 package com.supwisdom.dlpay.agent.service
 
+import com.supwisdom.dlpay.agent.AgentCode
 import com.supwisdom.dlpay.agent.AgentPayService
 import com.supwisdom.dlpay.agent.AgentResponse
 import com.supwisdom.dlpay.api.domain.TTransactionMain
@@ -7,6 +8,12 @@
 
 @Component("wanxiaoAgent")
 class WanxiaoAgentService : AgentPayService {
+    override fun auth(shopaccno: String?, billno: String?): AgentResponse {
+        return AgentResponse().apply {
+            this.code = AgentCode.NOT_SUPPORT
+        }
+    }
+
     override fun pay(transaction: TTransactionMain?): AgentResponse {
         TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
     }
diff --git a/payapi/src/main/kotlin/com/supwisdom/dlpay/agent/service/weichat_service.kt b/payapi/src/main/kotlin/com/supwisdom/dlpay/agent/service/weichat_service.kt
index a6869b5..dc748d7 100644
--- a/payapi/src/main/kotlin/com/supwisdom/dlpay/agent/service/weichat_service.kt
+++ b/payapi/src/main/kotlin/com/supwisdom/dlpay/agent/service/weichat_service.kt
@@ -1,5 +1,6 @@
 package com.supwisdom.dlpay.agent.service
 
+import com.supwisdom.dlpay.agent.AgentCode
 import com.supwisdom.dlpay.agent.AgentPayService
 import com.supwisdom.dlpay.agent.AgentResponse
 import com.supwisdom.dlpay.api.domain.TTransactionMain
@@ -7,6 +8,12 @@
 
 @Component("wechatpayAgent")
 class WeChatPayAgentService : AgentPayService {
+    override fun auth(shopaccno: String?, billno: String?): AgentResponse {
+        return AgentResponse().apply {
+            this.code = AgentCode.NOT_SUPPORT
+        }
+    }
+
     override fun pay(transaction: TTransactionMain?): AgentResponse {
         TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
     }
diff --git a/payapi/src/main/kotlin/com/supwisdom/dlpay/api/controller/consume_api_controller.kt b/payapi/src/main/kotlin/com/supwisdom/dlpay/api/controller/consume_api_controller.kt
index a8b6e05..fdf77bb 100644
--- a/payapi/src/main/kotlin/com/supwisdom/dlpay/api/controller/consume_api_controller.kt
+++ b/payapi/src/main/kotlin/com/supwisdom/dlpay/api/controller/consume_api_controller.kt
@@ -2,6 +2,8 @@
 
 import com.supwisdom.dlpay.agent.AgentCode
 import com.supwisdom.dlpay.agent.AgentPayService
+import com.supwisdom.dlpay.agent.domain.QrcodePayTrans
+import com.supwisdom.dlpay.agent.service.AgentServiceProxy
 import com.supwisdom.dlpay.api.*
 import com.supwisdom.dlpay.api.bean.*
 import com.supwisdom.dlpay.api.service.*
@@ -35,9 +37,15 @@
     lateinit var cardService: CardService
     @Autowired
     private lateinit var applicationContext: ApplicationContext
+
+    @Autowired
+    private lateinit var sourceTypeService: SourceTypeService
     @Autowired
     lateinit var agentQueryResultTask: AgentQueryResultTask
 
+    @Autowired
+    private lateinit var agentServiceProxy: AgentServiceProxy
+
     /**
      * ============================================================================
      * 消费流水结果查询统一接口
@@ -434,20 +442,151 @@
                 .fail(TradeErrorCode.BUSINESS_DEAL_ERROR, "交易扣费失败"))
     }
 
-    @PostMapping("/qrcodepay/init")
-    fun qrcodePayInit(@Valid @RequestBody param: QrcodePayParam): ResponseEntity<Any> {
-        //1. 识别qrcode
-        //2. 初始化交易流水
-        //3. 调用第三方检查身份信息
-        TODO("")
+    @PostMapping("/qrcode/init")
+    fun qrcodePayAuth(@RequestBody param: QrcodePayParam): ResponseEntity<ApiResponse> {
+        val qrcode = agentServiceProxy.qrcodeMatch(param.qrcode)
+                ?: return ResponseEntity.ok(ResponseBodyBuilder.create()
+                        .fail(QrcodePayResponse(), TradeErrorCode.BUSINESS_DEAL_ERROR, "未识别的支付码"))
+
+        val sourceType = sourceTypeService.getBySourceType(qrcode.sourceType)
+                ?: return ResponseEntity.ok(ResponseBodyBuilder.create()
+                        .fail(QrcodePayResponse(), TradeErrorCode.BUSINESS_DEAL_ERROR,
+                                "不支持的支付方式<${qrcode.sourceType}>"))
+
+        val qrcodeTrans = agentServiceProxy.qrcodePayTransSaveOrUpdate(
+                QrcodePayTrans().apply {
+                    this.agentMerchId = param.shopaccno
+                    this.billno = param.billno
+                    this.qrcode = param.qrcode
+                })
+
+        val service = createAgentService(qrcode.sourceType)
+
+        val agentResp = service.auth(qrcodeTrans.agentMerchId, qrcodeTrans.billno)
+
+        return when (agentResp.code) {
+            AgentCode.SUCCESS -> {
+                val qrcodeTransResp = agentServiceProxy.qrcodePayTransFindByMerchIdAndBillno(qrcodeTrans.agentMerchId,
+                        qrcodeTrans.billno)
+                if (!sourceType.anonymousEnable && qrcodeTransResp.isAnonymous) {
+                    ResponseEntity.ok(ResponseBodyBuilder.create()
+                            .fail(QrcodePayResponse(), TradeErrorCode.BUSINESS_DEAL_ERROR,
+                                    "支付方式<${qrcode.sourceType}> 不支持匿名支付"))
+                } else {
+                    ResponseEntity.ok(ResponseBodyBuilder.create()
+                            .success(QrcodePayResponse().also {
+                                it.anonymous = qrcodeTransResp.isAnonymous
+                                it.userid = qrcodeTransResp.agentUserId
+                            }))
+                }
+            }
+            AgentCode.NOT_SUPPORT -> {
+                if (!sourceType.anonymousEnable) {
+                    ResponseEntity.ok(ResponseBodyBuilder.create()
+                            .fail(QrcodePayResponse(), TradeErrorCode.BUSINESS_DEAL_ERROR,
+                                    "支付方式<${qrcode.sourceType}> 不支持匿名支付"))
+                } else {
+                    ResponseEntity.ok(ResponseBodyBuilder.create()
+                            .success(QrcodePayResponse().also {
+                                it.anonymous = true
+                            }))
+                }
+            }
+            else -> {
+                ResponseEntity.ok(ResponseBodyBuilder.create()
+                        .fail(QrcodePayResponse(), TradeErrorCode.BUSINESS_DEAL_ERROR,
+                                "第三方身份错误,<${agentResp.agentMsg}"))
+            }
+        }
     }
 
     @PostMapping("/qrcodepay/confirm")
-    fun qrcodePayConfirm(@Valid @RequestBody param: QrcodePayParam): ResponseEntity<Any> {
-        //1. 检查交易流水状态,并 wip
-        //2. 请求第三方交易
-        //3. 根据第三方返回处理业务流程
-        TODO("")
+    fun qrcodePayInit(@Valid @RequestBody param: QrcodePayParam): ResponseEntity<ApiResponse> {
+        //1. 交易检查
+        val qrcodeTrans = agentServiceProxy.qrcodePayTransFindByMerchIdAndBillno(param.shopaccno,
+                param.billno) ?: return ResponseEntity.ok(ResponseBodyBuilder.create()
+                .fail(QrcodePayResponse(), TradeErrorCode.BUSINESS_DEAL_ERROR, "未找到billno"))
+        if (qrcodeTrans.refno.isNotEmpty()) {
+            return ResponseEntity.ok(ResponseBodyBuilder.create()
+                    .fail(QrcodePayResponse(), TradeErrorCode.BUSINESS_DEAL_ERROR, "该交易已确认,请查询结果"))
+        }
+
+        if (qrcodeTrans.qrcode != param.qrcode && param.qrcode.isNotEmpty()) {
+            val qrcode = agentServiceProxy.qrcodeMatch(param.qrcode)
+                    ?: return ResponseEntity.ok(ResponseBodyBuilder.create()
+                            .fail(QrcodePayResponse(), TradeErrorCode.BUSINESS_DEAL_ERROR, "未识别的支付码"))
+            if (qrcodeTrans.sourceType != qrcode.sourceType) {
+                return ResponseEntity.ok(ResponseBodyBuilder.create()
+                        .fail(QrcodePayResponse(), TradeErrorCode.BUSINESS_DEAL_ERROR, "支付码不符"))
+            }
+            qrcodeTrans.qrcode = param.qrcode
+        }
+
+        val sourceType = sourceTypeService.getBySourceType(qrcodeTrans.sourceType)
+                ?: return ResponseEntity.ok(ResponseBodyBuilder.create()
+                        .fail(QrcodePayResponse(), TradeErrorCode.BUSINESS_DEAL_ERROR,
+                                "不支持的支付方式<${qrcodeTrans.sourceType}>"))
+        if (!sourceType.anonymousEnable && qrcodeTrans.isAnonymous) {
+            return ResponseEntity.ok(ResponseBodyBuilder.create()
+                    .fail(QrcodePayResponse(), TradeErrorCode.BUSINESS_DEAL_ERROR,
+                            "支付方式<${qrcodeTrans.sourceType}>不支持匿名支付"))
+        }
+
+        //2. 初始化交易流水
+        val builder = TransactionBuilder().apply {
+            setTransInfo(param.transdate, param.transtime, TradeCode.TRANSCODE_WECHAT, qrcodeTrans.sourceType)
+            setOutTransInfo(qrcodeTrans.agentMerchId, qrcodeTrans.billno)
+        }
+
+        val shopacc = accountUtilServcie.readShopbyShopaccno(qrcodeTrans.agentMerchId)
+        builder.shop(shopacc).apply {
+            setAmount(param.amount / 100.0, TradeDict.TRADE_FLAG_IN)
+        }
+        if (qrcodeTrans.isAnonymous) {
+            builder.anonymous().apply {
+                setAmount(param.amount / 100.0, TradeDict.TRADE_FLAG_OUT)
+            }
+        } else {
+            val account = accountUtilServcie.readAccount(qrcodeTrans.userid)
+            builder.person(account).apply {
+                setAmount(param.amount / 100.0, TradeDict.TRADE_FLAG_OUT)
+            }.and().shop().apply {
+                setOpposite(account.accno, account.accname)
+            }
+        }
+        val transaction = builder.person().apply {
+            setOpposite(shopacc.shopaccno, shopacc.shopname)
+        }.and().init(transactionService)
+
+        qrcodeTrans.refno = transaction.refno
+        agentServiceProxy.qrcodePayTransSaveOrUpdate(qrcodeTrans)
+
+        //3. 调用第三方支付
+        transactionService.wip(transaction.refno)
+        val service = createAgentService(qrcodeTrans.sourceType)
+        val response = service.pay(transaction)
+
+        return when (response.code) {
+            AgentCode.SUCCESS -> {
+                transactionService.success(transaction.refno)
+                ResponseEntity.ok(ResponseBodyBuilder.create()
+                        .success(QrcodePayResponse().also {
+                            it.refno = transaction.refno
+                        }))
+            }
+            AgentCode.REQUIRE_QUERY -> {
+                ResponseEntity.ok(ResponseBodyBuilder.create()
+                        .success(QrcodePayResponse().also {
+                            it.refno = transaction.refno
+                        }))
+            }
+            else -> {
+                transactionService.fail(transaction.refno, response.agentMsg)
+                ResponseEntity.ok(ResponseBodyBuilder.create()
+                        .fail(QrcodePayResponse(), TradeErrorCode.BUSINESS_DEAL_ERROR,
+                                "第三方身份错误,<${response.agentMsg}"))
+            }
+        }
     }
 
 // ============================================== //
diff --git a/payapi/src/main/kotlin/com/supwisdom/dlpay/api/service/impl/transaction_service_impl.kt b/payapi/src/main/kotlin/com/supwisdom/dlpay/api/service/impl/transaction_service_impl.kt
index e2ac86c..edb618c 100644
--- a/payapi/src/main/kotlin/com/supwisdom/dlpay/api/service/impl/transaction_service_impl.kt
+++ b/payapi/src/main/kotlin/com/supwisdom/dlpay/api/service/impl/transaction_service_impl.kt
@@ -87,13 +87,15 @@
                 TPersondtl().apply {
                     this.refno = transaction.refno
                     this.accdate = transaction.accdate
-                    userid = builder.person().person.userid
-                    accountNo = builder.person().person.accno
-                    userName = builder.person().person.accname
+                    if (!builder.person().isAnonymous()) {
+                        userid = builder.person().person!!.userid
+                        accountNo = builder.person().person!!.accno
+                        userName = builder.person().person!!.accname
+                        befbal = builder.person().person!!.availbal
+                    }
                     outtradeno = builder.outtradeno
                     transdate = builder.transDate
                     transtime = builder.transTime
-                    befbal = builder.person().person.availbal
                     amount = builder.person().amount
                     this.sourceType = builder.sourceType
                     payinfo = builder.person().payinfo
@@ -183,9 +185,9 @@
             }
 
 
-            if (builder.hasPerson()) {
+            if (builder.hasPerson() && !builder.person().isAnonymous()) {
                 val dc = getDebitOrCredit(builder.person().tradeFlag, builder.isReverseTrans())
-                transaction.sumAmountByAccno(builder.person().person.accno,
+                transaction.sumAmountByAccno(builder.person().person!!.accno,
                         Subject.SUBJNO_PERSONAL_DEPOSIT,
                         dc).also {
                     if (transaction.personDtl.amount != getTransAmountFromDetail(builder, it)) {
diff --git a/payapi/src/main/kotlin/com/supwisdom/dlpay/api/transaction_builder.kt b/payapi/src/main/kotlin/com/supwisdom/dlpay/api/transaction_builder.kt
index b0f583f..a20638d 100644
--- a/payapi/src/main/kotlin/com/supwisdom/dlpay/api/transaction_builder.kt
+++ b/payapi/src/main/kotlin/com/supwisdom/dlpay/api/transaction_builder.kt
@@ -8,6 +8,7 @@
 import com.supwisdom.dlpay.framework.domain.TSubject
 import com.supwisdom.dlpay.framework.util.TradeDict
 import com.supwisdom.dlpay.framework.util.TradeErrorCode
+import kotlin.math.abs
 
 open class SubTransactionBuilder<T : SubTransactionBuilder<T>>(val parent: TransactionBuilder) {
     var payinfo: String = ""
@@ -65,7 +66,7 @@
      * amount : 交易金额, 正向交易金额必须 >= 0, 冲正交易金额必须 <= 0
      */
     fun setAmount(amount: Double, inOut: String): SubTransactionBuilder<T> {
-        this.amount = if (inOut == TradeDict.TRADE_FLAG_IN) Math.abs(amount) else -Math.abs(amount)
+        this.amount = if (inOut == TradeDict.TRADE_FLAG_IN) abs(amount) else -abs(amount)
         this.tradeFlag = inOut
         return this
     }
@@ -80,8 +81,11 @@
 
 }
 
-class PersonTranactionBuilder(parent: TransactionBuilder, val person: TAccount)
+class PersonTranactionBuilder(parent: TransactionBuilder, val person: TAccount?)
     : SubTransactionBuilder<PersonTranactionBuilder>(parent) {
+    fun isAnonymous(): Boolean {
+        return person == null
+    }
 }
 
 class ShopTransactionBuilder(parent: TransactionBuilder, val shopacc: TShopacc)
@@ -217,6 +221,15 @@
         return this.personBuilder
     }
 
+    fun anonymous(): PersonTranactionBuilder {
+        if (this::personBuilder.isInitialized) {
+            throw TransactionCheckException(TradeErrorCode.BUSINESS_DEAL_ERROR,
+                    "交易个人流水已经初始化")
+        }
+        this.personBuilder = PersonTranactionBuilder(this, null)
+        return this.personBuilder
+    }
+
     fun person(account: TAccount): PersonTranactionBuilder {
         return if (!this::personBuilder.isInitialized) {
             PersonTranactionBuilder(this, account).also {
@@ -296,7 +309,7 @@
     }
 
     fun preCheck() {
-        if (dtltype.isNullOrEmpty()) {
+        if (dtltype.isEmpty()) {
             throw TransactionCheckException(TradeErrorCode.INPUT_DATA_ERROR,
                     "流水类型错误")
         }
@@ -333,7 +346,7 @@
         }
         if (hasPerson()) {
             person().also {
-                if (it.person.transStatus != TradeDict.STATUS_NORMAL) {
+                if (!it.isAnonymous() && it.person!!.transStatus != TradeDict.STATUS_NORMAL) {
                     throw TransactionCheckException(TradeErrorCode.PERSON_STATUS_ERROR,
                             "个人状态错误")
                 }
diff --git a/payapi/src/main/resources/data.sql b/payapi/src/main/resources/data.sql
index 5752950..31b965a 100644
--- a/payapi/src/main/resources/data.sql
+++ b/payapi/src/main/resources/data.sql
@@ -571,6 +571,9 @@
 INSERT INTO "tb_dictionary" ("id", "dictval", "dicttype", "dictcaption", "dicttypename", "tenantid")
 VALUES (30, 'shopmarket', 'dtltypeList', '商超消费', '流水类型', '{tenantid}');
 
-
+INSERT INTO QRCODE_PATTERN(ID, PATTERN, SOURCETYPE, TENANTID)
+VALUES(1, '28\d{16}', 'alipay', '{tenantid}');
+INSERT INTO QRCODE_PATTERN(ID, PATTERN, SOURCETYPE, TENANTID)
+VALUES(1, '13\d{16}', 'wechatpay', '{tenantid}');
 ----------------------------------------------------
 commit;
\ No newline at end of file