Merge #81 into master from cc_20260320_standard_expense_Type

feat:时间调整

* cc_20260320_standard_expense_Type: (40 commits squashed)

  - feat:费用类型新增

  - feat:费用类型

  - feat:默认数据

  - feat:类型调整

  - Merge branch 'master' into cc_20260320_standard_expense_Type

  - feat:逻辑调整

  - Merge branch 'master' into cc_20260320_standard_expense_Type

  - feat:逻辑调整-标准店

  - feat:逻辑调整-标准店

  - feat:逻辑调整-标准店

  - feat:逻辑调整-标准店

  - feat:查询预分账调整

  - feat:查询预分账调整

  - feat:心愿单 校验调整

  - feat:心愿单 校验调整

  - feat:心愿单 金额校验调整

  - feat:心愿单 金额校验调整

  - feat:心愿单 金额校验调整

  - feat:先推送账单 再推送

  - feat:先推送账单 再推送

  - feat:先推送账单 再推送

  - feat:先推送账单 再推送

  - feat:先推送账单 再推送

  - feat:先推送账单 再推送 优化推送 当系统使用费为零的时候 推送数据重置的问题

  - Merge branch 'master' into cc_20260320_standard_expense_Type

  - feat:接口新增字段

  - feat:接口新增字段

  - feat:接口新增字段

  - feat:接口新增字段

  - feat:接口新增字段

  - feat:接口新增字段

  - feat:数据调整

  - feat:新增系统服务费

  - feat:新增系统服务费 319

  - feat:新增系统服务费 319

  - feat:新增系统服务费 319

  - feat:时间调整

  - feat:时间调整

  - feat:时间调整

  - feat:时间调整

Signed-off-by: 正新 <accounts_6964c7bcd2a2c377c5bbd01b@mail.teambition.com>
Merged-by: 正新 <accounts_6964c7bcd2a2c377c5bbd01b@mail.teambition.com>

CR-link: https://codeup.aliyun.com/692ea314dec569489f6f167c/hangzhou/java/custom_zxjp/change/81
This commit is contained in:
正新
2026-03-30 13:20:15 +00:00
parent d03bdb7cb0
commit 310ae0be7d
50 changed files with 1606 additions and 325 deletions

View File

@@ -45,6 +45,8 @@ public class ConfigItemServiceImpl implements ConfigItemService {
entity.setSortNo(request.getSortNo());
entity.setStatus(request.getStatus());
entity.setRemark(request.getRemark());
entity.setExpenseTypeCode(request.getExpenseTypeCode());
entity.setMultipleChoice(request.getMultipleChoice());
entity.setCreatedTime(new Date());
entity.setCreatedUserId(userInfo.getUserId());
entity.setIsDeleted(0);
@@ -66,6 +68,8 @@ public class ConfigItemServiceImpl implements ConfigItemService {
entity.setSortNo(request.getSortNo());
entity.setStatus(request.getStatus());
entity.setRemark(request.getRemark());
entity.setExpenseTypeCode(request.getExpenseTypeCode());
entity.setMultipleChoice(request.getMultipleChoice());
entity.setUpdatedTime(new Date());
entity.setUpdatedUserId(userInfo.getUserId());
return configItemDAO.updateSelective(entity);

View File

@@ -65,7 +65,8 @@ public class ConfigOptionServiceImpl implements ConfigOptionService {
@Override
public PageInfo<ConfigOptionVO> queryPage(ConfigOptionQueryRequest request) {
PageHelper.startPage(request.getPageNum(), request.getPageSize());
List<ConfigOptionDO> list = configOptionDAO.query(request.getCategoryCode(), request.getItemCode(), request.getActive(), request.getOptionName());
List<ConfigOptionDO> list = configOptionDAO.query(request.getCategoryCode(), request.getItemCode(),
request.getActive(), request.getOptionName(),request.getExpenseTypeCode());
return BeanUtil.toPage(new PageInfo<>(list), ConfigOptionVO.class);
}
@@ -83,7 +84,7 @@ public class ConfigOptionServiceImpl implements ConfigOptionService {
.collect(Collectors.toMap(ConfigItemVO::getItemCode, Function.identity(), (a, b) -> a));
// 3) 一次性查询所有激活的配置选项(可选模糊名称)
List<ConfigOptionDO> options = configOptionDAO.query(null, null, 1, null);
List<ConfigOptionDO> options = configOptionDAO.query(null, null, 1, null,null);
if (CollectionUtils.isEmpty(options)) {
return Collections.emptyList();
}

View File

@@ -126,7 +126,7 @@ public class WalletPayInfoServiceImpl implements WalletPayInfoService {
assert feeItem != null;
return new BatchTransferRequest.TransDataRequest(payNo, feeItem.getFeeItemId(), shopAllocationInfoDO.getPayeeCode(), null, payAmount.toString(), feeItem.getDesc());
});
BatchTransferRequest transRequest = new BatchTransferRequest(walletType, shopInfo.getStoreId(), request.getPayPwd(), transDataList);
BatchTransferRequest transRequest = new BatchTransferRequest(walletType, shopInfo.getStoreId(), request.getPayPwd(),0, transDataList);
BatchTransferDTO batchTransferDTO = walletApiService.batchTransfer(transRequest);
if (CollectionUtils.isEmpty(batchTransferDTO.getTransArray())) {
throw new ServiceException(ErrorCodeEnum.WALLET_TRANS_FAIL);

View File

@@ -129,7 +129,7 @@ public class FranchiseFeeServiceImpl implements FranchiseFeeService {
LineInfoDO lineInfoDO = lineInfoMapper.getByLineId(shopInfoDO.getLineId());
commonService.sendSms(lineInfoDO.getMobile(), SMSMsgEnum.PAY_FRANCHISE_FEES);
//推送加盟费信息到新管家
PushFranchiseFeeRequest feeRequest = new PushFranchiseFeeRequest(shopInfoDO.getId(), lineInfoDO.getUsername(), franchiseFeeDO);
PushFranchiseFeeRequest feeRequest = new PushFranchiseFeeRequest(shopInfoDO.getId(), lineInfoDO.getUsername(), franchiseFeeDO,Integer.valueOf(shopInfoDO.getFranchiseBrand()));
feeRequest.setJoinBrand(Integer.valueOf(shopInfoDO.getFranchiseBrand()));
pushService.pushFranchiseFeeToXGJ(feeRequest);
return true;
@@ -179,7 +179,7 @@ public class FranchiseFeeServiceImpl implements FranchiseFeeService {
shopAllocationInfoService.updateBatch(request.getShopId(), request.getShopAllocationInfoList());
//推送加盟费信息到新管家
franchiseFeeDO.setCreateTime(franchiseFeeDO1.getCreateTime());
PushFranchiseFeeRequest feeRequest = new PushFranchiseFeeRequest(shopInfoDO.getId(), lineInfoDO.getUsername(), franchiseFeeDO);
PushFranchiseFeeRequest feeRequest = new PushFranchiseFeeRequest(shopInfoDO.getId(), lineInfoDO.getUsername(), franchiseFeeDO,Integer.valueOf(shopInfoDO.getFranchiseBrand()));
feeRequest.setJoinBrand(Integer.valueOf(shopInfoDO.getFranchiseBrand()));
pushService.pushFranchiseFeeToXGJ(feeRequest);
return true;
@@ -313,6 +313,16 @@ public class FranchiseFeeServiceImpl implements FranchiseFeeService {
franchiseFeeDO.setXgjCollectionStatus(request.getPaymentStatus());
franchiseFeeDO.setXgjRemainderPayableAmount(request.getRemainingFee());
franchiseFeeDO.setXgjFeesPaid(request.getPaidFees());
List<ShopSubStageStatusEnum> stageList = new ArrayList<>();
if (shopInfoDO.getUseStandardStore()==0){
stageList.add(SHOP_SUB_STAGE_STATUS_73);
stageList.add(SHOP_SUB_STAGE_STATUS_80);
}else {
//标准店
stageList.add(SHOP_SUB_STAGE_STATUS_285);
stageList.add(SHOP_SUB_STAGE_STATUS_80);
}
if (request.getPayableFee().compareTo(request.getPaidFees())==-1){
franchiseFeeDO.setXgjRemainderPayableAmount(new BigDecimal("0"));
franchiseFeeDO.setXgjCollectionStatus(XGJCollectionStatusEnum.COMPLETED.getCode());
@@ -322,15 +332,15 @@ public class FranchiseFeeServiceImpl implements FranchiseFeeService {
lastPay.setRemark(lastPay.getRemark()+"系统监测到您多缴费"+request.getPaidFees().subtract(request.getPayableFee())+"元 请申请退款或留做他用!");
linePayMapper.updateByPrimaryKeySelective(lastPay);
ShopStageInfoDO shopStageStatus = shopStageInfoDAO.getShopSubStageInfo(request.getShopId(), ShopSubStageEnum.SHOP_STAGE_8);
if (SHOP_SUB_STAGE_STATUS_00.getShopSubStageStatus().equals(shopStageStatus.getShopSubStageStatus())){
shopStageInfoDAO.batchUpdateShopStageStatus(request.getShopId(),Arrays.asList(SHOP_SUB_STAGE_STATUS_73,SHOP_SUB_STAGE_STATUS_80));
if (shopStageStatus!=null&&SHOP_SUB_STAGE_STATUS_00.getShopSubStageStatus().equals(shopStageStatus.getShopSubStageStatus())){
shopStageInfoDAO.batchUpdateShopStageStatus(request.getShopId(),stageList);
}
}
franchiseFeeMapper.updateByPrimaryKeySelective(franchiseFeeDO);
if (XGJCollectionStatusEnum.COMPLETED.getCode().equals(request.getPaymentStatus())){
ShopStageInfoDO shopStageStatus = shopStageInfoDAO.getShopSubStageInfo(request.getShopId(), ShopSubStageEnum.SHOP_STAGE_8);
if (SHOP_SUB_STAGE_STATUS_00.getShopSubStageStatus().equals(shopStageStatus.getShopSubStageStatus())){
shopStageInfoDAO.batchUpdateShopStageStatus(request.getShopId(),Arrays.asList(SHOP_SUB_STAGE_STATUS_73,SHOP_SUB_STAGE_STATUS_80));
if (shopStageStatus!=null&&SHOP_SUB_STAGE_STATUS_00.getShopSubStageStatus().equals(shopStageStatus.getShopSubStageStatus())){
shopStageInfoDAO.batchUpdateShopStageStatus(request.getShopId(),stageList);
}
}
return ApiResponse.success(Boolean.TRUE);

View File

@@ -8,6 +8,7 @@ import com.cool.store.constants.DictConstants;
import com.cool.store.context.LoginUserInfo;
import com.cool.store.dao.*;
import com.cool.store.dao.fees.WalletPayInfoDAO;
import com.cool.store.dao.order.PreAllocationRecordDAO;
import com.cool.store.dto.ContractInformationDTO;
import com.cool.store.dao.decoration.DecorationTeamConfigDAO;
import com.cool.store.dao.decoration.ShopDecorationAssignDAO;
@@ -20,6 +21,7 @@ import com.cool.store.entity.decoration.DecorationTeamConfigDO;
import com.cool.store.entity.decoration.ShopDecorationAssignDO;
import com.cool.store.entity.decoration.TeamAreaMappingDO;
import com.cool.store.entity.fees.WalletPayInfoDO;
import com.cool.store.entity.order.PreAllocationRecordDO;
import com.cool.store.enums.*;
import com.cool.store.enums.Decoration.DecorationDescStatus;
import com.cool.store.enums.fees.AllocationPayStatusEnum;
@@ -168,6 +170,8 @@ public class SignFranchiseServiceImpl implements SignFranchiseService, AuditResu
private WalletPayInfoDAO walletPayInfoDAO;
@Resource
private SignFranchiseService signFranchiseService;
@Resource
private PreAllocationRecordDAO preAllocationRecordDAO;
@Override
@@ -1009,6 +1013,7 @@ public class SignFranchiseServiceImpl implements SignFranchiseService, AuditResu
.orElse(null);
addSignFranchiseResponse.setPayDate(earliestPayTime);
}
if(CollectionUtils.isNotEmpty(payInfoList)){
Set<String> payNameSet = new HashSet<>();
List<Date> payTimeList = new ArrayList<>();
@@ -1064,6 +1069,16 @@ public class SignFranchiseServiceImpl implements SignFranchiseService, AuditResu
addSignFranchiseResponse.setCashierFee(franchiseFeeDO.getCashierFee());
addSignFranchiseResponse.setBigCashierFee(Convert.digitToChinese(convertToBig(franchiseFeeDO.getCashierFee())));
}
if (CollectionUtils.isEmpty(linePayList)){
List<PreAllocationRecordDO> preAllocationRecordDOS = preAllocationRecordDAO.queryPageByShopId(shopId);
List<Date> dateList = preAllocationRecordDOS.stream().map(PreAllocationRecordDO::getCreateTime).collect(Collectors.toList());
Date earliestPayTime = dateList.stream().filter(Objects::nonNull)
.min(Comparator.naturalOrder())
.orElse(null);
addSignFranchiseResponse.setPayDate(earliestPayTime);
addSignFranchiseResponse.setFirstYearStartTime(earliestPayTime);
addSignFranchiseResponse.setFirstYearEndTime(DateUtils.addDays(DateUtils.addYears(earliestPayTime,1),-1));
}
return addSignFranchiseResponse;
}

View File

@@ -1,6 +1,7 @@
package com.cool.store.service.order;
import com.cool.store.context.LoginUserInfo;
import com.cool.store.entity.order.StoreOrderDO;
import com.cool.store.request.order.*;
import com.cool.store.vo.PartnerUserInfoVO;
import com.cool.store.vo.order.MiniStoreOrderDetailVO;
@@ -44,7 +45,9 @@ public interface MiniStoreOrderService {
List<WalletPayVO> payList(Long shopId);
Boolean batchUpdateOptionQuantity(PCStoreOrderOptionQuantityUpdateRequest request);
Boolean managerOrder(PCStoreOrderOptionQuantityUpdateRequest request,LoginUserInfo userInfo);
Boolean batchUpdateOptionQuantity(PCStoreOrderOptionQuantityUpdateRequest request,LoginUserInfo userInfo);
Boolean saveOrUpdateWishlist(MiniStoreWishlistSaveRequest request, PartnerUserInfoVO userInfoVO);
@@ -52,7 +55,7 @@ public interface MiniStoreOrderService {
MiniStoreWishlistDetailVO wishlistDetail(Long wishlistId);
List<MiniStoreWishlistListVO> wishlistList(PartnerUserInfoVO userInfoVO);
List<MiniStoreWishlistListVO> wishlistList(Long lineId,Integer wishlistStatus);
PageInfo<MiniStoreWishlistListVO> wishAllList(WishAllListRequest request);
@@ -61,4 +64,8 @@ public interface MiniStoreOrderService {
Boolean wishlistApprove(WishlistAuditRequest request,LoginUserInfo userInfo);
MiniStoreWishlistDetailVO getCurrentShopBindWishlist(Long shopId);
Boolean changeWishlist(ChangeWishlistRequest request);
}

View File

@@ -34,6 +34,7 @@ import com.cool.store.entity.store.StoreTypeOptionDO;
import com.cool.store.entity.wallet.WalletTradeDO;
import com.cool.store.enums.*;
import com.cool.store.enums.fees.AllocationPayStatusEnum;
import com.cool.store.enums.fees.PayTypeEnum;
import com.cool.store.enums.fees.WalletFeeItemEnum;
import com.cool.store.enums.order.StoreOrderStatusEnum;
import com.cool.store.enums.order.WishlistStatusEnum;
@@ -41,6 +42,7 @@ import com.cool.store.enums.point.ShopSubStageStatusEnum;
import com.cool.store.enums.wallet.WalletTradeModuleEnum;
import com.cool.store.exception.ServiceException;
import com.cool.store.dto.wallet.BatchTransferDTO;
import com.cool.store.mapper.FranchiseFeeMapper;
import com.cool.store.mapper.ShopAuditInfoMapper;
import com.cool.store.request.PointRecommendLineRequest;
import com.cool.store.request.SelectPointRequest;
@@ -48,10 +50,8 @@ import com.cool.store.request.SysRoleRequest;
import com.cool.store.request.order.*;
import com.cool.store.request.dict.DictColumnQueryRequest;
import com.cool.store.request.wallet.BatchTransferRequest;
import com.cool.store.service.OperationLogService;
import com.cool.store.service.PointService;
import com.cool.store.service.ShopService;
import com.cool.store.service.UserAuthMappingService;
import com.cool.store.request.xgj.PushFranchiseFeeRequest;
import com.cool.store.service.*;
import com.cool.store.service.dict.DictColumnService;
import com.cool.store.service.order.MiniStoreOrderService;
import com.cool.store.service.store.PreAllocationRecordService;
@@ -72,6 +72,7 @@ import com.cool.store.vo.order.WalletPayVO;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.google.common.collect.Lists;
import groovy.util.logging.Slf4j;
import io.swagger.models.auth.In;
import lombok.RequiredArgsConstructor;
@@ -130,6 +131,9 @@ public class MiniStoreOrderServiceImpl implements MiniStoreOrderService {
private final PointService pointService;
private final PointInfoDAO pointInfoDAO;
private final ShopService shopService;
private final FranchiseFeeMapper franchiseFeeMapper;
private final PushService pushService;
private final StoreOrderOptionSnapshotDAO storeOrderOptionSnapshotDAO;
@Override
@@ -267,6 +271,7 @@ public class MiniStoreOrderServiceImpl implements MiniStoreOrderService {
.optionRemark(template.getOptionRemark())
.imageUrl(template.getImageUrl())
.optionUnit(template.getOptionUnit())
.expenseTypeCode(template.getExpenseTypeCode())
.videoUrl(template.getVideoUrl())
.quantity(quantity)
.amount(amount)
@@ -342,15 +347,17 @@ public class MiniStoreOrderServiceImpl implements MiniStoreOrderService {
//阶段状态
shopStageInfoDAO.updateShopStageInfo(request.getShopId(), ShopSubStageStatusEnum.SHOP_SUB_STAGE_STATUS_281);
operationLogService.addOperationLog(request.getShopId(), ShopSubStageStatusEnum.SHOP_SUB_STAGE_STATUS_280, user.getPartnerId(), user.getUsername(),
OperationTypeEnum.OPERATION_TYPE_0, "店型选购提交", OperationStatusEnum.PROCESSED);
if (user!=null){
operationLogService.addOperationLog(request.getShopId(), ShopSubStageStatusEnum.SHOP_SUB_STAGE_STATUS_280, user.getPartnerId(), user.getUsername(),
OperationTypeEnum.OPERATION_TYPE_0, "店型选购提交", OperationStatusEnum.PROCESSED);
SysRoleRequest sysRoleRequest = new SysRoleRequest();
sysRoleRequest.setRoleName(AI_STORE_TYPE_APPROVE.getDesc());
List<EnterpriseUserDO> userListByRole = userAuthMappingService.findUserListByRole(sysRoleRequest, false);
operationLogService.addOperationLog(request.getShopId(), ShopSubStageStatusEnum.SHOP_SUB_STAGE_STATUS_281,
user.getPartnerId(), userListByRole,
OperationTypeEnum.OPERATION_TYPE_1, "店型选购待立规审批", OperationStatusEnum.NOT_PROCESSED, 1);
SysRoleRequest sysRoleRequest = new SysRoleRequest();
sysRoleRequest.setRoleName(AI_STORE_TYPE_APPROVE.getDesc());
List<EnterpriseUserDO> userListByRole = userAuthMappingService.findUserListByRole(sysRoleRequest, false);
operationLogService.addOperationLog(request.getShopId(), ShopSubStageStatusEnum.SHOP_SUB_STAGE_STATUS_281,
user.getPartnerId(), userListByRole,
OperationTypeEnum.OPERATION_TYPE_1, "店型选购待立规审批", OperationStatusEnum.NOT_PROCESSED, 1);
}
return order.getId();
}
@@ -418,7 +425,11 @@ public class MiniStoreOrderServiceImpl implements MiniStoreOrderService {
LinkedHashMap::new,
Collectors.toList())));
List<MiniStoreOrderDetailVO.CategoryVO> categoryVOList = new ArrayList<>();
Set<Long> optinIdList = list.stream().map(StoreOrderOptionSnapshotDO::getOptionId).collect(Collectors.toSet());
List<StoreTypeOptionDO> storeTypeOptionDOS = storeTypeOptionDAO.selectByIds(new ArrayList<>(optinIdList),orderInfo.getStoreTypeId());
Map<Long, BigDecimal> defaultQuantityMap = storeTypeOptionDOS.stream().collect(Collectors.toMap(StoreTypeOptionDO::getOptionId, StoreTypeOptionDO::getDefaultQuantity,(existing, replacement) -> existing));
List<MiniStoreOrderDetailVO.CategoryVO> categoryVOList = new ArrayList<>();
for (Map.Entry<String, Map<String, List<StoreOrderOptionSnapshotDO>>> cEntry : groupMap.entrySet()) {
String categoryCode = cEntry.getKey();
MiniStoreOrderDetailVO.CategoryVO cvo = new MiniStoreOrderDetailVO.CategoryVO();
@@ -444,6 +455,8 @@ public class MiniStoreOrderServiceImpl implements MiniStoreOrderService {
ovo.setAmount(v.getAmount());
ovo.setOriginalAmount(v.getOriginalAmount());
ovo.setImageUrl(v.getImageUrl());
ovo.setExpenseTypeCode(v.getExpenseTypeCode());
ovo.setDefaultQuantity(defaultQuantityMap.get(v.getOptionId()));
return ovo;
})
.collect(Collectors.toList());
@@ -585,10 +598,14 @@ public class MiniStoreOrderServiceImpl implements MiniStoreOrderService {
//修改阶段数据
shopStageInfoDAO.updateShopStageInfo(order.getShopId(),ShopSubStageStatusEnum.SHOP_SUB_STAGE_STATUS_282);
//推送加盟费账单
preAllocationRecordService.pushStandardStoreFee(order);
}
return Boolean.TRUE;
}
@Override
@Transactional(rollbackFor = Exception.class)
public Boolean rejectOrder(OrderAuditRecordRequest request,LoginUserInfo userInfo) {
@@ -625,7 +642,11 @@ public class MiniStoreOrderServiceImpl implements MiniStoreOrderService {
shopAuditInfoDO.setSubmittedUserId(user.getUserId());
shopAuditInfoDO.setSubmittedUserName(user.getName());
shopAuditInfoDO.setResultType(resultType);
shopAuditInfoDO.setRejectReason(remark);
if (resultType==0){
shopAuditInfoDO.setPassReason(remark);
}else {
shopAuditInfoDO.setRejectReason(remark);
}
shopAuditInfoMapper.insertSelective(shopAuditInfoDO);
Long auditId = shopAuditInfoDO.getId();
List<OperationLogDO> operationLogs = operationLogDAO.getBySubStageStatusEnumAndsStatus(shopId, stageStatusEnum, OperationTypeEnum.OPERATION_TYPE_1.getCode());
@@ -636,6 +657,7 @@ public class MiniStoreOrderServiceImpl implements MiniStoreOrderService {
@Override
@Transactional
public Long updateOrder(MiniStoreOrderUpdateRequest request,PartnerUserInfoVO user) {
log.info("updateOrder request:{},操作人:{}",JSONObject.toJSONString(request),user.getUsername());
if (request == null || request.getOrderId() == null || request.getShopId() == null || request.getStoreTypeId() == null) {
throw new ServiceException(ErrorCodeEnum.PARAMS_VALIDATE_ERROR);
}
@@ -753,6 +775,7 @@ public class MiniStoreOrderServiceImpl implements MiniStoreOrderService {
.originalOptionPrice(originalPrice)
.optionUnit(template.getOptionUnit())
.optionRemark(template.getOptionRemark())
.expenseTypeCode(template.getExpenseTypeCode())
.imageUrl(template.getImageUrl())
.videoUrl(template.getVideoUrl())
.quantity(quantity)
@@ -904,254 +927,254 @@ public class MiniStoreOrderServiceImpl implements MiniStoreOrderService {
@Override
@Transactional
public Boolean payOrder(MiniStoreOrderPayRequest request, PartnerUserInfoVO userInfo) {
log.info("订单开始支付 payOrder{},userInfo:{}", JSONObject.toJSONString(request),JSONObject.toJSONString(userInfo));
//重复支付校验
String lockKey = MessageFormat.format(RedisConstant.STANDARD_STORE_PAY_LOCK_KEY, request.getOrderId());
Boolean lock = redisUtil.tryLock(lockKey, lockKey, 10, TimeUnit.SECONDS);
if (!Boolean.TRUE.equals(lock)) {
throw new ServiceException(ErrorCodeEnum.DUPLICATE_PAYMENTS);
}
try {
// 1. 参数校验
if (request == null || request.getOrderId() == null || request.getAmount() == null ||
StringUtils.isBlank(request.getPayPwd())) {
throw new ServiceException(ErrorCodeEnum.PARAMS_VALIDATE_ERROR);
}
// 2. 查询订单信息
StoreOrderDO order = storeOrderDAO.getById(request.getOrderId());
if (order == null) {
throw new ServiceException(ErrorCodeEnum.STORE_ORDER_NOT_FOUND);
}
// 3. 校验订单状态:仅待支付状态可以支付
if (!StoreOrderStatusEnum.WAIT_PAY.getCode().equals(order.getStatus())) {
throw new ServiceException(ErrorCodeEnum.STORE_ORDER_STATUS_INVALID);
}
// 4. 校验支付金额与订单金额是否一致
if (request.getAmount().compareTo(order.getTotalAmount()) != 0) {
throw new ServiceException(ErrorCodeEnum.PAY_AMOUNT_ERROR);
}
// 5. 查询门店信息
ShopInfoDO shopInfo = shopInfoDAO.getShopInfo(order.getShopId());
if (shopInfo == null) {
throw new ServiceException(ErrorCodeEnum.SHOP_NOT_EXIST);
}
// 6. 按门店查询预分账明细
List<PreAllocationRecordDO> allocationRecords = preAllocationRecordService.listDOByShop(order.getShopId());
if (CollectionUtils.isEmpty(allocationRecords)) {
throw new ServiceException(ErrorCodeEnum.THERE_IS_NO_PAYMENT_INFORMATION);
}
// 7. 校验预分账明细金额总和是否等于订单金额
BigDecimal allocationTotal = allocationRecords.stream()
.filter(record -> record != null && record.getPayAmount() != null)
.map(PreAllocationRecordDO::getPayAmount)
.reduce(BigDecimal.ZERO, BigDecimal::add);
if (allocationTotal.compareTo(order.getTotalAmount()) != 0) {
throw new ServiceException(ErrorCodeEnum.FEE_NOT_CONSISTENT);
}
// 9. 封装批量分账请求
BatchTransferRequest batchTransferRequest = new BatchTransferRequest();
batchTransferRequest.setOutStoreId(shopInfo.getStoreId());
batchTransferRequest.setPayPwd(request.getPayPwd());
batchTransferRequest.setWalletType(2);
List<BatchTransferRequest.TransDataRequest> transArray = new ArrayList<>();
for (PreAllocationRecordDO record : allocationRecords) {
BatchTransferRequest.TransDataRequest transData = new BatchTransferRequest.TransDataRequest();
// payNo 必须唯一且失败重试要沿用第一次的 payNo
String payNo = record.getPayNo();
if (StringUtils.isBlank(payNo)) {
payNo = GenerateNoUtil.generateMillsNoWithRandom();
record.setPayNo(payNo);
}
transData.setReqNo(payNo);
// 根据费用类型获取费用科目ID
WalletFeeItemEnum feeItem = WalletFeeItemEnum.getByExpenseType(record.getExpenseType());
if (feeItem == null) {
throw new ServiceException(ErrorCodeEnum.NONSUPPORT_EXPENSE_TYPE);
}
transData.setFeeItemId(feeItem.getFeeItemId());
transData.setCompanyCode(record.getPayeeCode());
transData.setAmount(record.getPayAmount().toString());
transArray.add(transData);
}
batchTransferRequest.setTransArray(transArray);
Map<String, PreAllocationRecordDO> map = allocationRecords.stream().collect(Collectors.toMap(PreAllocationRecordDO::getPayNo, data -> data));
// 调用第三方前先固化 payNo失败重试需要复用
preAllocationRecordDAO.updateBatch(allocationRecords);
// 10. 调用第三方分账接口
BatchTransferDTO batchTransferResult;
try {
batchTransferResult = walletApiService.batchTransfer(batchTransferRequest);
} catch (Exception e) {
throw new ServiceException(ErrorCodeEnum.THIRD_API_ERROR.getCode(), "支付失败:" + e.getMessage());
}
// 11. 处理分账结果
if (batchTransferResult == null || batchTransferResult.getTradeStatus() == null) {
throw new ServiceException(ErrorCodeEnum.THIRD_API_ERROR.getCode(), "支付失败:分账接口返回异常");
}
// 12. 根据分账结果更新状态和记录
List<WalletPayInfoDO> walletPayInfoList = new ArrayList<>();
List<WalletTradeDO> walletTradeList = new ArrayList<>();
List<PreAllocationRecordDO> updatedRecords = new ArrayList<>();
//批量支付状态 1.成功 2.失败 3.处理中(目前是实时转账 无处理中)
Integer tradeStatus = batchTransferResult.getTradeStatus();
// 订单状态
Integer orderStatus = null;
// 按批次结果全成/全败
Integer allocationStatus;
Integer payStatus;
if (tradeStatus != null && tradeStatus == 1) {
allocationStatus = 1;
payStatus = AllocationPayStatusEnum.PAID.getStatus();
orderStatus = StoreOrderStatusEnum.PAID.getCode();
} else {
allocationStatus = 0;
payStatus = AllocationPayStatusEnum.FAIL.getStatus();
orderStatus = PAY_FAIL.getCode();
}
// 无论成功失败,都需要落库,并更新预分账状态
if (batchTransferResult.getTransArray() != null) {
for (int i = 0; i < batchTransferResult.getTransArray().size() && i < allocationRecords.size(); i++) {
BatchTransferDTO.TransDataRequest result = batchTransferResult.getTransArray().get(i);
PreAllocationRecordDO record = map.get(result.getReqNo());
if (record == null) {
continue;
}
record.setAllocationStatus(allocationStatus);
updatedRecords.add(record);
WalletPayInfoDO walletPayInfo = new WalletPayInfoDO();
walletPayInfo.setShopId(order.getShopId());
walletPayInfo.setModule(STANDARD_STORE.getModule());
walletPayInfo.setPayNo(result.getReqNo());
walletPayInfo.setPayUserName(userInfo.getUsername());
walletPayInfo.setPayAmount(new BigDecimal(result.getAmount()));
walletPayInfo.setPayStatus(payStatus);
walletPayInfo.setPayTime(new Date());
walletPayInfo.setClaimStatus(ClaimStatusEnum.TO_BE_CLAIMED.getCode());
walletPayInfo.setExpenseTypes(record.getExpenseType());
walletPayInfo.setCreateTime(new Date());
walletPayInfo.setTradeId(result.getTradeId());
walletPayInfoList.add(walletPayInfo);
WalletTradeDO walletTrade = new WalletTradeDO();
walletTrade.setModule(STANDARD_STORE.getModule());
walletTrade.setPayNo(result.getReqNo());
walletTrade.setTradeId(result.getTradeId());
walletTrade.setType(1);
walletTrade.setPayUserName(userInfo.getUsername());
walletTrade.setPayAmount(new BigDecimal(result.getAmount()));
walletTrade.setPayStatus(payStatus);
walletTrade.setPayTime(new Date());
walletTrade.setCreateTime(new Date());
walletTradeList.add(walletTrade);
}
}
// 13. 保存钱包支付信息/交易单payNo 唯一索引,存在则更新,不存在则插入(批量处理)
List<String> payNoList = walletPayInfoList.stream()
.map(WalletPayInfoDO::getPayNo)
.filter(StringUtils::isNotBlank)
.distinct()
.collect(Collectors.toList());
Set<String> existPayNoSet = new HashSet<>();
if (CollectionUtils.isNotEmpty(payNoList)) {
List<WalletPayInfoDO> existList = walletPayInfoDAO.getByPayNoList(payNoList);
if (CollectionUtils.isNotEmpty(existList)) {
existPayNoSet = existList.stream().map(WalletPayInfoDO::getPayNo).collect(Collectors.toSet());
}
}
List<WalletPayInfoDO> walletPayInfoInsertList = new ArrayList<>();
List<WalletPayInfoDO> walletPayInfoUpdateList = new ArrayList<>();
for (WalletPayInfoDO v : walletPayInfoList) {
if (v == null || StringUtils.isBlank(v.getPayNo())) {
continue;
}
if (existPayNoSet.contains(v.getPayNo())) {
walletPayInfoUpdateList.add(v);
} else {
walletPayInfoInsertList.add(v);
}
}
if (CollectionUtils.isNotEmpty(walletPayInfoInsertList)) {
walletPayInfoDAO.insertBatch(walletPayInfoInsertList);
}
if (CollectionUtils.isNotEmpty(walletPayInfoUpdateList)) {
walletPayInfoDAO.updateBatchByPayNo(walletPayInfoUpdateList);
}
// WalletTrade同样按 payNo 分批新增/更新
List<WalletTradeDO> walletTradeInsertList = new ArrayList<>();
List<WalletTradeDO> walletTradeUpdateList = new ArrayList<>();
for (WalletTradeDO v : walletTradeList) {
if (v == null || StringUtils.isBlank(v.getPayNo())) {
continue;
}
if (existPayNoSet.contains(v.getPayNo())) {
walletTradeUpdateList.add(v);
} else {
walletTradeInsertList.add(v);
}
}
if (CollectionUtils.isNotEmpty(walletTradeInsertList)) {
walletTradeDAO.insertBatch(walletTradeInsertList);
}
if (CollectionUtils.isNotEmpty(walletTradeUpdateList)) {
walletTradeDAO.updateBatchByPayNo(walletTradeUpdateList);
}
// 更新预分账明细
if (CollectionUtils.isNotEmpty(updatedRecords)) {
preAllocationRecordDAO.updateBatch(updatedRecords);
}
StoreOrderDO updateOrder = StoreOrderDO.builder()
.id(order.getId())
.status(orderStatus)
.updateTime(new Date())
.build();
if (batchTransferResult.getTradeStatus()==1) {
//支付成功 改订单下所有分账详情变为已分账
preAllocationRecordDAO.updateBatch(allocationRecords);
//todo 推送数据到新管家?
shopStageInfoDAO.batchUpdateShopStageStatus(order.getShopId(),Arrays.asList(ShopSubStageStatusEnum.SHOP_SUB_STAGE_STATUS_80,ShopSubStageStatusEnum.SHOP_SUB_STAGE_STATUS_285));
//支付成功 修改金额,支付中 回调的时候习惯
updateOrder.setPaidAmount(order.getTotalAmount());
updateOrder.setUnpaidAmount(BigDecimal.ZERO);
updateOrder.setPayTime(new Date());
}
storeOrderDAO.updateSelective(updateOrder);
}finally {
redisUtil.unlock(lockKey);
}
// log.info("订单开始支付 payOrder{},userInfo:{}", JSONObject.toJSONString(request),JSONObject.toJSONString(userInfo));
// //重复支付校验
// String lockKey = MessageFormat.format(RedisConstant.STANDARD_STORE_PAY_LOCK_KEY, request.getOrderId());
// Boolean lock = redisUtil.tryLock(lockKey, lockKey, 10, TimeUnit.SECONDS);
// if (!Boolean.TRUE.equals(lock)) {
// throw new ServiceException(ErrorCodeEnum.DUPLICATE_PAYMENTS);
// }
// try {
// // 1. 参数校验
// if (request == null || request.getOrderId() == null || request.getAmount() == null ||
// StringUtils.isBlank(request.getPayPwd())) {
// throw new ServiceException(ErrorCodeEnum.PARAMS_VALIDATE_ERROR);
// }
//
// // 2. 查询订单信息
// StoreOrderDO order = storeOrderDAO.getById(request.getOrderId());
// if (order == null) {
// throw new ServiceException(ErrorCodeEnum.STORE_ORDER_NOT_FOUND);
// }
//
// // 3. 校验订单状态:仅待支付状态可以支付
// if (!StoreOrderStatusEnum.WAIT_PAY.getCode().equals(order.getStatus())) {
// throw new ServiceException(ErrorCodeEnum.STORE_ORDER_STATUS_INVALID);
// }
//
// // 4. 校验支付金额与订单金额是否一致
// if (request.getAmount().compareTo(order.getTotalAmount()) != 0) {
// throw new ServiceException(ErrorCodeEnum.PAY_AMOUNT_ERROR);
// }
//
// // 5. 查询门店信息
// ShopInfoDO shopInfo = shopInfoDAO.getShopInfo(order.getShopId());
// if (shopInfo == null) {
// throw new ServiceException(ErrorCodeEnum.SHOP_NOT_EXIST);
// }
//
// // 6. 按门店查询预分账明细
// List<PreAllocationRecordDO> allocationRecords = preAllocationRecordService.listDOByShop(order.getShopId());
// if (CollectionUtils.isEmpty(allocationRecords)) {
// throw new ServiceException(ErrorCodeEnum.THERE_IS_NO_PAYMENT_INFORMATION);
// }
//
// // 7. 校验预分账明细金额总和是否等于订单金额
// BigDecimal allocationTotal = allocationRecords.stream()
// .filter(record -> record != null && record.getPayAmount() != null)
// .map(PreAllocationRecordDO::getPayAmount)
// .reduce(BigDecimal.ZERO, BigDecimal::add);
//
// if (allocationTotal.compareTo(order.getTotalAmount()) != 0) {
// throw new ServiceException(ErrorCodeEnum.FEE_NOT_CONSISTENT);
// }
//
// // 9. 封装批量分账请求
// BatchTransferRequest batchTransferRequest = new BatchTransferRequest();
// batchTransferRequest.setOutStoreId(shopInfo.getStoreId());
// batchTransferRequest.setPayPwd(request.getPayPwd());
// batchTransferRequest.setWalletType(2);
//
// List<BatchTransferRequest.TransDataRequest> transArray = new ArrayList<>();
// for (PreAllocationRecordDO record : allocationRecords) {
// BatchTransferRequest.TransDataRequest transData = new BatchTransferRequest.TransDataRequest();
//
// // payNo 必须唯一且失败重试要沿用第一次的 payNo
// String payNo = record.getPayNo();
// if (StringUtils.isBlank(payNo)) {
// payNo = GenerateNoUtil.generateMillsNoWithRandom();
// record.setPayNo(payNo);
// }
// transData.setReqNo(payNo);
//
// // 根据费用类型获取费用科目ID
// WalletFeeItemEnum feeItem = WalletFeeItemEnum.getByExpenseType(record.getExpenseType());
// if (feeItem == null) {
// throw new ServiceException(ErrorCodeEnum.NONSUPPORT_EXPENSE_TYPE);
// }
// transData.setFeeItemId(feeItem.getFeeItemId());
// transData.setCompanyCode(record.getPayeeCode());
// transData.setAmount(record.getPayAmount().toString());
//
// transArray.add(transData);
// }
// batchTransferRequest.setTransArray(transArray);
// Map<String, PreAllocationRecordDO> map = allocationRecords.stream().collect(Collectors.toMap(PreAllocationRecordDO::getPayNo, data -> data));
//
// // 调用第三方前先固化 payNo失败重试需要复用
// preAllocationRecordDAO.updateBatch(allocationRecords);
//
// // 10. 调用第三方分账接口
// BatchTransferDTO batchTransferResult;
// try {
// batchTransferResult = walletApiService.batchTransfer(batchTransferRequest);
// } catch (Exception e) {
// throw new ServiceException(ErrorCodeEnum.THIRD_API_ERROR.getCode(), "支付失败:" + e.getMessage());
// }
//
// // 11. 处理分账结果
// if (batchTransferResult == null || batchTransferResult.getTradeStatus() == null) {
// throw new ServiceException(ErrorCodeEnum.THIRD_API_ERROR.getCode(), "支付失败:分账接口返回异常");
// }
//
// // 12. 根据分账结果更新状态和记录
// List<WalletPayInfoDO> walletPayInfoList = new ArrayList<>();
// List<WalletTradeDO> walletTradeList = new ArrayList<>();
// List<PreAllocationRecordDO> updatedRecords = new ArrayList<>();
//
// //批量支付状态 1.成功 2.失败 3.处理中(目前是实时转账 无处理中)
// Integer tradeStatus = batchTransferResult.getTradeStatus();
//
// // 订单状态
// Integer orderStatus = null;
//
// // 按批次结果全成/全败
// Integer allocationStatus;
// Integer payStatus;
// if (tradeStatus != null && tradeStatus == 1) {
// allocationStatus = 1;
// payStatus = AllocationPayStatusEnum.PAID.getStatus();
// orderStatus = StoreOrderStatusEnum.PAID.getCode();
// } else {
// allocationStatus = 0;
// payStatus = AllocationPayStatusEnum.FAIL.getStatus();
// orderStatus = PAY_FAIL.getCode();
// }
//
// // 无论成功失败,都需要落库,并更新预分账状态
// if (batchTransferResult.getTransArray() != null) {
// for (int i = 0; i < batchTransferResult.getTransArray().size() && i < allocationRecords.size(); i++) {
// BatchTransferDTO.TransDataRequest result = batchTransferResult.getTransArray().get(i);
// PreAllocationRecordDO record = map.get(result.getReqNo());
// if (record == null) {
// continue;
// }
//
// record.setAllocationStatus(allocationStatus);
// updatedRecords.add(record);
//
// WalletPayInfoDO walletPayInfo = new WalletPayInfoDO();
// walletPayInfo.setShopId(order.getShopId());
// walletPayInfo.setModule(STANDARD_STORE.getModule());
// walletPayInfo.setPayNo(result.getReqNo());
// walletPayInfo.setPayUserName(userInfo.getUsername());
// walletPayInfo.setPayAmount(new BigDecimal(result.getAmount()));
// walletPayInfo.setPayStatus(payStatus);
// walletPayInfo.setPayTime(new Date());
// walletPayInfo.setClaimStatus(ClaimStatusEnum.TO_BE_CLAIMED.getCode());
// walletPayInfo.setExpenseTypes(record.getExpenseType());
// walletPayInfo.setCreateTime(new Date());
// walletPayInfo.setTradeId(result.getTradeId());
// walletPayInfoList.add(walletPayInfo);
//
// WalletTradeDO walletTrade = new WalletTradeDO();
// walletTrade.setModule(STANDARD_STORE.getModule());
// walletTrade.setPayNo(result.getReqNo());
// walletTrade.setTradeId(result.getTradeId());
// walletTrade.setType(1);
// walletTrade.setPayUserName(userInfo.getUsername());
// walletTrade.setPayAmount(new BigDecimal(result.getAmount()));
// walletTrade.setPayStatus(payStatus);
// walletTrade.setPayTime(new Date());
// walletTrade.setCreateTime(new Date());
// walletTradeList.add(walletTrade);
// }
// }
//
// // 13. 保存钱包支付信息/交易单payNo 唯一索引,存在则更新,不存在则插入(批量处理)
// List<String> payNoList = walletPayInfoList.stream()
// .map(WalletPayInfoDO::getPayNo)
// .filter(StringUtils::isNotBlank)
// .distinct()
// .collect(Collectors.toList());
//
// Set<String> existPayNoSet = new HashSet<>();
// if (CollectionUtils.isNotEmpty(payNoList)) {
// List<WalletPayInfoDO> existList = walletPayInfoDAO.getByPayNoList(payNoList);
// if (CollectionUtils.isNotEmpty(existList)) {
// existPayNoSet = existList.stream().map(WalletPayInfoDO::getPayNo).collect(Collectors.toSet());
// }
// }
//
// List<WalletPayInfoDO> walletPayInfoInsertList = new ArrayList<>();
// List<WalletPayInfoDO> walletPayInfoUpdateList = new ArrayList<>();
// for (WalletPayInfoDO v : walletPayInfoList) {
// if (v == null || StringUtils.isBlank(v.getPayNo())) {
// continue;
// }
// if (existPayNoSet.contains(v.getPayNo())) {
// walletPayInfoUpdateList.add(v);
// } else {
// walletPayInfoInsertList.add(v);
// }
// }
//
// if (CollectionUtils.isNotEmpty(walletPayInfoInsertList)) {
// walletPayInfoDAO.insertBatch(walletPayInfoInsertList);
// }
// if (CollectionUtils.isNotEmpty(walletPayInfoUpdateList)) {
// walletPayInfoDAO.updateBatchByPayNo(walletPayInfoUpdateList);
// }
//
// // WalletTrade同样按 payNo 分批新增/更新
// List<WalletTradeDO> walletTradeInsertList = new ArrayList<>();
// List<WalletTradeDO> walletTradeUpdateList = new ArrayList<>();
// for (WalletTradeDO v : walletTradeList) {
// if (v == null || StringUtils.isBlank(v.getPayNo())) {
// continue;
// }
// if (existPayNoSet.contains(v.getPayNo())) {
// walletTradeUpdateList.add(v);
// } else {
// walletTradeInsertList.add(v);
// }
// }
//
// if (CollectionUtils.isNotEmpty(walletTradeInsertList)) {
// walletTradeDAO.insertBatch(walletTradeInsertList);
// }
// if (CollectionUtils.isNotEmpty(walletTradeUpdateList)) {
// walletTradeDAO.updateBatchByPayNo(walletTradeUpdateList);
// }
//
// // 更新预分账明细
// if (CollectionUtils.isNotEmpty(updatedRecords)) {
// preAllocationRecordDAO.updateBatch(updatedRecords);
// }
//
// StoreOrderDO updateOrder = StoreOrderDO.builder()
// .id(order.getId())
// .status(orderStatus)
// .updateTime(new Date())
// .build();
//
// if (batchTransferResult.getTradeStatus()==1) {
// //支付成功 改订单下所有分账详情变为已分账
// preAllocationRecordDAO.updateBatch(allocationRecords);
// //todo 推送数据到新管家?
//
// shopStageInfoDAO.batchUpdateShopStageStatus(order.getShopId(),Arrays.asList(ShopSubStageStatusEnum.SHOP_SUB_STAGE_STATUS_80,ShopSubStageStatusEnum.SHOP_SUB_STAGE_STATUS_285));
//
// //支付成功 修改金额,支付中 回调的时候习惯
// updateOrder.setPaidAmount(order.getTotalAmount());
// updateOrder.setUnpaidAmount(BigDecimal.ZERO);
// updateOrder.setPayTime(new Date());
// }
//
// storeOrderDAO.updateSelective(updateOrder);
// }finally {
// redisUtil.unlock(lockKey);
// }
return true;
}
@@ -1173,9 +1196,190 @@ public class MiniStoreOrderServiceImpl implements MiniStoreOrderService {
return walletPayVOS;
}
@Override
public Boolean managerOrder(PCStoreOrderOptionQuantityUpdateRequest request, LoginUserInfo userInfo) {
log.info("managerOrder request:{},操作人:{}",JSONObject.toJSONString(request),userInfo.getName());
if (request == null || request.getOrderId() == null ) {
throw new ServiceException(ErrorCodeEnum.PARAMS_VALIDATE_ERROR);
}
// 1. 查询原订单
StoreOrderDO order = storeOrderDAO.getById(request.getOrderId());
if (order == null || !order.getShopId().equals(order.getShopId())) {
throw new ServiceException(ErrorCodeEnum.STORE_ORDER_NOT_FOUND);
}
// 2. 待立规审核 可管理订单
Integer status = order.getStatus();
if (!StoreOrderStatusEnum.WAIT_CONFIRM.getCode().equals(status)) {
throw new ServiceException(ErrorCodeEnum.STORE_ORDER_UPDATE_FORBIDDEN);
}
// 3. 查询新店型信息
StoreTypeDO storeType = storeTypeDAO.getById(order.getStoreTypeId());
if (storeType == null || Boolean.TRUE.equals(storeType.getDeleted()) ||
!Boolean.TRUE.equals(storeType.getActive())) {
throw new ServiceException(ErrorCodeEnum.CONFIG_NOT_EXIST);
}
// 4. 获取新店型的选项绑定关系
List<StoreTypeOptionDO> bindings = storeTypeOptionDAO.listByStoreTypeId(order.getStoreTypeId());
Map<Long, StoreTypeOptionDO> bindingMap = bindings.stream()
.collect(Collectors.toMap(StoreTypeOptionDO::getOptionId, Function.identity(), (a, b) -> a));
// 5. 处理选中的配置选项
BigDecimal optionAmount = BigDecimal.ZERO;
BigDecimal originalOptionAmount = BigDecimal.ZERO;
List<StoreOrderOptionSnapshotDO> snapshotList = new ArrayList<>();
if (CollectionUtils.isNotEmpty(request.getSelectedOptions())) {
Set<Long> optionIds = request.getSelectedOptions().stream()
.filter(Objects::nonNull)
.map(PCStoreOrderOptionQuantityUpdateRequest.SelectedOption::getOptionId)
.filter(Objects::nonNull)
.collect(Collectors.toSet());
// 查询选项模板
Map<Long, ConfigOptionDO> optionTemplateMap = new HashMap<>();
if (!optionIds.isEmpty()) {
List<ConfigOptionDO> optionTemplates = configOptionDAO.listActiveByIds(new ArrayList<>(optionIds));
optionTemplateMap = optionTemplates.stream()
.collect(Collectors.toMap(ConfigOptionDO::getId, Function.identity(), (a, b) -> a));
}
// 校验并计算金额
Set<String> selectedItemCodes = new HashSet<>();
for (PCStoreOrderOptionQuantityUpdateRequest.SelectedOption selected : request.getSelectedOptions()) {
if (selected == null || selected.getOptionId() == null) {
continue;
}
StoreTypeOptionDO binding = bindingMap.get(selected.getOptionId());
if (binding == null) {
throw new ServiceException(ErrorCodeEnum.THE_OPTION_IS_NOT_PART_OF_THIS_STORE_TYPE);
}
ConfigOptionDO template = optionTemplateMap.get(selected.getOptionId());
if (template == null || !Boolean.TRUE.equals(template.getActive())) {
throw new ServiceException(ErrorCodeEnum.CONFIG_NOT_EXIST);
}
// 处理数量
BigDecimal quantity = selected.getQuantity();
// 校验不可修改数量的选项
BigDecimal defaultQty = binding.getDefaultQuantity();
//使用店型上配置的价格 不能使用选项的配置上的价格
BigDecimal price = binding.getOptionPrice() == null ? BigDecimal.ZERO : binding.getOptionPrice();
BigDecimal originalPrice = template.getOriginalOptionPrice() == null ? BigDecimal.ZERO : template.getOriginalOptionPrice();
BigDecimal amount = BigDecimal.ZERO;
//小于默认数的时候
if(quantity.compareTo(defaultQty)<=0){
amount = price.multiply(quantity);
}else {
// 店型优惠价*默认数量 + 原价 *(选择数量-默认数量)
amount = price.multiply(defaultQty).add(originalPrice.multiply(quantity.subtract(defaultQty)));
}
BigDecimal originalAmount = originalPrice.multiply(quantity);
optionAmount = optionAmount.add(amount);
originalOptionAmount = originalOptionAmount.add(originalAmount);
// 创建快照
StoreOrderOptionSnapshotDO snapshot = StoreOrderOptionSnapshotDO.builder()
.orderId(order.getId())
.shopId(order.getShopId())
.storeTypeId(storeType.getId())
.optionId(selected.getOptionId())
.categoryCode(template.getCategoryCode())
.itemCode(template.getItemCode())
.optionCode(template.getOptionCode())
.optionName(template.getOptionName())
.optionPrice(price)
.originalOptionPrice(originalPrice)
.optionUnit(template.getOptionUnit())
.optionRemark(template.getOptionRemark())
.imageUrl(template.getImageUrl())
.videoUrl(template.getVideoUrl())
.quantity(quantity)
.expenseTypeCode(template.getExpenseTypeCode())
.amount(amount)
.originalAmount(originalAmount)
.build();
snapshotList.add(snapshot);
}
}
// 6. 计算固定费用和总金额
BigDecimal storeFixedAmount = safe(storeType.getFranchiseFee())
.add(safe(storeType.getBrandUsageFee()))
.add(safe(storeType.getManagementFee()))
.add(safe(storeType.getSystemUsageFee()))
.add(safe(storeType.getDesignFee()))
.add(safe(storeType.getFirstOrderFee()))
.add(safe(storeType.getContractDeposit()));
BigDecimal originalStoreFixedAmount = safe(storeType.getOriginalFranchiseFee())
.add(safe(storeType.getOriginalBrandUsageFee()))
.add(safe(storeType.getOriginalManagementFee()))
.add(safe(storeType.getOriginalSystemUsageFee()))
.add(safe(storeType.getOriginalDesignFee()))
.add(safe(storeType.getOriginalContractDeposit()));
BigDecimal totalAmount = storeFixedAmount.add(optionAmount);
BigDecimal originalTotalAmount = originalStoreFixedAmount.add(originalOptionAmount);
// 7. 更新订单信息
StoreOrderDO updateOrder = StoreOrderDO.builder()
.id(order.getId())
.storeTypeId(storeType.getId())
.storeTypeCode(storeType.getStoreTypeCode())
.storeTypeName(storeType.getStoreTypeName())
.storeType(storeType.getStoreType())
.brand(storeType.getBrand())
.franchiseFee(safe(storeType.getFranchiseFee()))
.originalFranchiseFee(safe(storeType.getOriginalFranchiseFee()))
.brandUsageFee(safe(storeType.getBrandUsageFee()))
.originalBrandUsageFee(safe(storeType.getOriginalBrandUsageFee()))
.managementFee(safe(storeType.getManagementFee()))
.originalManagementFee(safe(storeType.getOriginalManagementFee()))
.systemUsageFee(safe(storeType.getSystemUsageFee()))
.originalSystemUsageFee(safe(storeType.getOriginalSystemUsageFee()))
.contractDeposit(safe(storeType.getContractDeposit()))
.originalContractDeposit(safe(storeType.getOriginalContractDeposit()))
.designFee(safe(storeType.getDesignFee()))
.originalDesignFee(safe(storeType.getOriginalDesignFee()))
.firstOrderFee(safe(storeType.getFirstOrderFee()))
.storeFixedAmount(storeFixedAmount)
.originalStoreFixedAmount(originalStoreFixedAmount)
.optionAmount(optionAmount)
.originalOptionAmount(originalOptionAmount)
.totalAmount(totalAmount)
.originalTotalAmount(originalTotalAmount)
.unpaidAmount(totalAmount.subtract(order.getPaidAmount()))
.status(WAIT_CONFIRM.getCode())
.updateTime(new Date())
.build();
// 8. 删除旧快照并保存新快照
snapshotDAO.deleteByOrderId(order.getId());
if (!snapshotList.isEmpty()) {
snapshotDAO.insertBatch(snapshotList);
}
// 9. 更新订单
storeOrderDAO.updateSelective(updateOrder);
return Boolean.TRUE;
}
@Override
@Transactional
public Boolean batchUpdateOptionQuantity(PCStoreOrderOptionQuantityUpdateRequest request) {
public Boolean batchUpdateOptionQuantity(PCStoreOrderOptionQuantityUpdateRequest request,LoginUserInfo userInfo) {
log.info("batchUpdateOptionQuantity request:{},操作人:{}",JSONObject.toJSONString(request),userInfo.getName());
if (request == null || request.getOrderId() == null || CollectionUtils.isEmpty(request.getSelectedOptions())) {
throw new ServiceException(ErrorCodeEnum.PARAMS_VALIDATE_ERROR);
}
@@ -1407,11 +1611,11 @@ public class MiniStoreOrderServiceImpl implements MiniStoreOrderService {
}
@Override
public List<MiniStoreWishlistListVO> wishlistList( PartnerUserInfoVO userInfoVO) {
if (userInfoVO == null || userInfoVO.getLineId() == null) {
public List<MiniStoreWishlistListVO> wishlistList( Long lineId,Integer wishlistStatus) {
if (lineId == null) {
return Collections.emptyList();
}
List<MiniStoreWishlistListVO> wishlistList = storeWishlistDAO.listByLineId(userInfoVO.getLineId(), null);
List<MiniStoreWishlistListVO> wishlistList = storeWishlistDAO.listByLineId(lineId, null,wishlistStatus);
if (CollectionUtils.isEmpty(wishlistList)) {
return Collections.emptyList();
}
@@ -1588,6 +1792,69 @@ public class MiniStoreOrderServiceImpl implements MiniStoreOrderService {
return convert(storelistDO);
}
@Override
@Transactional
public Boolean changeWishlist(ChangeWishlistRequest request) {
if (request.getWishlistId()==null||request.getOrderId()==null||request.getShopId()==null){
throw new ServiceException(ErrorCodeEnum.ERROR_MESSAGE);
}
//校验订单状态
StoreOrderDO storeOrderDO = storeOrderDAO.getById(request.getOrderId());
if (storeOrderDO==null){
throw new ServiceException(ErrorCodeEnum.STORE_ORDER_NOT_FOUND);
}
if (!WAIT_CONFIRM.getCode().equals(storeOrderDO.getStatus())){
throw new ServiceException(ErrorCodeEnum.CURRENT_ORDER_STATUS_NOT_SUPPORT_CHANGE);
}
MiniStoreWishlistDetailVO miniStoreWishlistDetailVO = wishlistDetail(request.getWishlistId());
if (miniStoreWishlistDetailVO==null){
throw new ServiceException(ErrorCodeEnum.CURRENT_WISHLIST_NOT_EXIST);
}
//校验心愿单状态
StoreWishlistDO wishlistDO = storeWishlistDAO.getById(request.getWishlistId());
//校验心愿单是否绑定其他铺位
if (!WishlistStatusEnum.COMPLETE_POINT.getCode().equals(wishlistDO.getWishlistStatus())){
throw new ServiceException(ErrorCodeEnum.CURRENT_WISHLIST_BIND_OTHER_POINT);
}
//查询老的心愿单
ShopInfoDO shopInfo = shopInfoDAO.getShopInfo(request.getShopId());
if (shopInfo.getPointId()==null){
throw new ServiceException(ErrorCodeEnum.ORDER_DATA_EXCEPTION);
}
//老的心愿单
StoreWishlistDO oldWishlist = storeWishlistDAO.getByPointId(shopInfo.getLineId(), shopInfo.getPointId());
//老的心愿单解绑关系
storeWishlistDAO.unbindPoint(oldWishlist.getId());
//新的心愿单关联关系
wishlistDO.setPointId(shopInfo.getPointId());
wishlistDO.setWishlistStatus(WishlistStatusEnum.PASS.getCode());
storeWishlistDAO.updateByExampleSelective(wishlistDO);
//删除老的订单
storeOrderDAO.deleteById(storeOrderDO);
//删除快照
storeOrderOptionSnapshotDAO.deleteByOrderId(storeOrderDO.getId());
MiniStoreOrderCreateRequest miniStoreOrderCreateRequest = new MiniStoreOrderCreateRequest();
miniStoreOrderCreateRequest.setStoreTypeId(miniStoreWishlistDetailVO.getStoreTypeId());
miniStoreOrderCreateRequest.setShopId(request.getShopId());
List<MiniStoreOrderCreateRequest.SelectedOption> selectedOptions = new ArrayList<>();
miniStoreWishlistDetailVO.getOptions().forEach(x->{
MiniStoreOrderCreateRequest.SelectedOption selectedOption = new MiniStoreOrderCreateRequest.SelectedOption();
selectedOption.setOptionId(x.getOptionId());
selectedOption.setQuantity(x.getQuantity());
selectedOptions.add(selectedOption);
});
miniStoreOrderCreateRequest.setSelectedOptions(selectedOptions);
//创建订单
createOrder(miniStoreOrderCreateRequest,null);
return Boolean.TRUE;
}
private MiniStoreWishlistDetailVO convert(StoreWishlistDO storeWishlistDO){
if (storeWishlistDO==null){

View File

@@ -1,6 +1,7 @@
package com.cool.store.service.store;
import com.cool.store.entity.order.PreAllocationRecordDO;
import com.cool.store.entity.order.StoreOrderDO;
import com.cool.store.request.store.PreAllocationQueryShopRequest;
import com.cool.store.request.store.PreAllocationSaveRequest;
import com.cool.store.vo.order.PreAllocationRecordVO;
@@ -17,8 +18,12 @@ public interface PreAllocationRecordService {
Boolean saveBatch(PreAllocationSaveRequest req);
void queryAndUpdateBatchTransferStatus(String batchCode);
List<PreAllocationRecordVO> queryByShop(Long shopId);
List<PreAllocationRecordDO> listDOByShop(Long shopId);
Integer pushStandardStoreFee(StoreOrderDO storeOrderDO);
}

View File

@@ -1,40 +1,87 @@
package com.cool.store.service.store.impl;
import cn.hutool.core.collection.CollStreamUtil;
import com.alibaba.fastjson.JSONObject;
import com.cool.store.dao.FranchiseFeeDAO;
import com.cool.store.dao.LineInfoDAO;
import com.cool.store.dao.ShopInfoDAO;
import com.cool.store.dao.ShopStageInfoDAO;
import com.cool.store.dao.fees.WalletAllocationConfigDAO;
import com.cool.store.dao.fees.WalletPayInfoDAO;
import com.cool.store.dao.order.PreAllocationRecordDAO;
import com.cool.store.dao.order.StoreOrderDAO;
import com.cool.store.dao.order.StoreOrderOptionSnapshotDAO;
import com.cool.store.dao.wallet.WalletTradeDAO;
import com.cool.store.dto.fees.ExpenseTypeAmountDTO;
import com.cool.store.dto.fees.WalletAllocationDTO;
import com.cool.store.dto.wallet.AccountInfoDTO;
import com.cool.store.dto.wallet.BatchTransferDTO;
import com.cool.store.entity.FranchiseFeeDO;
import com.cool.store.entity.LineInfoDO;
import com.cool.store.entity.ShopInfoDO;
import com.cool.store.entity.ShopStageInfoDO;
import com.cool.store.entity.fees.ShopAllocationInfoDO;
import com.cool.store.entity.fees.WalletAllocationConfigDO;
import com.cool.store.entity.fees.WalletPayInfoDO;
import com.cool.store.entity.order.PreAllocationRecordDO;
import com.cool.store.entity.order.StoreOrderDO;
import com.cool.store.entity.wallet.WalletTradeDO;
import com.cool.store.enums.ClaimStatusEnum;
import com.cool.store.enums.ErrorCodeEnum;
import com.cool.store.enums.FranchiseBrandEnum;
import com.cool.store.enums.XGJCollectionStatusEnum;
import com.cool.store.enums.fees.AllocationPayStatusEnum;
import com.cool.store.enums.fees.PayTypeEnum;
import com.cool.store.enums.fees.WalletFeeItemEnum;
import com.cool.store.enums.order.StoreOrderStatusEnum;
import com.cool.store.enums.point.ShopSubStageEnum;
import com.cool.store.enums.point.ShopSubStageStatusEnum;
import com.cool.store.exception.ServiceException;
import com.cool.store.mapper.FranchiseFeeMapper;
import com.cool.store.request.store.PreAllocationSaveRequest;
import com.cool.store.request.wallet.BatchTransferQueryRequest;
import com.cool.store.request.wallet.BatchTransferRequest;
import com.cool.store.request.wallet.OutStoreIdRequest;
import com.cool.store.request.xgj.PushFranchiseFeeRequest;
import com.cool.store.request.xgj.ReceiptRequest;
import com.cool.store.service.PushService;
import com.cool.store.service.dict.impl.DictService;
import com.cool.store.service.fees.WalletPayInfoService;
import com.cool.store.service.order.MiniStoreOrderService;
import com.cool.store.service.store.PreAllocationRecordService;
import com.cool.store.service.wallet.WalletApiService;
import com.cool.store.utils.BeanUtil;
import com.cool.store.utils.GenerateNoUtil;
import com.cool.store.utils.RedisUtil;
import com.cool.store.utils.StringUtil;
import com.cool.store.vo.order.MiniStoreOrderDetailVO;
import com.cool.store.vo.order.PreAllocationRecordVO;
import groovy.util.logging.Slf4j;
import lombok.RequiredArgsConstructor;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import static com.cool.store.enums.order.StoreOrderStatusEnum.PAY_FAIL;
import static com.cool.store.enums.wallet.WalletTradeModuleEnum.STANDARD_STORE;
/**
* @Auther zx_szh
* @Date 2026/2/4 15:56
* @Version 1.0
*/
@lombok.extern.slf4j.Slf4j
@Service
@RequiredArgsConstructor
@Slf4j
public class PreAllocationRecordServiceImpl implements PreAllocationRecordService {
private final PreAllocationRecordDAO dao;
@@ -43,6 +90,19 @@ public class PreAllocationRecordServiceImpl implements PreAllocationRecordServic
private final StoreOrderDAO storeOrderDAO;
private final ShopStageInfoDAO shopStageInfoDAO;
private final WalletPayInfoDAO walletPayInfoDAO;
private final WalletAllocationConfigDAO walletAllocationConfigDAO;
private final StoreOrderOptionSnapshotDAO storeOrderOptionSnapshotDAO;
private final ShopInfoDAO shopInfoDAO;
private final WalletApiService walletApiService;
private final LineInfoDAO lineInfoDAO;
private final WalletTradeDAO walletTradeDAO;
private final PreAllocationRecordDAO preAllocationRecordDAO;
private final WalletPayInfoService walletPayInfoService;
private final PushService pushService;
private final FranchiseFeeDAO franchiseFeeDAO;
private final FranchiseFeeMapper franchiseFeeMapper;
@Transactional
@Override
public Boolean saveBatch(PreAllocationSaveRequest req){
@@ -60,31 +120,98 @@ public class PreAllocationRecordServiceImpl implements PreAllocationRecordServic
}
BigDecimal totalAmount = storeOrder.getTotalAmount() == null ? BigDecimal.ZERO : storeOrder.getTotalAmount();
BigDecimal sumPayAmount = req.getItems() == null ? BigDecimal.ZERO : req.getItems().stream()
.filter(i -> i != null)
.map(i -> i.getPayAmount() == null ? BigDecimal.ZERO : i.getPayAmount())
List<PreAllocationRecordDO> existList = dao.queryPageByShopId(req.getShopId());
Map<Long, PreAllocationRecordDO> existMap = existList.stream()
.filter(v -> v.getId() != null)
.collect(Collectors.toMap(PreAllocationRecordDO::getId, Function.identity(), (a, b) -> a));
List<PreAllocationSaveRequest.PreAllocationItem> reqItems = req.getItems() == null ? Collections.emptyList() : req.getItems().stream().filter(item->BigDecimal.ZERO.compareTo(item.getPayAmount())<0).collect(Collectors.toList());
Set<Long> reqIdSet = reqItems.stream()
.filter(Objects::nonNull)
.map(PreAllocationSaveRequest.PreAllocationItem::getId)
.filter(Objects::nonNull)
.collect(Collectors.toSet());
List<PreAllocationRecordDO> insertList = new ArrayList<>();
List<PreAllocationRecordDO> updateList = new ArrayList<>();
BigDecimal reqTouchedAmount = BigDecimal.ZERO;
for (PreAllocationSaveRequest.PreAllocationItem item : reqItems) {
if (item == null) {
continue;
}
if (BigDecimal.ZERO.compareTo(item.getPayAmount())>=0){
throw new ServiceException(ErrorCodeEnum.ERROR_MESSAGE);
}
Long id = item.getId();
if (id == null) {
insertList.add(PreAllocationRecordDO.builder()
.orderId(req.getOrderId())
.shopId(req.getShopId())
.expenseType(item.getExpenseType())
.payeeName(item.getPayeeName())
.payeeCode(item.getPayeeCode())
.payAmount(item.getPayAmount())
.allocationStatus(AllocationPayStatusEnum.UNPAID.getStatus())
.build());
reqTouchedAmount = reqTouchedAmount.add(item.getPayAmount() == null ? BigDecimal.ZERO : item.getPayAmount());
continue;
}
PreAllocationRecordDO exist = existMap.get(id);
if (exist == null) {
throw new ServiceException(ErrorCodeEnum.PARAMS_VALIDATE_ERROR);
}
if (!Objects.equals(exist.getShopId(), req.getShopId()) || !Objects.equals(exist.getOrderId(), req.getOrderId())) {
throw new ServiceException(ErrorCodeEnum.PARAMS_VALIDATE_ERROR);
}
//已支付
if (Objects.equals(exist.getAllocationStatus(), 1)) {
reqTouchedAmount = reqTouchedAmount.add(exist.getPayAmount() == null ? BigDecimal.ZERO : exist.getPayAmount());
continue;
}
exist.setExpenseType(item.getExpenseType());
exist.setPayeeName(item.getPayeeName());
exist.setPayeeCode(item.getPayeeCode());
exist.setPayAmount(item.getPayAmount());
updateList.add(exist);
reqTouchedAmount = reqTouchedAmount.add(item.getPayAmount() == null ? BigDecimal.ZERO : item.getPayAmount());
}
List<PreAllocationRecordDO> removedList = existList.stream()
.filter(v -> v != null && v.getId() != null && !reqIdSet.contains(v.getId()))
.collect(Collectors.toList());
BigDecimal paidRemovedAmount = removedList.stream()
.filter(v -> Objects.equals(v.getAllocationStatus(), AllocationPayStatusEnum.PAID.getStatus()))
.map(v -> v.getPayAmount() == null ? BigDecimal.ZERO : v.getPayAmount())
.reduce(BigDecimal.ZERO, BigDecimal::add);
//订单金额与分账金额对不上 抛出异常
if (sumPayAmount.compareTo(totalAmount) != 0) {
BigDecimal finalAmount = reqTouchedAmount.add(paidRemovedAmount);
if (finalAmount.compareTo(totalAmount) != 0) {
throw new ServiceException(ErrorCodeEnum.FEE_NOT_CONSISTENT);
}
dao.deleteByShopId(req.getShopId());
List<PreAllocationRecordDO> list = req.getItems().stream().map(i ->
PreAllocationRecordDO.builder()
.orderId(req.getOrderId())
.shopId(req.getShopId())
.expenseType(i.getExpenseType())
.payeeName(i.getPayeeName())
.payeeCode(i.getPayeeCode())
.payAmount(i.getPayAmount())
.allocationStatus(0)
.build()
).collect(Collectors.toList());
dao.insertBatch(list);
shopStageInfoDAO.updateShopStageInfo(req.getShopId(), ShopSubStageStatusEnum.SHOP_SUB_STAGE_STATUS_284);
storeOrder.setStatus(StoreOrderStatusEnum.WAIT_PAY.getCode());
storeOrderDAO.updateSelective(storeOrder);
if (CollectionUtils.isNotEmpty(updateList)) {
dao.batchUpdateEditableFields(updateList);
}
if (CollectionUtils.isNotEmpty(insertList)) {
dao.insertBatch(insertList);
}
List<Long> removeIds = removedList.stream()
.filter(v -> !Objects.equals(v.getAllocationStatus(), AllocationPayStatusEnum.PAID.getStatus()))
.map(PreAllocationRecordDO::getId)
.filter(Objects::nonNull)
.collect(Collectors.toList());
if (CollectionUtils.isNotEmpty(removeIds)) {
dao.deleteByIdsNotPaid(removeIds);
}
//分账
batchTrans(req,storeOrder);
return Boolean.TRUE;
}finally{
redisUtil.unlock(lockKey);
@@ -92,11 +219,382 @@ public class PreAllocationRecordServiceImpl implements PreAllocationRecordServic
}
@Transactional
public void batchTrans(PreAllocationSaveRequest req,StoreOrderDO storeOrder){
log.info("batchTrans:{}", JSONObject.toJSONString(req));
LineInfoDO lineInfo = lineInfoDAO.getLineInfo(storeOrder.getLineId());
//分账
List<String> walletFeeItemBySubStage = WalletFeeItemEnum.getWalletFeeItemBySubStage(req.getSubStage());
List<PreAllocationRecordDO> newAllocationList = dao.queryPageByShopId(req.getShopId());
//待分账数据
List<PreAllocationRecordDO> list = newAllocationList.stream().
filter(x -> x.getExpenseType() != null && walletFeeItemBySubStage.contains(x.getExpenseType()) && x.getAllocationStatus() == AllocationPayStatusEnum.UNPAID.getStatus()
).collect(Collectors.toList());
if (CollectionUtils.isNotEmpty(list)){
ShopInfoDO shopInfo = shopInfoDAO.getShopInfo(storeOrder.getShopId());
BatchTransferRequest batchTransferRequest = new BatchTransferRequest();
batchTransferRequest.setOutStoreId(shopInfo.getStoreId());
batchTransferRequest.setVerifyPassword(1);
batchTransferRequest.setWalletType(2);
List<BatchTransferRequest.TransDataRequest> transArray = new ArrayList<>();
//
BigDecimal currentAmount = new BigDecimal("0");
for (PreAllocationRecordDO record : list) {
BatchTransferRequest.TransDataRequest transData = new BatchTransferRequest.TransDataRequest();
// payNo 必须唯一且失败重试要沿用第一次的 payNo
String payNo = record.getPayNo();
if (StringUtils.isBlank(payNo)) {
payNo = GenerateNoUtil.generateMillsNoWithRandom();
record.setPayNo(payNo);
}
transData.setReqNo(payNo);
// 根据费用类型获取费用科目ID
WalletFeeItemEnum feeItem = WalletFeeItemEnum.getByExpenseType(record.getExpenseType());
if (feeItem == null) {
throw new ServiceException(ErrorCodeEnum.NONSUPPORT_EXPENSE_TYPE);
}
transData.setFeeItemId(feeItem.getFeeItemId());
transData.setCompanyCode(record.getPayeeCode());
transData.setAmount(record.getPayAmount().toString());
currentAmount = currentAmount.add(record.getPayAmount());
transArray.add(transData);
}
if (StringUtil.isNotEmpty(shopInfo.getStoreId())){
List<AccountInfoDTO> accountInfo = walletApiService.getAccountInfo(new OutStoreIdRequest(shopInfo.getStoreId()));
if (CollectionUtils.isNotEmpty(accountInfo)){
AccountInfoDTO accountInfoDTO = accountInfo.get(0);
String totalAmount = accountInfoDTO.getTotalAmount();
BigDecimal total = new BigDecimal(totalAmount);
//校验本次缴纳金额
if (total.compareTo(currentAmount)<0) {
throw new ServiceException(ErrorCodeEnum.NOT_ENOUGH_BALANCE);
}
//首次缴款 校验总金额
if (req.getSubStage()==ShopSubStageEnum.SHOP_STAGE_28.getShopSubStage()){
if (total.compareTo(storeOrder.getTotalAmount())<0) {
throw new ServiceException(ErrorCodeEnum.NOT_ENOUGH_BALANCE);
}
}
}
}
batchTransferRequest.setTransArray(transArray);
Map<String, PreAllocationRecordDO> map = list.stream().collect(Collectors.toMap(PreAllocationRecordDO::getPayNo, data -> data));
//// 调用第三方前先固化 payNo失败重试需要复用
preAllocationRecordDAO.updateBatch(list);
BatchTransferDTO batchTransferResult;
try {
batchTransferResult = walletApiService.batchTransfer(batchTransferRequest);
} catch (Exception e) {
throw new ServiceException(ErrorCodeEnum.THIRD_API_ERROR.getCode(), "支付失败:" + e.getMessage());
}
// 11. 处理分账结果
if (batchTransferResult == null || batchTransferResult.getTradeStatus() == null) {
throw new ServiceException(ErrorCodeEnum.THIRD_API_ERROR.getCode(), "支付失败:分账接口返回异常");
}
List<WalletPayInfoDO> walletPayInfoList = new ArrayList<>();
List<WalletTradeDO> walletTradeList = new ArrayList<>();
List<PreAllocationRecordDO> updatedRecords = new ArrayList<>();
//批量支付状态 1.成功 2.失败 3.处理中(网商银行有处理中)
Integer tradeStatus = batchTransferResult.getTradeStatus();
// 订单状态
Integer orderStatus = null;
// 按批次结果全成/全败
Integer allocationStatus = tradeStatus;
if (tradeStatus != null && tradeStatus == 1) {
orderStatus = StoreOrderStatusEnum.PART_OF_WAIT_PAY.getCode();
}
// 无论成功失败,都需要落库,并更新预分账状态
if (batchTransferResult.getTransArray() != null) {
for (int i = 0; i < batchTransferResult.getTransArray().size() && i < list.size(); i++) {
BatchTransferDTO.TransDataRequest result = batchTransferResult.getTransArray().get(i);
PreAllocationRecordDO record = map.get(result.getReqNo());
if (record == null) {
continue;
}
record.setAllocationStatus(allocationStatus);
updatedRecords.add(record);
WalletPayInfoDO walletPayInfo = new WalletPayInfoDO();
walletPayInfo.setShopId(storeOrder.getShopId());
walletPayInfo.setModule(STANDARD_STORE.getModule());
walletPayInfo.setPayNo(result.getReqNo());
walletPayInfo.setPayUserName(lineInfo.getUsername());
walletPayInfo.setPayAmount(new BigDecimal(result.getAmount()));
walletPayInfo.setPayStatus(tradeStatus);
walletPayInfo.setPayTime(new Date());
walletPayInfo.setClaimStatus(ClaimStatusEnum.TO_BE_CLAIMED.getCode());
walletPayInfo.setExpenseTypes(record.getExpenseType());
walletPayInfo.setCreateTime(new Date());
walletPayInfo.setTradeId(result.getTradeId());
walletPayInfo.setBatchCode(batchTransferResult.getBatchCode());
walletPayInfoList.add(walletPayInfo);
WalletTradeDO walletTrade = new WalletTradeDO();
walletTrade.setModule(STANDARD_STORE.getModule());
walletTrade.setPayNo(result.getReqNo());
walletTrade.setTradeId(result.getTradeId());
walletTrade.setType(1);
walletTrade.setPayUserName(lineInfo.getUsername());
walletTrade.setPayAmount(new BigDecimal(result.getAmount()));
walletTrade.setPayStatus(tradeStatus);
walletTrade.setPayTime(new Date());
walletTrade.setBatchCode(batchTransferResult.getBatchCode());
walletTrade.setCreateTime(new Date());
walletTradeList.add(walletTrade);
}
}
// 13. 保存钱包支付信息/交易单payNo 唯一索引,存在则更新,不存在则插入(批量处理)
List<String> payNoList = walletPayInfoList.stream()
.map(WalletPayInfoDO::getPayNo)
.filter(StringUtils::isNotBlank)
.distinct()
.collect(Collectors.toList());
Set<String> existPayNoSet = new HashSet<>();
if (CollectionUtils.isNotEmpty(payNoList)) {
List<WalletPayInfoDO> existList = walletPayInfoDAO.getByPayNoList(payNoList);
if (CollectionUtils.isNotEmpty(existList)) {
existPayNoSet = existList.stream().map(WalletPayInfoDO::getPayNo).collect(Collectors.toSet());
}
}
List<WalletPayInfoDO> walletPayInfoInsertList = new ArrayList<>();
List<WalletPayInfoDO> walletPayInfoUpdateList = new ArrayList<>();
for (WalletPayInfoDO v : walletPayInfoList) {
if (v == null || StringUtils.isBlank(v.getPayNo())) {
continue;
}
if (existPayNoSet.contains(v.getPayNo())) {
walletPayInfoUpdateList.add(v);
} else {
walletPayInfoInsertList.add(v);
}
}
if (CollectionUtils.isNotEmpty(walletPayInfoInsertList)) {
walletPayInfoDAO.insertBatch(walletPayInfoInsertList);
}
if (CollectionUtils.isNotEmpty(walletPayInfoUpdateList)) {
walletPayInfoDAO.updateBatchByPayNo(walletPayInfoUpdateList);
}
// WalletTrade同样按 payNo 分批新增/更新
List<WalletTradeDO> walletTradeInsertList = new ArrayList<>();
List<WalletTradeDO> walletTradeUpdateList = new ArrayList<>();
for (WalletTradeDO v : walletTradeList) {
if (v == null || StringUtils.isBlank(v.getPayNo())) {
continue;
}
if (existPayNoSet.contains(v.getPayNo())) {
walletTradeUpdateList.add(v);
} else {
walletTradeInsertList.add(v);
}
}
if (CollectionUtils.isNotEmpty(walletTradeInsertList)) {
walletTradeDAO.insertBatch(walletTradeInsertList);
}
if (CollectionUtils.isNotEmpty(walletTradeUpdateList)) {
walletTradeDAO.updateBatchByPayNo(walletTradeUpdateList);
}
// 更新预分账明细
if (CollectionUtils.isNotEmpty(updatedRecords)) {
preAllocationRecordDAO.updateBatch(updatedRecords);
}
StoreOrderDO updateOrder = StoreOrderDO.builder()
.id(storeOrder.getId())
.status(orderStatus)
.updateTime(new Date())
.build();
if (batchTransferResult.getTradeStatus()==1) {
List<WalletPayInfoDO> walletPayInfoDOS = new ArrayList<>();
if (CollectionUtils.isNotEmpty(walletPayInfoInsertList)){
walletPayInfoDOS.addAll(walletPayInfoInsertList);
}
if (CollectionUtils.isNotEmpty(walletPayInfoUpdateList)){
walletPayInfoDOS.addAll(walletPayInfoUpdateList);
}
this.pushReceiptRequest(walletPayInfoUpdateList,shopInfo,storeOrder);
//对账中
shopStageInfoDAO.batchUpdateShopStageStatus(storeOrder.getShopId(),Arrays.asList(ShopSubStageStatusEnum.SHOP_SUB_STAGE_STATUS_284_5));
//当前缴纳金额 = 本次缴纳前已缴纳金额+本次缴纳金额
BigDecimal paidAmount = storeOrder.getPaidAmount().add(currentAmount);
BigDecimal unpaidAmount = storeOrder.getTotalAmount().subtract(paidAmount);
//支付成功 修改金额,支付中 回调的时候习惯
updateOrder.setPaidAmount(paidAmount);
updateOrder.setUnpaidAmount(unpaidAmount);
updateOrder.setPayTime(new Date());
if (unpaidAmount.compareTo(new BigDecimal(0))==0){
//剩余缴纳金额是0 缴费完成
updateOrder.setStatus( StoreOrderStatusEnum.PAID.getCode());
}
}
storeOrderDAO.updateSelective(updateOrder);
}
}
private void pushReceiptRequest(List<WalletPayInfoDO> payInfoList, ShopInfoDO shopInfoDO,StoreOrderDO storeOrder) {
if (CollectionUtils.isEmpty(payInfoList)) {
return;
}
FranchiseFeeDO franchiseFeeDO = franchiseFeeDAO.selectByShopId(shopInfoDO.getId());
Integer feeId = null;
if (Objects.isNull(franchiseFeeDO)){
feeId = this.pushStandardStoreFee(storeOrder);
}else {
feeId = franchiseFeeDO.getId().intValue();
}
for (WalletPayInfoDO payInfo : payInfoList) {
ReceiptRequest receiptRequest = new ReceiptRequest(shopInfoDO.getId(), feeId, payInfo, Integer.valueOf(shopInfoDO.getFranchiseBrand()));
try {
pushService.pushReceiptToXGJ(receiptRequest);
} catch (Exception e) {
log.error("钱包账单推送新管家失败, walletPayInfoId:{}", payInfo.getId(), e);
}
}
}
@Override
@Transactional
public void queryAndUpdateBatchTransferStatus(String batchCode) {
BatchTransferDTO batchTransferDTO = walletApiService.queryBatchTransfer(new BatchTransferQueryRequest(batchCode));
// 根据批次号更新交易单
walletTradeDAO.updatePayStatusByBatchCode(batchCode, batchTransferDTO.getTradeStatus());
// 根据批次号更新业务单
List<WalletPayInfoDO> payInfoList = walletPayInfoDAO.getByBatchCode(batchCode);
if (CollectionUtils.isEmpty(payInfoList)) {
log.error("查询并更新批量转账状态异常,业务单为空");
return;
}
walletPayInfoDAO.updatePayStatusByBatchCode(batchCode, batchTransferDTO.getTradeStatus());
// 更新分账信息
Long shopId = payInfoList.get(0).getShopId();
List<String> payNoList = batchTransferDTO.getTransArray().stream().map(BatchTransferDTO.TransDataRequest::getReqNo).collect(Collectors.toList());
//分账状态调整
preAllocationRecordDAO.updateByPayNoList(payNoList,batchTransferDTO.getTradeStatus());
// 校验并流转流程
if (AllocationPayStatusEnum.PAID.getStatus().equals(batchTransferDTO.getTradeStatus())) {
ShopInfoDO shopInfo = shopInfoDAO.getShopInfo(shopId);
// 校验并流转流程
shopStageInfoDAO.updateShopStageInfo(shopId, ShopSubStageStatusEnum.SHOP_SUB_STAGE_STATUS_284_5);
//订单状态更新
StoreOrderDO storeOrder = storeOrderDAO.getLatestOrderByShopId(shopId);
//部分支付
StoreOrderDO updateOrder = StoreOrderDO.builder()
.id(storeOrder.getId())
.status(StoreOrderStatusEnum.PART_OF_WAIT_PAY.getCode())
.updateTime(new Date())
.build();
//当前缴纳金额 = 本次缴纳前已缴纳金额+本次缴纳金额
BigDecimal currentAmount = sumAmount(payInfoList);
BigDecimal paidAmount = storeOrder.getPaidAmount().add(currentAmount);
BigDecimal unpaidAmount = storeOrder.getTotalAmount().subtract(paidAmount);
//支付成功 修改金额,支付中 回调的时候习惯
updateOrder.setPaidAmount(paidAmount);
updateOrder.setUnpaidAmount(unpaidAmount);
updateOrder.setPayTime(new Date());
if (unpaidAmount.compareTo(new BigDecimal(0))==0){
//剩余缴纳金额是0 缴费完成
updateOrder.setStatus( StoreOrderStatusEnum.PAID.getCode());
}
storeOrderDAO.updateSelective(updateOrder);
// 推送缴费单数据到新管家
if (CollectionUtils.isNotEmpty(payInfoList)) {
pushReceiptRequest(payInfoList, shopInfo,storeOrder);
}
}
}
@Override
public List<PreAllocationRecordVO> queryByShop(Long shopId){
List<PreAllocationRecordDO> list = dao.queryPageByShopId(shopId);
if (CollectionUtils.isEmpty(list)){
return new ArrayList<>();
if (CollectionUtils.isEmpty(list)) {
StoreOrderDO storeOrder = storeOrderDAO.getLatestOrderByShopId(shopId);
if (storeOrder == null) {
return new ArrayList<>();
}
// 获取基础费用类型配置
List<String> baseExpenseTypeList = WalletFeeItemEnum.getBaseExpenseType().stream()
.map(WalletFeeItemEnum::getExpenseType)
.collect(Collectors.toList());
// 获取费用配置映射
Map<String, WalletAllocationDTO> allocationConfigMap = walletAllocationConfigDAO
.selectByExpenseTypeList(FranchiseBrandEnum.ZXJP.getCode(), null)
.stream()
.collect(Collectors.toMap(WalletAllocationDTO::getExpenseType, Function.identity()));
// 获取订单实际费用明细
List<ExpenseTypeAmountDTO> actualExpenseList = storeOrderOptionSnapshotDAO
.getExpenseTypeAmountByOrderId(storeOrder.getId());
// 构建已存在的费用类型集合
Set<String> processedExpenseTypes = new HashSet<>();
// 构建结果集
List<PreAllocationRecordVO> result = new ArrayList<>();
// 处理实际费用明细
for (ExpenseTypeAmountDTO expense : actualExpenseList) {
String expenseType = expense.getExpenseType();
BigDecimal payAmount;
if (processedExpenseTypes.contains(expenseType)) {
// 重复的费用类型金额设为0
payAmount = BigDecimal.ZERO;
} else {
payAmount = expense.getTotalAmount();
processedExpenseTypes.add(expenseType);
}
PreAllocationRecordVO record = buildPreAllocationRecord(
storeOrder, shopId, expenseType, payAmount, allocationConfigMap);
result.add(record);
}
// 处理配置中但订单中没有的费用
for (String expenseType : baseExpenseTypeList) {
// 如果已经处理过金额设为0继续添加
if (processedExpenseTypes.contains(expenseType)) {
PreAllocationRecordVO record = buildPreAllocationRecord(
storeOrder, shopId, expenseType, BigDecimal.ZERO, allocationConfigMap);
result.add(record);
continue;
}
// 未处理过的,从订单中获取金额
BigDecimal amount = getAmountFromOrderByExpenseType(storeOrder, expenseType);
PreAllocationRecordVO record = buildPreAllocationRecord(
storeOrder, shopId, expenseType, amount, allocationConfigMap);
result.add(record);
processedExpenseTypes.add(expenseType);
}
return result;
}
List<String> payNoList = list.stream().filter(x-> StringUtil.isNotEmpty(x.getPayNo())).map(PreAllocationRecordDO::getPayNo).collect(Collectors.toList());
Map<String, WalletPayInfoDO> map = new HashMap<>();
@@ -116,10 +614,101 @@ public class PreAllocationRecordServiceImpl implements PreAllocationRecordServic
return preAllocationRecordVOS;
}
/**
* 构建预分配记录
*/
private PreAllocationRecordVO buildPreAllocationRecord(
StoreOrderDO storeOrder, Long shopId, String expenseType,
BigDecimal payAmount, Map<String, WalletAllocationDTO> allocationConfigMap) {
PreAllocationRecordVO record = new PreAllocationRecordVO();
record.setShopId(shopId);
record.setOrderId(storeOrder.getId());
record.setExpenseType(expenseType);
record.setExpenseTypeName(WalletFeeItemEnum.getByExpenseTypeName(expenseType));
record.setPayAmount(payAmount);
record.setClaimStatus(ClaimStatusEnum.TO_BE_CLAIMED.getCode());
record.setAllocationStatus(AllocationPayStatusEnum.UNPAID.getStatus());
// 设置收款方信息
WalletAllocationDTO allocation = allocationConfigMap.get(expenseType);
if (allocation != null) {
record.setPayeeName(allocation.getPayeeName());
record.setPayeeCode(allocation.getPayeeCode());
}
dictService.fillDictField(record);
return record;
}
/**
* 根据费用类型从订单中获取金额
*/
private BigDecimal getAmountFromOrderByExpenseType(StoreOrderDO storeOrder, String expenseType) {
if (WalletFeeItemEnum.FRANCHISE_FEE.getExpenseType().equals(expenseType)) {
return storeOrder.getFranchiseFee();
}
if (WalletFeeItemEnum.MANAGEMENT_FEE.getExpenseType().equals(expenseType)) {
return storeOrder.getManagementFee();
}
if (WalletFeeItemEnum.BRAND_USAGE_FEE.getExpenseType().equals(expenseType)) {
return storeOrder.getBrandUsageFee();
}
if (WalletFeeItemEnum.DESIGN_FEE_GROUP.getExpenseType().equals(expenseType)) {
return storeOrder.getDesignFee();
}
if (WalletFeeItemEnum.EARNEST_MONEY.getExpenseType().equals(expenseType)) {
return storeOrder.getContractDeposit();
}
return BigDecimal.ZERO;
}
public BigDecimal sumAmount(List<WalletPayInfoDO> list) {
if (list == null || list.isEmpty()) {
return BigDecimal.ZERO;
}
// 方法1使用 map 和 reduce
return list.stream()
.map(WalletPayInfoDO::getPayAmount)
.filter(Objects::nonNull)
.reduce(BigDecimal.ZERO, BigDecimal::add);
}
@Override
public List<PreAllocationRecordDO> listDOByShop(Long shopId) {
return dao.queryPageByShopId(shopId);
}
@Override
public Integer pushStandardStoreFee(StoreOrderDO order) {
FranchiseFeeDO franchiseFeeDO = new FranchiseFeeDO();
franchiseFeeDO.setXgjCollectionStatus(XGJCollectionStatusEnum.WAIT_PAY.getCode());
franchiseFeeDO.setCreateTime(new Date());
franchiseFeeDO.setShopId(order.getShopId());
//加盟费
franchiseFeeDO.setYearFranchiseFee(order.getFranchiseFee().stripTrailingZeros().toPlainString());
//保证金
franchiseFeeDO.setLoanMargin(order.getContractDeposit().stripTrailingZeros().toPlainString());
//品牌使用费
franchiseFeeDO.setFirstYearFee(order.getBrandUsageFee().stripTrailingZeros().toPlainString());
//管理费
franchiseFeeDO.setFirstYearManageFee(order.getManagementFee().stripTrailingZeros().toPlainString());
//设计费
franchiseFeeDO.setPerformanceBond(order.getDesignFee().stripTrailingZeros().toPlainString());
franchiseFeeDO.setDiscountReason("标准AI店优惠");
//系统使用费
franchiseFeeDO.setCashierFee(order.getSystemUsageFee().stripTrailingZeros().toPlainString());
franchiseFeeDO.setPayType(PayTypeEnum.PING_AN.getType());
Integer feeId = franchiseFeeMapper.insertSelective(franchiseFeeDO);
ShopInfoDO shopInfoDO = shopInfoDAO.getShopInfo(order.getShopId());
LineInfoDO lineInfo = lineInfoDAO.getLineInfo(shopInfoDO.getLineId());
PushFranchiseFeeRequest feeRequest = new PushFranchiseFeeRequest(shopInfoDO.getId(), lineInfo.getUsername(), franchiseFeeDO,Integer.valueOf(shopInfoDO.getFranchiseBrand()));
feeRequest.setJoinBrand(Integer.valueOf(shopInfoDO.getFranchiseBrand()));
pushService.pushFranchiseFeeToXGJ(feeRequest);
return feeId;
}
}