package com.ydd.app.service.impl; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.ydd.app.dto.OrderValuationDto; import com.ydd.app.dto.OrderValuationReq; import com.ydd.app.dto.ValuationRes; import com.ydd.app.response.OrderValuationResponse; import com.ydd.app.service.OpenApiOrderValuationService; import com.ydd.app.vo.OrderValuationVo; import com.ydd.common.constant.BillingConstant; import com.ydd.common.core.domain.ResponseResult; import com.ydd.common.enums.DeliveryTypeEnums; import com.ydd.common.enums.ResponseResultCodeEnum; import com.ydd.common.utils.SnCodeUtils; import com.ydd.common.utils.StringUtils; import com.ydd.ecloud.core.utils.BigDecimalUtils; import com.ydd.module.domain.*; import com.ydd.module.dto.*; import com.ydd.module.enums.*; import com.ydd.module.service.*; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.compress.utils.Lists; import org.springframework.beans.BeanUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.math.BigDecimal; import java.util.*; import java.util.stream.Collectors; /** * 开放接口-订单计价ServiceImpl * @author 叶君翔 * @date 2022/04/08 15:51 */ @Slf4j @Service @RequiredArgsConstructor(onConstructor_ = @Autowired) public class OpenApiOrderValuationServiceImpl implements OpenApiOrderValuationService { private final IShopService iShopService; private final IMemberService iMemberService; private final IProductService iProductService; private final IPackageCityConfigService iPackageCityConfigService; private final IPackageDeliveryService iPackageDeliveryService; private final IPackageDiscountService iPackageDiscountService; private final IPackageDiscountDetailService iPackageDiscountDetailService; private final IPackageCommissionService iPackageCommissionService; private final IPackageCommissionDetailService iPackageCommissionDetailService; private final IDspDeliveryService iDspDeliveryService; private final IShopDeliveryDisableService iShopDeliveryDisableService; private final IShopDeliveryService iShopDeliveryService; private final IMemberConfigService iMemberConfigService; @Override public ResponseResult valuation(OrderValuationReq valuationReq) { OrderValuationDto valuationDto = new OrderValuationDto(); // 参数校验 ResponseResult result = this.validParam(valuationReq, valuationDto); if (result.getCode() != ResponseResultCodeEnum.SUCCESS.getCode()) { return result; } Product product = iProductService.getById(valuationReq.getCategoryId()); if (product == null) { return ResponseResult.error(ResponseResultCodeEnum.CATEGORY_NOT_EXIST); } valuationDto.setProduct(product); valuationDto.setOrderSn(SnCodeUtils.createSn()); valuationDto.setTakeType(0); // 开放平台大商户对应的用户 Member member = iMemberService.getOne(new QueryWrapper().eq("member_type", MemberTypeEnum.MERCHANT.type).eq("merchant_id", valuationDto.getMerchantId())); // 获取最匹配的运力包(门店 > 城市 > 全国) Long deliveryPackageId = iPackageCityConfigService.getPackageId(valuationDto.getShopId(), member, null, PackageCityConfigPackageTypeEnum.DELIVERY.type); List types = Lists.newArrayList(); PackageDeliveryDto packageDeliveryDto = null; if (deliveryPackageId != null) { packageDeliveryDto = iPackageDeliveryService.getDeliveryDtoByPackageIdAndDeliveryType(deliveryPackageId); List deliveryDetailDtoList = packageDeliveryDto.getPackageDeliveryDetailDtoList(); if (CollectionUtils.isNotEmpty(deliveryDetailDtoList)) { types = deliveryDetailDtoList.stream().map(PackageDeliveryDetailDto::getDeliveryType).collect(Collectors.toList()); } } // 获取门店屏蔽运力 List disableDeliveryTypes = iShopDeliveryDisableService.list(new QueryWrapper() .eq("shop_id", valuationDto.getShopId()).eq("deleted", 0)) .stream().map(ShopDeliveryDisable::getDeliveryType).collect(Collectors.toList()); if (CollectionUtils.isNotEmpty(disableDeliveryTypes)) { types.removeAll(disableDeliveryTypes); } // 获取可用发单运力 List deliveryInfos = this.getDeliveryInfos(valuationDto, types); if (CollectionUtils.isEmpty(deliveryInfos)) { log.warn("无可用发单运力!"); return ResponseResult.error(ResponseResultCodeEnum.NO_DELIVERY); } List deliveryTypes = deliveryInfos.stream().map(DspDelivery::getType).collect(Collectors.toList()); // 获取最匹配的优惠包(门店 > 代理商 > 全国) Long discountPackageId = iPackageCityConfigService.getPackageId(valuationDto.getShopId(), member, null, PackageCityConfigPackageTypeEnum.DISCOUNT.type); Map> packageDiscountMap = new HashMap<>(); if (discountPackageId != null) { List discountDetailDtoList = iPackageDiscountDetailService.getDiscountListByPackageIdAndDeliveryType(discountPackageId, deliveryTypes); packageDiscountMap = discountDetailDtoList.stream().collect(Collectors.groupingBy(PackageDiscountDetailDto::getDeliveryType)); } // 获取最匹配的佣金包(门店 > 代理商 > 全国) Long commissionPackageId = iPackageCityConfigService.getPackageId(valuationDto.getShopId(), member, null, PackageCityConfigPackageTypeEnum.COMMISSION.type); Map> packageCommissionMap = new HashMap<>(); if (commissionPackageId != null) { List commissionDetailDtoList = iPackageCommissionDetailService.getCommissionListByPackageIdAndDeliveryType(commissionPackageId, deliveryTypes); packageCommissionMap = commissionDetailDtoList.stream().collect(Collectors.groupingBy(PackageCommissionDetailDto::getDeliveryType)); } // 计价 List list = this.getValuationResList(member, valuationDto, deliveryInfos, packageDeliveryDto, packageDiscountMap, packageCommissionMap); // 默认价格优先 list.sort(Comparator.comparing(ValuationRes::getDeliveryAmount)); // 运力包发单类型为自定义, 则先按照sort排,再按价格排 if (packageDeliveryDto != null && PackageDeliveryTypeEnum.CUSTOM.type.equals(packageDeliveryDto.getType())) { Collections.sort(list); } // 处理发单运力 List billList = this.handleBillList(member.getId(), list); // 设置发单时长 if (packageDeliveryDto != null) { billList = this.setBillingDuration(packageDeliveryDto, billList); } // todo: 计价结果缓存到redis, 10分钟有效 // 数据转换 List valuationVos = this.convertResult(billList); OrderValuationResponse response = OrderValuationResponse.builder().valuationList(valuationVos).outOrderSn(valuationReq.getOutOrderSn()).build(); return ResponseResult.success(response); } private List convertResult(List billList) { // todo: 数据转换 return null; } private List handleBillList(Long memberId, List list) { // 查询下单设置推荐屏蔽运力 List billList = Lists.newArrayList(); MemberConfig config = iMemberConfigService.getOne(new QueryWrapper().eq("member_id", memberId)); if (config != null) { if (StringUtils.isNotEmpty(config.getBillDeliveryIds())) { List billDeliveryIds = Arrays.asList(config.getBillDeliveryIds().split(",")); // 过滤出商家设置的推荐运力, 计价页面靠前显示 billList = list.stream().filter(a -> billDeliveryIds.contains(a.getDeliveryId().toString())).collect(Collectors.toList()); } if (StringUtils.isNotEmpty(config.getShieldDeliveryIds())) { List shieldDeliveryIds = Arrays.asList(config.getShieldDeliveryIds().split(",")); // 过滤掉商家设置的屏蔽运力 list = list.stream().filter(a -> !shieldDeliveryIds.contains(a.getDeliveryId().toString())).collect(Collectors.toList()); } } list.removeAll(billList); billList.addAll(list); // 闪送距离替换 Optional optional = billList.stream().filter(item -> !item.getDeliveryType().equals(DeliveryTypeEnums.SHAN_SONG.getType())).findFirst(); if (optional.isPresent()) { String desc = optional.get().getDesc(); for (ValuationRes res1 : billList) { if (DeliveryTypeEnums.SHAN_SONG.getType().equals(res1.getDeliveryType())) { res1.setDesc(desc); break; } } } return billList; } private List getValuationResList(Member member, OrderValuationDto valuationDto, List deliveryInfos, PackageDeliveryDto packageDeliveryDto, Map> packageDiscountMap, Map> packageCommissionMap) { List valuationResList = Lists.newArrayList(); for (DeliveryInfo info : deliveryInfos) { // 计价 ValuationRes valuationRes = this.doValuation(valuationDto, info, valuationDto.getMerchantId(), valuationDto.getShopId()); if (valuationRes == null) { continue; } valuationRes.setPreferredDelivery(info.getPreferredDelivery()); valuationRes.setOriginalMoney(valuationRes.getDeliveryAmount()); // 设置排序 if (packageDeliveryDto != null && PackageDeliveryTypeEnum.CUSTOM.type.equals(packageDeliveryDto.getType())) { this.setBillingSort(packageDeliveryDto, valuationRes); } // 设置优惠 if (packageDiscountMap.size() > 0) { this.setDiscountInfo(packageDiscountMap.get(info.getType()), valuationRes); } // 设置佣金 if (packageCommissionMap.size() > 0) { this.setCommissionInfo(packageCommissionMap.get(info.getType()), valuationRes); } valuationRes.setIsMerchant(info.getIsMerchant()); if (valuationRes.getIsMine() == 0) { // 校验余额是否充足 if (member.getAmount().compareTo(valuationRes.getDeliveryAmount()) >= 0) { valuationRes.setIsEnough(StatusEnum.SHOW.status); } } valuationResList.add(valuationRes); } return valuationResList; } private ValuationRes doValuation(OrderValuationDto valuationDto, DeliveryInfo info, Long merchantId, Long shopId) { // todo: 计价主逻辑 return null; } private void setBillingSort(PackageDeliveryDto packageDeliveryDto, ValuationRes valuationRes) { List deliveryDetailDtoList = packageDeliveryDto.getPackageDeliveryDetailDtoList(); if (CollectionUtils.isNotEmpty(deliveryDetailDtoList)) { Optional optional = deliveryDetailDtoList.stream().filter(item -> valuationRes.getDeliveryType().equals(item.getDeliveryType())).findFirst(); if (optional.isPresent()) { PackageDeliveryDetailDto packageDeliveryDetailDto = optional.get(); valuationRes.setSort((packageDeliveryDetailDto.getSort() == null || packageDeliveryDetailDto.getSort() == 0) ? BillingConstant.DEFAULT_BILL_SORT : packageDeliveryDetailDto.getSort()); } } } private List setBillingDuration(PackageDeliveryDto packageDeliveryDto, List billList) { String billDurationStr = packageDeliveryDto.getBillDurationStr(); List deliveryDetailList = packageDeliveryDto.getPackageDeliveryDetailDtoList(); if (StringUtils.isNotEmpty(billDurationStr) && CollectionUtils.isNotEmpty(deliveryDetailList)) { String[] split = billDurationStr.split(","); if (PackageDeliveryTypeEnum.CUSTOM.type.equals(packageDeliveryDto.getType())) { deliveryDetailList = deliveryDetailList.stream().filter(item -> item.getSort() != null && item.getSort() > 0).collect(Collectors.toList()); deliveryDetailList.sort(Comparator.comparing(PackageDeliveryDetailDto::getSort)); for (int i = 0; i < deliveryDetailList.size(); i++) { PackageDeliveryDetailDto packageDeliveryDetailDto = deliveryDetailList.get(i); if (i < split.length) { packageDeliveryDetailDto.setBillDuration(Integer.parseInt(split[i])); } } for (ValuationRes valuationRes : billList) { int billDuration = BillingConstant.DEFAULT_BILL_DURATION; Optional optional = deliveryDetailList.stream().filter(item -> item.getDeliveryType().equals(valuationRes.getDeliveryType())).findAny(); if (optional.isPresent()) { PackageDeliveryDetailDto packageDeliveryDetailDto = optional.get(); billDuration = packageDeliveryDetailDto.getBillDuration(); } valuationRes.setBillDuration(billDuration == 0 ? BillingConstant.DEFAULT_BILL_DURATION : billDuration); } } else { for (int i = 0; i < billList.size(); i++) { ValuationRes valuationRes = billList.get(i); int billDuration = BillingConstant.DEFAULT_BILL_DURATION; if (i < split.length) { billDuration = Integer.parseInt(split[i]); } valuationRes.setBillDuration(billDuration); } } } else { billList = billList.stream().map(valuationRes -> valuationRes.setBillDuration(BillingConstant.DEFAULT_BILL_DURATION)).collect(Collectors.toList()); } return billList; } private void setCommissionInfo(List packageCommissionDetailDtoList, ValuationRes valuationRes) { BigDecimal commission = BigDecimal.ZERO; if (valuationRes.getIsMine() == 1 || DeliveryTypeEnums.HUO_LA_LA.getType().equals(valuationRes.getDeliveryType())) { valuationRes.setCommission(commission); return; } if (CollectionUtils.isNotEmpty(packageCommissionDetailDtoList) && packageCommissionDetailDtoList.size() > 0) { PackageCommissionDetailDto packageCommissionDetailDto = packageCommissionDetailDtoList.get(0); if (PackageCommissionTypeEnum.RATE.type.equals(packageCommissionDetailDto.getCommissionType())) { if (packageCommissionDetailDto.getValue() != null) { commission = packageCommissionDetailDto.getValue().multiply(valuationRes.getDeliveryAmount()) .divide(new BigDecimal("100"), BigDecimal.ROUND_HALF_UP).setScale(6, BigDecimal.ROUND_HALF_UP); } } else if (PackageDiscountDetailTypeEnum.GRADIENT.type.equals(packageCommissionDetailDto.getCommissionType())) { for (PackageCommissionDetailDto item : packageCommissionDetailDtoList) { boolean inRange = BigDecimalUtils.inRange(item.getLeftValue(), item.getRightValue(), valuationRes.getDeliveryAmount()); if (inRange) { if (item.getValue() != null) { commission = item.getValue(); } break; } } } } valuationRes.setCommission(commission); valuationRes.setDeliveryAmount(commission.add(valuationRes.getDeliveryAmount())); } private void setDiscountInfo(List discountDetailDtoList, ValuationRes valuationRes) { if (valuationRes.getIsMine() == 1) { return; } if (CollectionUtils.isNotEmpty(discountDetailDtoList) && discountDetailDtoList.size() > 0) { PackageDiscountDetailDto discountDetailDto = discountDetailDtoList.get(0); if (PackageDiscountDetailTypeEnum.ZHE_KOU.type.equals(discountDetailDto.getType())) { if (discountDetailDto.getValue() != null) { BigDecimal discountValue = discountDetailDto.getValue().multiply(valuationRes.getDeliveryAmount()) .divide(BigDecimal.TEN, BigDecimal.ROUND_HALF_UP).setScale(6, BigDecimal.ROUND_HALF_UP); double abs = Math.abs(valuationRes.getDeliveryAmount().subtract(discountValue).doubleValue()); if (discountDetailDto.getMaxValue() != null) { abs = Math.min(abs, discountDetailDto.getMaxValue().doubleValue()); } // 判断是优惠还是提价 boolean positiveNum = discountValue.subtract(valuationRes.getDeliveryAmount()).compareTo(BigDecimal.ZERO) >= 0; if (positiveNum) { valuationRes.setDeliveryAmount(valuationRes.getDeliveryAmount().add(new BigDecimal(abs))); } else { valuationRes.setDeliveryAmount(valuationRes.getDeliveryAmount().subtract(new BigDecimal(abs))); } valuationRes.setZk(discountDetailDto.getValue()); } } else if (PackageDiscountDetailTypeEnum.GRADIENT.type.equals(discountDetailDto.getType())) { for (PackageDiscountDetailDto item : discountDetailDtoList) { boolean inRange = BigDecimalUtils.inRange(item.getLeftValue(), item.getRightValue(), valuationRes.getDeliveryAmount()); if (inRange) { if (item.getValue() != null) { BigDecimal discountAmount = valuationRes.getDeliveryAmount().subtract(item.getValue()); valuationRes.setDeliveryAmount(discountAmount.compareTo(BigDecimal.ZERO) > 0 ? discountAmount : BigDecimal.ZERO); valuationRes.setMj(item.getValue()); } break; } } } } } private List getDeliveryInfos(OrderValuationDto valuationDto, List types) { List list = iDspDeliveryService.list(new QueryWrapper() .isNotNull("parent_id") .eq("status", StatusEnum.SHOW.status) .eq("deleted", IsDeleteEnum.NORMAL.status) .ne("type", DeliveryTypeEnums.HUO_LA_LA.getType()) .in(CollectionUtils.isNotEmpty(types), "type", types)); List infos = Lists.newArrayList(); List deliveryTypes = Arrays.asList(DeliveryTypeEnums.DADA.getType(), DeliveryTypeEnums.DADA_YZ.getType(), DeliveryTypeEnums.DWD.getType(), DeliveryTypeEnums.FENG_NIAO.getType(), DeliveryTypeEnums.FENG_NIAO_PT.getType(), DeliveryTypeEnums.MEI_TUAN.getType(), DeliveryTypeEnums.SHAN_SONG.getType(), DeliveryTypeEnums.SHUN_FENG.getType()); List deliveryIds = list.stream().map(DspDelivery::getId).collect(Collectors.toList()); Map> deliveryMap = new HashMap<>(); if (CollectionUtils.isNotEmpty(deliveryIds)) { deliveryMap = iShopDeliveryService.list(new QueryWrapper() .eq("merchant_id", valuationDto.getMerchantId()) .in("delivery_id", deliveryIds) .eq("deleted", IsDeleteEnum.NORMAL.status) .eq("shop_id", valuationDto.getShopId()) .eq("bind_status",1)) .stream() .collect(Collectors.groupingBy(item -> item.getDeliveryId() + "-" + item.getMerchantId() + "-" + item.getShopId())); } for (DspDelivery delivery : list) { DeliveryInfo info = new DeliveryInfo(); BeanUtils.copyProperties(delivery, info); if (deliveryTypes.contains(info.getType()) && valuationDto.getMerchantId() != null && valuationDto.getShopId() != null) { List shopDeliveries = deliveryMap.get(info.getId() + "-" + valuationDto.getMerchantId() + "-" + valuationDto.getShopId()); ShopDelivery sd = new ShopDelivery(); if (CollectionUtils.isNotEmpty(shopDeliveries)) { sd = shopDeliveries.get(0); } if (sd.getThirdShopId() != null && (DeliveryTypeEnums.DADA.getType().equals(info.getType()) || DeliveryTypeEnums.DADA_YZ.getType().equals(info.getType()) || DeliveryTypeEnums.SHAN_SONG.getType().equals(info.getType()))) { info.setShopId(sd.getThirdShopId()); } if(sd.getThirdShopId() != null && (DeliveryTypeEnums.FENG_NIAO.getType().equals(info.getType()) || DeliveryTypeEnums.FENG_NIAO_PT.getType().equals(info.getType()) || DeliveryTypeEnums.MEI_TUAN.getType().equals(info.getType()))) { info.setThirdShopId(sd.getThirdShopId()); } } info.setIsMine(0); infos.add(info); } return infos; } private ResponseResult validParam(OrderValuationReq valuationReq, OrderValuationDto valuationDto) { ResponseResult result = ResponseResult.success(); if (StringUtils.isBlank(valuationReq.getShopCode())) { if (StringUtils.isBlank(valuationReq.getSendName())) { return ResponseResult.error(ResponseResultCodeEnum.FIELD_EMPTY, "发件人名称", null); } if (StringUtils.isBlank(valuationReq.getSendPhone())) { return ResponseResult.error(ResponseResultCodeEnum.FIELD_EMPTY, "发件人联系电话", null); } if (StringUtils.isBlank(valuationReq.getSendProvinceName())) { return ResponseResult.error(ResponseResultCodeEnum.FIELD_EMPTY, "发件人所在省", null); } if (StringUtils.isBlank(valuationReq.getSendCityName())) { return ResponseResult.error(ResponseResultCodeEnum.FIELD_EMPTY, "发件人所在市", null); } if (StringUtils.isBlank(valuationReq.getSendAddress())) { return ResponseResult.error(ResponseResultCodeEnum.FIELD_EMPTY, "发件人详细地址", null); } if (StringUtils.isBlank(valuationReq.getSendLng())) { return ResponseResult.error(ResponseResultCodeEnum.FIELD_EMPTY, "发件人纬度", null); } if (StringUtils.isBlank(valuationReq.getSendLat())) { return ResponseResult.error(ResponseResultCodeEnum.FIELD_EMPTY, "发件人经度", null); } } else { Shop shop = iShopService.getByCode(valuationReq.getShopCode()); if (shop == null) { return ResponseResult.error(ResponseResultCodeEnum.SHOP_NOT_EXIST); } valuationReq.setSendName(shop.getContactName()); valuationReq.setSendPhone(shop.getMobile()); valuationReq.setSendProvinceName(shop.getProvinceName()); valuationReq.setSendCityName(shop.getCityName()); valuationReq.setSendDistrictName(shop.getDistrictName()); valuationReq.setSendAddress(shop.getAddress()); valuationReq.setSendHouseNumber(shop.getStreet()); valuationReq.setSendLat(shop.getLat()); valuationReq.setSendLng(shop.getLng()); valuationDto.setShopId(shop.getId()); valuationDto.setShopName(shop.getName()); valuationDto.setMerchantId(shop.getMerchantId()); } BeanUtils.copyProperties(valuationReq, valuationDto); return result; } }