be112d1f1c8991a3271d70e3d4a6fd764676995f
[epayment/food_payapi.git] /
1 package com.supwisdom.dlpay.api.service.impl
2
3 import com.supwisdom.dlpay.agent.citizencard.YnrccUtil
4 import com.supwisdom.dlpay.api.bean.YnrccChkfileBean
5 import com.supwisdom.dlpay.api.dao.PersondtlDao
6 import com.supwisdom.dlpay.api.dao.TransactionChkdtlDao
7 import com.supwisdom.dlpay.api.dao.TransactionChkfileDao
8 import com.supwisdom.dlpay.api.dao.TransactionMainDao
9 import com.supwisdom.dlpay.api.domain.TTransactionChkdtl
10 import com.supwisdom.dlpay.api.domain.TTransactionChkfile
11 import com.supwisdom.dlpay.api.service.TransactionReconciliationService
12 import com.supwisdom.dlpay.api.service.TransactionServiceProxy
13 import com.supwisdom.dlpay.exception.TransactionCheckException
14 import com.supwisdom.dlpay.framework.dao.BusinessparaDao
15 import com.supwisdom.dlpay.framework.service.SystemUtilService
16 import com.supwisdom.dlpay.framework.tenant.TenantContext
17 import com.supwisdom.dlpay.framework.util.MoneyUtil
18 import com.supwisdom.dlpay.framework.util.TradeDict
19 import com.supwisdom.dlpay.framework.util.TradeErrorCode
20 import com.supwisdom.dlpay.util.ConstantUtil
21 import org.springframework.beans.factory.annotation.Autowired
22 import org.springframework.stereotype.Service
23
24 @Service
25 class TransactionReconciliationServiceImpl : TransactionReconciliationService {
26     @Autowired
27     private lateinit var transactionChkfileDao: TransactionChkfileDao
28     @Autowired
29     private lateinit var transactionChkdtlDao: TransactionChkdtlDao
30     @Autowired
31     private lateinit var systemUtilService: SystemUtilService
32     @Autowired
33     private lateinit var businessparaDao: BusinessparaDao
34     @Autowired
35     private lateinit var transactionMainDao: TransactionMainDao
36     @Autowired
37     private lateinit var persondtlDao: PersondtlDao
38     @Autowired
39     private lateinit var transactionService: TransactionServiceProxy
40
41     override fun getTransactionChkfile(accdate: String, sourcetype: String): TTransactionChkfile? {
42         return transactionChkfileDao.getByAccdateAndSourcetype(accdate, sourcetype)
43     }
44
45     override fun doInitTransactionChkfile(accdate: String, sourcetype: String): TTransactionChkfile {
46         return transactionChkfileDao.getByAccdateAndSourcetype(accdate, sourcetype).let {
47             if (it != null) {
48                 if (ConstantUtil.CHKFILE_STATUS_INIT != it.status)
49                     throw TransactionCheckException(TradeErrorCode.BUSINESS_DEAL_ERROR, "accdate=$accdate,sourcetype=$sourcetype 的chkfile已经存在")
50                 it
51             } else {
52                 saveInitTransactionChkfile(accdate, sourcetype) //保存init对账文件
53             }
54         }
55     }
56
57     override fun saveOrUpdateTransactionChkfile(chkfile: TTransactionChkfile): TTransactionChkfile {
58         return transactionChkfileDao.save(chkfile)
59     }
60
61     override fun saveYnrccTransactionChkDtl(chkfile: TTransactionChkfile, bean: YnrccChkfileBean): TTransactionChkdtl {
62         return transactionChkdtlDao.save(TTransactionChkdtl().apply {
63             this.chkfileId = chkfile.id
64             this.accdate = chkfile.accdate
65             this.sourcetype = chkfile.sourcetype
66             this.recordno = bean.recordno
67             this.amount = bean.amount / 100.0
68             this.otherRefno = bean.agentrefno
69             this.localRefno = bean.refno
70             this.otherAccdate = bean.agentdate
71             this.transtype = bean.flag
72             this.otherStatus = bean.status
73             this.remark = null
74             this.extdata = bean.summary
75             this.chkresult = ConstantUtil.CHKDTL_CHKRESULT_UNCHECK
76             this.resolved = null
77             this.lastsaved = systemUtilService.sysdatetime.sysdate
78             this.tenantid = TenantContext.getTenantSchema()
79         })
80     }
81
82     override fun doBatchSaveYnrccTransactionChkDtl(chkfile: TTransactionChkfile, list: ArrayList<YnrccChkfileBean>): Boolean {
83         for (bean in list) {
84             saveYnrccTransactionChkDtl(chkfile, bean)
85         }
86         return true
87     }
88
89     override fun doSuccessTransactionChkfile(chkfile: TTransactionChkfile, remark: String) {
90         val suminfo = transactionChkdtlDao.getTransactionSumInfo(chkfile.accdate, chkfile.sourcetype)
91         chkfile.status = ConstantUtil.CHKFILE_STATUS_UNCHECK
92         chkfile.remark = remark
93         chkfile.othercnt = suminfo.totalcnt ?: 0
94         chkfile.otheramt = suminfo.totalamt ?: 0.0
95         transactionChkfileDao.save(chkfile)
96         businessparaDao.updateBusinessparaValue(YnrccUtil.YNRCC_BILLS_DOWNLOAD_LASTDATE, chkfile.accdate) //更新下载对账单日期
97     }
98
99     override fun deleteTransactionChkdtls(chkfileId: String) {
100         transactionChkdtlDao.deleteByChkfileid(chkfileId)
101     }
102
103     override fun saveInitTransactionChkfile(accdate: String, sourcetype: String): TTransactionChkfile {
104         return transactionChkfileDao.save(TTransactionChkfile().apply {
105             this.accdate = accdate
106             this.sourcetype = sourcetype
107             this.status = ConstantUtil.CHKFILE_STATUS_INIT
108             this.result = ConstantUtil.CHKFILE_RESULT_NONE
109             this.remark = null
110             this.othercnt = 0
111             this.otheramt = 0.00
112             this.localcnt = 0
113             this.localamt = 0.00
114             this.lastsaved = systemUtilService.sysdatetime.sysdate
115             this.tenantid = TenantContext.getTenantSchema()
116         })
117     }
118
119     override fun doCheckEqualTransdtls(chkfile: TTransactionChkfile) {
120         //所有一致的记录,一次任务处理
121         transactionChkdtlDao.getCheckEqualDetails(chkfile.id)?.forEach { chkdtl ->
122             chkdtl.chkresult = ConstantUtil.CHKDTL_CHKRESULT_EQUAL
123             chkdtl.resolved = ConstantUtil.CHKDTL_RESOLVED_EQUAL
124             chkdtl.remark = "双方交易一致"
125             transactionChkdtlDao.save(chkdtl) //对账明细表更新
126
127             transactionService.checkSuccessConfirm(chkdtl.localRefno, chkdtl.otherAccdate)
128         }
129     }
130
131     override fun getUncheckTransactionChkdtls(chkfileId: String): List<TTransactionChkdtl> {
132         return transactionChkdtlDao.getUncheckTransactionChkdtls(chkfileId) ?: ArrayList<TTransactionChkdtl>(0)
133     }
134
135     override fun doCheckTransactionChkdtl(chkdtl: TTransactionChkdtl) {
136         val transMain = transactionMainDao.findByRefno(chkdtl.localRefno)
137
138         if (null == transMain || !transMain.person) {
139             chkdtl.chkresult = ConstantUtil.CHKDTL_CHKRESULT_NOTEXIST
140             chkdtl.resolved = ConstantUtil.CHKDTL_RESOLVED_HANGUP
141             chkdtl.remark = "本地流水不存在"
142             transactionChkdtlDao.save(chkdtl) //对账明细表更新
143         }
144
145         if(!MoneyUtil.moneyEqual(chkdtl.amount,transMain.personDtl.amount)){
146             chkdtl.chkresult = ConstantUtil.CHKDTL_CHKRESULT_DIFF
147             chkdtl.resolved = ConstantUtil.CHKDTL_RESOLVED_HANGUP
148             chkdtl.remark = "交易金额不相等"
149             transactionChkdtlDao.save(chkdtl) //对账明细表更新
150         }
151
152         if(transMain.accdate!=chkdtl.accdate || transMain.sourceType != chkdtl.sourcetype){
153             //TODO: 数据异常??
154             chkdtl.chkresult = ConstantUtil.CHKDTL_CHKRESULT_ERROR
155             chkdtl.resolved = ConstantUtil.CHKDTL_RESOLVED_HANGUP
156             chkdtl.remark = "记账日期或支付方式错误"
157             transactionChkdtlDao.save(chkdtl) //对账明细表更新
158         }
159
160         if (transMain.status == TradeDict.DTL_STATUS_SUCCESS) {
161             chkdtl.chkresult = ConstantUtil.CHKDTL_CHKRESULT_EQUAL
162             chkdtl.resolved = ConstantUtil.CHKDTL_RESOLVED_EQUAL
163             chkdtl.remark = "双方交易一致"
164             transactionChkdtlDao.save(chkdtl) //对账明细表更新
165
166             transactionService.checkSuccessConfirm(chkdtl.localRefno, chkdtl.otherAccdate)
167         } else {
168             //补账
169             transactionService.repair(transMain.refno, chkdtl.otherAccdate, chkdtl.otherRefno, "补账成功")
170
171             chkdtl.chkresult = ConstantUtil.CHKDTL_CHKRESULT_NOCHARGE
172             chkdtl.resolved = ConstantUtil.CHKDTL_RESOLVED_EQUAL
173             chkdtl.remark = "本地未入账,补账成功"
174             transactionChkdtlDao.save(chkdtl) //对账明细表更新
175         }
176     }
177
178     override fun checkUncheckExists(chkfileId: String): Boolean {
179         return transactionChkdtlDao.getUncheckCount(chkfileId).existed > 0
180     }
181
182     override fun doCheckLocalMoreDtls(chkfile: TTransactionChkfile) {
183         transactionChkdtlDao.findLocalMoreDtls(chkfile.accdate, chkfile.sourcetype, chkfile.id)?.forEach { refno ->
184             //保存多余的记录
185             transactionMainDao.findByRefno(refno)?.let { transMain ->
186                 if (TradeDict.DTL_STATUS_SUCCESS == transMain.status && transMain.accdate == chkfile.accdate && transMain.sourceType == chkfile.sourcetype) {
187                     transactionChkdtlDao.save(TTransactionChkdtl().apply {
188                         this.chkfileId = chkfile.id
189                         this.accdate = chkfile.accdate
190                         this.sourcetype = chkfile.sourcetype
191                         this.recordno = null
192                         this.amount = transMain.personDtl.amount
193                         this.otherRefno = transMain.reverseRefno ?: "0"
194                         this.localRefno = transMain.refno
195                         this.otherAccdate = transMain.accdate
196                         this.transtype = when (transMain.reverseType) {
197                             "none" -> "pay"
198                             else -> transMain.reverseType
199                         }
200                         this.otherStatus = "unknown"
201                         this.remark = "本地成功流水第三方流水不存在"
202                         this.extdata = transMain.personDtl.transdesc
203                         this.chkresult = ConstantUtil.CHKDTL_CHKRESULT_NOTEXIST
204                         this.resolved = ConstantUtil.CHKDTL_RESOLVED_HANGUP
205                         this.lastsaved = systemUtilService.sysdatetime.sysdate
206                         this.tenantid = chkfile.tenantid
207                     }) //保存本地多出的记录
208                 }
209             }
210         }
211     }
212
213     override fun doConfirmChkfileStatus(chkfile: TTransactionChkfile): TTransactionChkfile {
214         val personSumInfo = persondtlDao.getPersondtlSumInfo(chkfile.accdate, chkfile.sourcetype, chkfile.tenantid)
215         chkfile.localcnt = personSumInfo.totalcnt ?: 0
216         chkfile.localamt = personSumInfo.totalamt ?: 0.00
217         chkfile.status = ConstantUtil.CHKFILE_STATUS_finish  //对账结束
218         if (chkfile.othercnt == chkfile.localcnt && MoneyUtil.moneyEqual(chkfile.otheramt, chkfile.localamt)) {
219             //fixme: 是否还需判断chkdtl中resolved是否都equal
220             chkfile.result = ConstantUtil.CHKFILE_RESULT_EQUAL
221             chkfile.remark = "对账完成,双方一致"
222         } else {
223             chkfile.result = ConstantUtil.CHKFILE_RESULT_UNEQUAL
224             chkfile.remark = "对账不平,请查看明细数据"
225         }
226         transactionChkfileDao.save(chkfile)
227         return chkfile
228     }
229 }