@@ -0,0 +1,332 @@
package com.jsowell.pile.service.impl ;
import com.alibaba.fastjson2.JSON ;
import com.jsowell.common.constant.Constants ;
import com.jsowell.common.exception.ServiceException ;
import com.jsowell.common.util.DateUtils ;
import com.jsowell.common.util.StringUtils ;
import com.jsowell.pile.constant.MerchantWithdrawInvoiceConstants ;
import com.jsowell.pile.domain.ClearingBillInfo ;
import com.jsowell.pile.domain.ClearingWithdrawInfo ;
import com.jsowell.pile.domain.ClearingWithdrawInvoice ;
import com.jsowell.pile.domain.PileMerchantInfo ;
import com.jsowell.pile.dto.WithdrawInvoiceSubmitRequest ;
import com.jsowell.pile.mapper.ClearingWithdrawInfoMapper ;
import com.jsowell.pile.mapper.ClearingWithdrawInvoiceMapper ;
import com.jsowell.pile.service.ClearingBillInfoService ;
import com.jsowell.pile.service.MerchantWithdrawInvoiceService ;
import com.jsowell.pile.service.PileMerchantInfoService ;
import com.jsowell.pile.vo.web.MerchantWithdrawInvoiceVO ;
import com.jsowell.system.constant.TodoTaskConstants ;
import com.jsowell.system.domain.SysTodoTask ;
import com.jsowell.system.domain.dto.TodoTaskCreateCommand ;
import com.jsowell.system.service.TodoTaskAssigneeService ;
import com.jsowell.system.service.TodoTaskService ;
import org.apache.commons.collections4.CollectionUtils ;
import org.slf4j.Logger ;
import org.slf4j.LoggerFactory ;
import org.springframework.beans.BeanUtils ;
import org.springframework.beans.factory.annotation.Autowired ;
import org.springframework.dao.DuplicateKeyException ;
import org.springframework.stereotype.Service ;
import org.springframework.transaction.annotation.Transactional ;
import javax.annotation.Resource ;
import java.util.Date ;
import java.util.HashMap ;
import java.util.List ;
import java.util.Map ;
/**
* 运营商提现向平台开票服务实现。
*/
@Service
public class MerchantWithdrawInvoiceServiceImpl implements MerchantWithdrawInvoiceService {
private static final Logger log = LoggerFactory . getLogger ( MerchantWithdrawInvoiceServiceImpl . class ) ;
@Resource
private ClearingWithdrawInfoMapper clearingWithdrawInfoMapper ;
@Resource
private ClearingWithdrawInvoiceMapper clearingWithdrawInvoiceMapper ;
@Autowired
private ClearingBillInfoService clearingBillInfoService ;
@Autowired
private PileMerchantInfoService pileMerchantInfoService ;
@Autowired
private TodoTaskAssigneeService todoTaskAssigneeService ;
@Autowired
private TodoTaskService todoTaskService ;
@Override
@Transactional ( rollbackFor = Exception . class )
public void handleWithdrawSucceeded ( String withdrawCode ) {
String safeWithdrawCode = normalizeRequired ( withdrawCode , " 提现编号 " , 64 ) ;
ClearingWithdrawInfo withdrawInfo = clearingWithdrawInfoMapper . selectByWithdrawCode ( safeWithdrawCode ) ;
if ( withdrawInfo = = null ) {
throw new ServiceException ( " 提现记录不存在,无法创建开票待办 " ) ;
}
Date now = DateUtils . getNowDate ( ) ;
if ( ! Constants . ONE . equals ( withdrawInfo . getWithdrawStatus ( ) ) | | withdrawInfo . getArrivalTime ( ) = = null ) {
withdrawInfo . setWithdrawStatus ( Constants . ONE ) ;
withdrawInfo . setArrivalTime ( now ) ;
withdrawInfo . setUpdateTime ( now ) ;
clearingWithdrawInfoMapper . updateByPrimaryKeySelective ( withdrawInfo ) ;
}
completeClearingBills ( safeWithdrawCode ) ;
ClearingWithdrawInvoice invoice = getOrCreateInvoice ( withdrawInfo ) ;
if ( ! MerchantWithdrawInvoiceConstants . STATUS_PENDING . equals ( invoice . getInvoiceStatus ( ) ) ) {
return ;
}
createTodos ( withdrawInfo ) ;
}
@Override
public MerchantWithdrawInvoiceVO getForAssignee ( String withdrawCode , Long todoId , Long userId ) {
String safeWithdrawCode = normalizeRequired ( withdrawCode , " 提现编号 " , 64 ) ;
validateTodo ( safeWithdrawCode , todoId , userId ) ;
ClearingWithdrawInvoice invoice = requireInvoice ( safeWithdrawCode ) ;
ClearingWithdrawInfo withdrawInfo = clearingWithdrawInfoMapper . selectByWithdrawCode ( safeWithdrawCode ) ;
return buildView ( invoice , withdrawInfo ) ;
}
@Override
@Transactional ( rollbackFor = Exception . class )
public boolean submit ( String withdrawCode , WithdrawInvoiceSubmitRequest request ,
Long userId , String operatorName ) {
if ( request = = null ) {
throw new ServiceException ( " 发票提交参数不能为空 " ) ;
}
String safeWithdrawCode = normalizeRequired ( withdrawCode , " 提现编号 " , 64 ) ;
SysTodoTask todoTask = validateTodo ( safeWithdrawCode , request . getTodoId ( ) , userId ) ;
ClearingWithdrawInvoice invoice = requireInvoice ( safeWithdrawCode ) ;
if ( MerchantWithdrawInvoiceConstants . STATUS_SUBMITTED . equals ( invoice . getInvoiceStatus ( ) ) ) {
return true ;
}
if ( ! TodoTaskConstants . isActiveStatus ( todoTask . getTaskStatus ( ) ) ) {
throw new ServiceException ( " 当前待办状态不允许提交发票 " ) ;
}
if ( ! MerchantWithdrawInvoiceConstants . STATUS_PENDING . equals ( invoice . getInvoiceStatus ( ) ) ) {
throw new ServiceException ( " 当前提现开票状态不允许提交 " ) ;
}
Date now = DateUtils . getNowDate ( ) ;
invoice . setInvoiceStatus ( MerchantWithdrawInvoiceConstants . STATUS_SUBMITTED ) ;
invoice . setInvoiceNumber ( normalizeRequired ( request . getInvoiceNumber ( ) , " 发票号码 " , 100 ) ) ;
invoice . setVoucherUrl ( normalizeRequired ( request . getVoucherUrl ( ) , " 发票凭证 " , 1000 ) ) ;
invoice . setSubmittedBy ( userId ) ;
invoice . setSubmittedName ( normalizeOperator ( operatorName , userId ) ) ;
invoice . setSubmittedTime ( now ) ;
invoice . setUpdateBy ( invoice . getSubmittedName ( ) ) ;
invoice . setUpdateTime ( now ) ;
if ( clearingWithdrawInvoiceMapper . markSubmitted ( invoice ) = = 0 ) {
ClearingWithdrawInvoice current = requireInvoice ( safeWithdrawCode ) ;
if ( MerchantWithdrawInvoiceConstants . STATUS_SUBMITTED . equals ( current . getInvoiceStatus ( ) ) ) {
return true ;
}
throw new ServiceException ( " 当前提现开票状态不允许提交 " ) ;
}
todoTaskService . completeByBusiness ( MerchantWithdrawInvoiceConstants . BUSINESS_TYPE ,
safeWithdrawCode , null , userId , invoice . getSubmittedName ( ) ) ;
return true ;
}
@Override
@Transactional ( rollbackFor = Exception . class )
public boolean close ( String withdrawCode , String reason , Long operatorId , String operatorName ) {
String safeWithdrawCode = normalizeRequired ( withdrawCode , " 提现编号 " , 64 ) ;
if ( operatorId = = null | | operatorId < = 0 ) {
throw new ServiceException ( " 关闭操作人不能为空 " ) ;
}
ClearingWithdrawInvoice invoice = requireInvoice ( safeWithdrawCode ) ;
if ( MerchantWithdrawInvoiceConstants . STATUS_CLOSED . equals ( invoice . getInvoiceStatus ( ) ) ) {
return true ;
}
if ( ! MerchantWithdrawInvoiceConstants . STATUS_PENDING . equals ( invoice . getInvoiceStatus ( ) ) ) {
throw new ServiceException ( " 当前提现开票状态不允许关闭 " ) ;
}
Date now = DateUtils . getNowDate ( ) ;
String safeOperator = normalizeOperator ( operatorName , operatorId ) ;
String safeReason = normalizeRequired ( reason , " 关闭原因 " , 500 ) ;
invoice . setInvoiceStatus ( MerchantWithdrawInvoiceConstants . STATUS_CLOSED ) ;
invoice . setClosedBy ( operatorId ) ;
invoice . setClosedName ( safeOperator ) ;
invoice . setClosedTime ( now ) ;
invoice . setCloseReason ( safeReason ) ;
invoice . setUpdateBy ( safeOperator ) ;
invoice . setUpdateTime ( now ) ;
if ( clearingWithdrawInvoiceMapper . markClosed ( invoice ) = = 0 ) {
ClearingWithdrawInvoice current = requireInvoice ( safeWithdrawCode ) ;
if ( MerchantWithdrawInvoiceConstants . STATUS_CLOSED . equals ( current . getInvoiceStatus ( ) ) ) {
return true ;
}
throw new ServiceException ( " 当前提现开票状态不允许关闭 " ) ;
}
todoTaskService . cancelByBusiness ( MerchantWithdrawInvoiceConstants . BUSINESS_TYPE ,
safeWithdrawCode , null , safeOperator , safeReason ) ;
return true ;
}
private void completeClearingBills ( String withdrawCode ) {
List < ClearingBillInfo > billInfos = clearingBillInfoService . selectByWithdrawCode ( withdrawCode ) ;
if ( CollectionUtils . isEmpty ( billInfos ) ) {
return ;
}
for ( ClearingBillInfo billInfo : billInfos ) {
billInfo . setBillStatus ( " 4 " ) ;
}
clearingBillInfoService . updateBatchSelective ( billInfos ) ;
}
private ClearingWithdrawInvoice getOrCreateInvoice ( ClearingWithdrawInfo withdrawInfo ) {
ClearingWithdrawInvoice invoice = clearingWithdrawInvoiceMapper . selectByWithdrawCode ( withdrawInfo . getWithdrawCode ( ) ) ;
if ( invoice ! = null ) {
return invoice ;
}
invoice = new ClearingWithdrawInvoice ( ) ;
invoice . setWithdrawCode ( withdrawInfo . getWithdrawCode ( ) ) ;
invoice . setMerchantId ( withdrawInfo . getMerchantId ( ) ) ;
invoice . setInvoiceStatus ( MerchantWithdrawInvoiceConstants . STATUS_PENDING ) ;
invoice . setCreateBy ( " adapay-callback " ) ;
invoice . setDelFlag ( " 0 " ) ;
try {
clearingWithdrawInvoiceMapper . insertSelective ( invoice ) ;
return invoice ;
} catch ( DuplicateKeyException exception ) {
invoice = clearingWithdrawInvoiceMapper . selectByWithdrawCode ( withdrawInfo . getWithdrawCode ( ) ) ;
if ( invoice ! = null ) {
return invoice ;
}
throw exception ;
}
}
private void createTodos ( ClearingWithdrawInfo withdrawInfo ) {
if ( StringUtils . isBlank ( withdrawInfo . getMerchantId ( ) ) ) {
log . warn ( " 提现记录缺少运营商, 无法创建开票待办, withdrawCode={} " , withdrawInfo . getWithdrawCode ( ) ) ;
return ;
}
PileMerchantInfo merchantInfo ;
try {
merchantInfo = pileMerchantInfoService . selectPileMerchantInfoById ( Long . parseLong ( withdrawInfo . getMerchantId ( ) ) ) ;
} catch ( NumberFormatException exception ) {
log . warn ( " 提现记录运营商 ID 非法, 无法创建开票待办, withdrawCode={}, merchantId={} " ,
withdrawInfo . getWithdrawCode ( ) , withdrawInfo . getMerchantId ( ) ) ;
return ;
}
if ( merchantInfo = = null | | StringUtils . isBlank ( merchantInfo . getDeptId ( ) ) ) {
log . warn ( " 提现记录运营商未配置部门, 无法创建开票待办, withdrawCode={}, merchantId={} " ,
withdrawInfo . getWithdrawCode ( ) , withdrawInfo . getMerchantId ( ) ) ;
return ;
}
Long deptId ;
try {
deptId = Long . parseLong ( merchantInfo . getDeptId ( ) ) ;
} catch ( NumberFormatException exception ) {
log . warn ( " 提现记录运营商部门 ID 非法, 无法创建开票待办, withdrawCode={}, deptId={} " ,
withdrawInfo . getWithdrawCode ( ) , merchantInfo . getDeptId ( ) ) ;
return ;
}
List < Long > assigneeUserIds = todoTaskAssigneeService . findActiveOperatorAdminUserIdsByDeptTree ( deptId ) ;
if ( CollectionUtils . isEmpty ( assigneeUserIds ) ) {
log . warn ( " 提现记录运营商部门下没有正常管理员, 无法创建开票待办, withdrawCode={}, deptId={} " ,
withdrawInfo . getWithdrawCode ( ) , deptId ) ;
return ;
}
String routeParams = buildRouteParams ( withdrawInfo ) ;
for ( Long assigneeUserId : assigneeUserIds ) {
String idempotentKey = MerchantWithdrawInvoiceConstants . TASK_TYPE + " : "
+ MerchantWithdrawInvoiceConstants . BUSINESS_TYPE + " : "
+ withdrawInfo . getWithdrawCode ( ) + " : " + assigneeUserId ;
todoTaskService . createTask ( TodoTaskCreateCommand . builder ( )
. taskType ( MerchantWithdrawInvoiceConstants . TASK_TYPE )
. title ( " 运营商提现向平台开票 " )
. summary ( " 提现已成功,请向平台提交发票,提现编号: " + withdrawInfo . getWithdrawCode ( ) )
. businessType ( MerchantWithdrawInvoiceConstants . BUSINESS_TYPE )
. businessId ( withdrawInfo . getWithdrawCode ( ) )
. routeName ( MerchantWithdrawInvoiceConstants . ROUTE_NAME )
. routeParams ( routeParams )
. assigneeUserId ( assigneeUserId )
. assigneeMerchantId ( withdrawInfo . getMerchantId ( ) )
. priority ( TodoTaskConstants . PRIORITY_IMPORTANT )
. idempotentKey ( idempotentKey )
. createBy ( " adapay-callback " )
. build ( ) ) ;
}
}
private String buildRouteParams ( ClearingWithdrawInfo withdrawInfo ) {
Map < String , Object > query = new HashMap < > ( 2 ) ;
query . put ( " merchantId " , withdrawInfo . getMerchantId ( ) ) ;
query . put ( " withdrawCode " , withdrawInfo . getWithdrawCode ( ) ) ;
Map < String , Object > routeParams = new HashMap < > ( 1 ) ;
routeParams . put ( " query " , query ) ;
return JSON . toJSONString ( routeParams ) ;
}
private SysTodoTask validateTodo ( String withdrawCode , Long todoId , Long userId ) {
SysTodoTask todoTask = todoTaskService . getForAssignee ( todoId , userId ) ;
if ( ! MerchantWithdrawInvoiceConstants . TASK_TYPE . equals ( todoTask . getTaskType ( ) )
| | ! MerchantWithdrawInvoiceConstants . BUSINESS_TYPE . equals ( todoTask . getBusinessType ( ) )
| | ! withdrawCode . equals ( todoTask . getBusinessId ( ) ) ) {
throw new ServiceException ( " 待办任务与提现开票信息不匹配 " ) ;
}
return todoTask ;
}
private ClearingWithdrawInvoice requireInvoice ( String withdrawCode ) {
ClearingWithdrawInvoice invoice = clearingWithdrawInvoiceMapper . selectByWithdrawCode ( withdrawCode ) ;
if ( invoice = = null ) {
throw new ServiceException ( " 提现开票信息不存在 " ) ;
}
return invoice ;
}
private MerchantWithdrawInvoiceVO buildView ( ClearingWithdrawInvoice invoice ,
ClearingWithdrawInfo withdrawInfo ) {
MerchantWithdrawInvoiceVO view = new MerchantWithdrawInvoiceVO ( ) ;
BeanUtils . copyProperties ( invoice , view ) ;
if ( withdrawInfo ! = null ) {
view . setWithdrawAmt ( withdrawInfo . getWithdrawAmt ( ) ) ;
view . setFeeAmt ( withdrawInfo . getFeeAmt ( ) ) ;
view . setCreditedAmt ( withdrawInfo . getCreditedAmt ( ) ) ;
view . setApplicationTime ( withdrawInfo . getApplicationTime ( ) ) ;
view . setArrivalTime ( withdrawInfo . getArrivalTime ( ) ) ;
}
return view ;
}
private String normalizeRequired ( String value , String fieldName , int maxLength ) {
String safeValue = StringUtils . trim ( value ) ;
if ( StringUtils . isEmpty ( safeValue ) ) {
throw new ServiceException ( fieldName + " 不能为空 " ) ;
}
if ( safeValue . length ( ) > maxLength ) {
throw new ServiceException ( fieldName + " 不能超过 " + maxLength + " 个字符 " ) ;
}
return safeValue ;
}
private String normalizeOperator ( String operatorName , Long operatorId ) {
String safeOperator = StringUtils . isNotEmpty ( operatorName )
? operatorName . trim ( ) : String . valueOf ( operatorId ) ;
if ( safeOperator . length ( ) > 64 ) {
throw new ServiceException ( " 操作人名称不能超过64个字符 " ) ;
}
return safeOperator ;
}
}