1 package com.supwisdom.dlpay.api.service.impl
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.TSourceTypeCheckStatus
10 import com.supwisdom.dlpay.api.domain.TTransactionChkdtl
11 import com.supwisdom.dlpay.api.domain.TTransactionChkfile
12 import com.supwisdom.dlpay.api.service.SourceTypeService
13 import com.supwisdom.dlpay.api.service.TransactionReconciliationService
14 import com.supwisdom.dlpay.api.service.TransactionServiceProxy
15 import com.supwisdom.dlpay.exception.TransactionCheckException
16 import com.supwisdom.dlpay.exception.TransactionException
17 import com.supwisdom.dlpay.framework.dao.BusinessparaDao
18 import com.supwisdom.dlpay.framework.service.SystemUtilService
19 import com.supwisdom.dlpay.framework.tenant.TenantContext
20 import com.supwisdom.dlpay.framework.util.MoneyUtil
21 import com.supwisdom.dlpay.framework.util.TradeDict
22 import com.supwisdom.dlpay.framework.util.TradeErrorCode
23 import com.supwisdom.dlpay.util.ConstantUtil
24 import org.springframework.beans.factory.annotation.Autowired
25 import org.springframework.stereotype.Service
28 class TransactionReconciliationServiceImpl : TransactionReconciliationService {
30 private lateinit var transactionChkfileDao: TransactionChkfileDao
32 private lateinit var transactionChkdtlDao: TransactionChkdtlDao
34 private lateinit var systemUtilService: SystemUtilService
36 private lateinit var businessparaDao: BusinessparaDao
38 private lateinit var transactionMainDao: TransactionMainDao
40 private lateinit var persondtlDao: PersondtlDao
42 private lateinit var transactionService: TransactionServiceProxy
45 private lateinit var sourceTypeService: SourceTypeService
47 override fun getTransactionChkfile(accdate: String, sourcetype: String): TTransactionChkfile? {
48 return transactionChkfileDao.getByAccdateAndSourcetype(accdate, sourcetype)
51 override fun doInitTransactionChkfile(accdate: String, sourcetype: String): TTransactionChkfile {
52 return transactionChkfileDao.getByAccdateAndSourcetype(accdate, sourcetype).let {
54 if (ConstantUtil.CHKFILE_STATUS_INIT != it.status)
55 throw TransactionCheckException(TradeErrorCode.BUSINESS_DEAL_ERROR,
56 "accdate=$accdate,sourcetype=$sourcetype 的chkfile已经存在")
59 saveInitTransactionChkfile(accdate, sourcetype) //保存init对账文件
64 override fun saveOrUpdateTransactionChkfile(chkfile: TTransactionChkfile): TTransactionChkfile {
65 return transactionChkfileDao.save(chkfile)
68 override fun saveYnrccTransactionChkDtl(chkfile: TTransactionChkfile, bean: YnrccChkfileBean): TTransactionChkdtl {
69 return transactionChkdtlDao.save(TTransactionChkdtl().apply {
70 this.chkfileId = chkfile.id
71 this.accdate = chkfile.accdate
72 this.sourcetype = chkfile.sourcetype
73 this.recordno = bean.recordno
74 this.amount = bean.amount / 100.0
75 this.otherRefno = bean.agentrefno
76 this.localRefno = bean.refno
77 this.otherAccdate = bean.agentdate
78 this.transtype = bean.flag
79 this.otherStatus = bean.status
81 this.extdata = bean.summary
82 this.chkresult = ConstantUtil.CHKDTL_CHKRESULT_UNCHECK
83 this.resolved = ConstantUtil.CHKDTL_RESOLVED_NONE
84 this.lastsaved = systemUtilService.sysdatetime.sysdate
85 this.tenantid = TenantContext.getTenantSchema()
89 override fun doBatchSaveYnrccTransactionChkDtl(chkfile: TTransactionChkfile, list: ArrayList<YnrccChkfileBean>): Boolean {
91 saveYnrccTransactionChkDtl(chkfile, bean)
96 override fun doSuccessTransactionChkfile(chkfile: TTransactionChkfile, remark: String) {
97 val suminfo = transactionChkdtlDao.getTransactionSumInfo(chkfile.accdate, chkfile.sourcetype)
98 chkfile.status = ConstantUtil.CHKFILE_STATUS_UNCHECK
99 chkfile.remark = remark
100 chkfile.othercnt = suminfo.totalcnt ?: 0
101 chkfile.otheramt = suminfo.totalamt ?: 0.0
102 transactionChkfileDao.save(chkfile)
103 businessparaDao.updateBusinessparaValue(YnrccUtil.YNRCC_BILLS_DOWNLOAD_LASTDATE, chkfile.accdate) //更新下载对账单日期
106 override fun deleteTransactionChkdtls(chkfileId: String) {
107 transactionChkdtlDao.deleteByChkfileid(chkfileId)
110 override fun saveInitTransactionChkfile(accdate: String, sourcetype: String): TTransactionChkfile {
111 return transactionChkfileDao.save(TTransactionChkfile().apply {
112 this.accdate = accdate
113 this.sourcetype = sourcetype
114 this.status = ConstantUtil.CHKFILE_STATUS_INIT
115 this.result = ConstantUtil.CHKFILE_RESULT_NONE
121 this.lastsaved = systemUtilService.sysdatetime.sysdate
122 this.tenantid = TenantContext.getTenantSchema()
126 override fun doCheckEqualTransdtls(chkfile: TTransactionChkfile, start: Int): Int {
128 return transactionChkdtlDao.findEqualDtlWithLimit(chkfile.id, start, start + 1000)?.also {
129 it.forEach { chkdtl ->
130 chkdtl.chkresult = ConstantUtil.CHKDTL_CHKRESULT_EQUAL
131 chkdtl.resolved = ConstantUtil.CHKDTL_RESOLVED_EQUAL
132 chkdtl.remark = "双方交易一致"
133 transactionChkdtlDao.save(chkdtl) //对账明细表更新
135 transactionService.checkSuccessConfirm(chkdtl.localRefno, chkdtl.otherAccdate)
140 override fun getMinChkDtlRecordNo(chkfile: TTransactionChkfile, status: String): Int {
141 return if (status.isEmpty()) {
142 transactionChkdtlDao.getMinRecordNo(chkfile.id)
144 transactionChkdtlDao.getMinRecordNoByStatus(chkfile.id, status)
148 override fun getUncheckTransactionChkdtls(chkfileId: String): List<TTransactionChkdtl> {
149 return transactionChkdtlDao.getUncheckTransactionChkdtls(chkfileId)
150 ?: ArrayList<TTransactionChkdtl>(0)
153 override fun doCheckTransactionChkdtl(chkdtl: TTransactionChkdtl): TTransactionChkdtl {
154 val transMain = transactionMainDao.findByRefno(chkdtl.localRefno)
156 if (null == transMain || !transMain.person) {
157 chkdtl.chkresult = ConstantUtil.CHKDTL_CHKRESULT_NOTEXIST
158 chkdtl.resolved = ConstantUtil.CHKDTL_RESOLVED_HANGUP
159 chkdtl.remark = "本地流水不存在"
160 return transactionChkdtlDao.save(chkdtl) //对账明细表更新
163 if (!MoneyUtil.moneyEqual(chkdtl.amount, transMain.personDtl.amount)) {
164 chkdtl.chkresult = ConstantUtil.CHKDTL_CHKRESULT_DIFF
165 chkdtl.resolved = ConstantUtil.CHKDTL_RESOLVED_HANGUP
166 chkdtl.remark = "交易金额不相等"
167 return transactionChkdtlDao.save(chkdtl) //对账明细表更新
170 if (transMain.accdate != chkdtl.accdate || transMain.sourceType != chkdtl.sourcetype) {
172 chkdtl.chkresult = ConstantUtil.CHKDTL_CHKRESULT_ERROR
173 chkdtl.resolved = ConstantUtil.CHKDTL_RESOLVED_HANGUP
174 chkdtl.remark = "记账日期或支付方式错误"
175 return transactionChkdtlDao.save(chkdtl) //对账明细表更新
178 return if (transMain.status == TradeDict.DTL_STATUS_SUCCESS) {
179 chkdtl.chkresult = ConstantUtil.CHKDTL_CHKRESULT_EQUAL
180 chkdtl.resolved = ConstantUtil.CHKDTL_RESOLVED_EQUAL
181 chkdtl.remark = "双方交易一致"
182 transactionService.checkSuccessConfirm(chkdtl.localRefno, chkdtl.otherAccdate)
183 transactionChkdtlDao.save(chkdtl) //对账明细表更新
186 chkdtl.chkresult = ConstantUtil.CHKDTL_CHKRESULT_NOCHARGE
187 chkdtl.resolved = ConstantUtil.CHKDTL_RESOLVED_ADD
188 chkdtl.remark = "本地未入账,需要补助"
189 transactionChkdtlDao.save(chkdtl) //对账明细表更新
193 override fun checkUncheckExists(chkfileId: String): Boolean {
194 return transactionChkdtlDao.getCountByChkresult(chkfileId, ConstantUtil.CHKDTL_CHKRESULT_UNCHECK).existed > 0
197 override fun doCheckLocalMoreDtls(chkfile: TTransactionChkfile): Int {
198 return transactionChkdtlDao.findLocalMoreDtls(chkfile.accdate, chkfile.sourcetype, chkfile.id)?.also {
199 it.forEachIndexed { index, refno ->
201 transactionMainDao.findByRefno(refno)?.also { transMain ->
202 transactionChkdtlDao.save(TTransactionChkdtl().apply {
203 this.chkfileId = chkfile.id
204 this.accdate = chkfile.accdate
205 this.sourcetype = chkfile.sourcetype
206 this.recordno = -1 * (index + 1)
207 this.amount = transMain.personDtl.amount
208 this.otherRefno = transMain.sourceTypeRefno ?: "$index"
209 this.localRefno = transMain.refno
210 this.otherAccdate = transMain.accdate
211 this.transtype = when (transMain.reverseType) {
213 else -> transMain.reverseType
215 this.otherStatus = "unknown"
216 this.remark = "本地有成功流水,第三方流水不存在"
217 this.extdata = transMain.personDtl.transdesc
218 this.chkresult = ConstantUtil.CHKDTL_CHKRESULT_SURPLUS
219 this.resolved = ConstantUtil.CHKDTL_RESOLVED_HANGUP
220 this.lastsaved = systemUtilService.sysdatetime.sysdate
221 this.tenantid = chkfile.tenantid
223 }.also { transMain ->
224 if (transMain == null) {
225 throw TransactionException(-3, "本地存在多余成功流水记录,且交易参考号<$refno>异常,未找到transactionMain记录")
232 override fun doFinishChkfileStatus(chkfile: TTransactionChkfile, checkStatus: TSourceTypeCheckStatus) {
233 if (transactionChkdtlDao.getCountByChkresult(chkfile.id, ConstantUtil.CHKDTL_CHKRESULT_UNCHECK).existed > 0) {
234 throw TransactionException(-2, "存在未对账的明细记录")
237 chkfile.status = ConstantUtil.CHKFILE_STATUS_FINISH
238 checkStatus.checkStatus = true
239 checkStatus.repairStatus = false
240 checkStatus.settleStatus = false
241 if (transactionChkdtlDao.getErrorCount(chkfile.id).existed > 0) {
243 chkfile.result = ConstantUtil.CHKFILE_RESULT_ERROR
244 chkfile.remark = "校对完成,明细存在对比异常"
245 transactionChkdtlDao.getCountByChkresult(chkfile.id, ConstantUtil.CHKDTL_CHKRESULT_SURPLUS).existed.also {
246 if (null != it && it > 0) chkfile.remark = "本地有<$it>条流水不在对账文件中,请联系管理员检查"
250 if (transactionChkdtlDao.getCountByChkresult(chkfile.id, ConstantUtil.CHKDTL_CHKRESULT_NOCHARGE).existed > 0) {
252 chkfile.result = ConstantUtil.CHKFILE_RESULT_UNEQUAL //不平
253 chkfile.remark = "校对完成,存在需补账的交易记录"
255 chkfile.result = ConstantUtil.CHKFILE_RESULT_EQUAL //一致
256 chkfile.remark = "校对完成,双方交易一致"
258 checkStatus.repairStatus = true
260 checkStatus.remark = chkfile.remark
261 transactionChkfileDao.save(chkfile)
262 sourceTypeService.saveOrUpdateSourceTypeCheckStatus(checkStatus)
265 override fun getNeedRepairChkdtls(chkfile: TTransactionChkfile): List<TTransactionChkdtl> {
266 return transactionChkdtlDao.getNeedRepairChkdtls(chkfile.id) ?: ArrayList<TTransactionChkdtl>(0)
269 override fun doRepairTransactionChkdtl(chkdtl: TTransactionChkdtl): TTransactionChkdtl {
270 transactionService.repair(chkdtl.localRefno, chkdtl.otherAccdate, chkdtl.otherRefno, "补账成功")
271 chkdtl.resolved = ConstantUtil.CHKDTL_RESOLVED_EQUAL
272 chkdtl.remark = "本地未入账,补账成功"
273 return transactionChkdtlDao.save(chkdtl)
276 override fun saveOrUpdateTransctionChkdtl(chkdtl: TTransactionChkdtl){
277 transactionChkdtlDao.save(chkdtl)
280 override fun doConfirmChkfileStatus(chkfile: TTransactionChkfile, checkStatus: TSourceTypeCheckStatus): TTransactionChkfile {
281 val personSumInfo = persondtlDao.getPersondtlSumInfo(chkfile.accdate, chkfile.sourcetype, chkfile.tenantid)
282 chkfile.localcnt = personSumInfo.totalcnt ?: 0
283 chkfile.localamt = personSumInfo.totalamt ?: 0.00
285 checkStatus.settleStatus = false
286 checkStatus.remark = chkfile.remark
287 if (chkfile.result in setOf(ConstantUtil.CHKFILE_RESULT_EQUAL, ConstantUtil.CHKFILE_RESULT_UNEQUAL)) {
288 val notEqualCount = transactionChkdtlDao.getChkdtlNotEqualCount(chkfile.id).existed
289 val equalCount = transactionChkdtlDao.getChkdtlEqualCount(chkfile.id).existed
290 if (notEqualCount == 0 && equalCount==chkfile.othercnt && chkfile.othercnt == chkfile.localcnt && MoneyUtil.moneyEqual(chkfile.otheramt, chkfile.localamt)) {
292 chkfile.remark = when (chkfile.result == ConstantUtil.CHKFILE_RESULT_EQUAL) {
293 true -> "对账完成,双方交易一致"
294 else -> "对账完成,补账后双方交易一致"
296 checkStatus.settleStatus = true
297 checkStatus.forceRecheck = false //清掉
298 checkStatus.remark = chkfile.remark
300 checkStatus.remark = "对账完成,补账有失败"
304 sourceTypeService.saveOrUpdateSourceTypeCheckStatus(checkStatus)
305 return transactionChkfileDao.save(chkfile)