server/admin/src/main/java/com/doumee/api/business/OrdersController.java
@@ -94,9 +94,10 @@ for (Orders o : records) { OrdersExportVO vo = new OrdersExportVO(); vo.setCode(o.getCode()); vo.setRelationOrderCode(o.getRelationOrderCode()); vo.setGoodsInfo(o.getGoodsInfo()); vo.setTypeName(o.getType() != null ? (o.getType() == 0 ? "就地存取" : "异地存取") : ""); vo.setOrderLevel(Constants.getDriverLevelName(Objects.nonNull(o.getOrderLevel())?Integer.valueOf(o.getOrderLevel()):Constants.ZERO)); vo.setTypeName(o.getType() != null ? (o.getType() == 0 ? "就地寄存" : "同城寄送") : ""); vo.setOrderLevel(StringUtils.isNotBlank(o.getOrderLevel()) ? Constants.getDriverLevelName(Integer.valueOf(o.getOrderLevel())) : Constants.getDriverLevelName(Constants.ZERO)); vo.setDeclaredFee(String.valueOf(Constants.getFormatMoney(o.getDeclaredFee()))); vo.setBasicAmount(String.valueOf(Constants.getFormatMoney(o.getBasicAmount()))); vo.setTotalAmount(String.valueOf(Constants.getFormatMoney(o.getTotalAmount()))); @@ -106,8 +107,8 @@ vo.setOverdueAmount(String.valueOf(Constants.getFormatMoney(o.getOverdueAmount()))); vo.setExceptionAmount(String.valueOf(Constants.getFormatMoney(o.getExceptionAmount()))); vo.setDeductionAmount(String.valueOf(Constants.getFormatMoney(o.getDeductionAmount()))); vo.setShopCompensationAmount(String.valueOf(Constants.getFormatMoney(o.getShopCompensationAmount()))); vo.setExceptionFee(String.valueOf(Constants.getFormatMoney(o.getExceptionFee()))); vo.setShopCompensationAmount(String.valueOf(Constants.getFormatMoney(o.getShopCompensationAmount()))); vo.setStatusDesc(o.getStatusDesc()); vo.setSettlementDesc(o.getSettlementStatus() != null ? (o.getSettlementStatus() == 1 ? "已结算" : "待结算") : ""); vo.setPayTime(o.getPayTime()); server/admin/src/main/java/com/doumee/api/business/PricingRuleController.java
@@ -44,7 +44,7 @@ @PreventRepeat @ApiOperation("批量保存就地存取规则") @ApiOperation("批量保存就地寄存规则") @PostMapping("/localStorage/batchSave") @RequiresPermissions("business:pricingRule:create") public ApiResponse batchSaveLocalStoragePricing(@RequestBody @Validated LocalStoragePricingSaveDTO request) { @@ -52,7 +52,7 @@ return ApiResponse.success(null); } @ApiOperation("查询就地存取规则列表") @ApiOperation("查询就地寄存规则列表") @GetMapping("/localStorage/list") @RequiresPermissions("business:pricingRule:query") public ApiResponse<List<LocalStoragePricingVO>> listLocalStoragePricing(@RequestParam Integer cityId) { server/admin/src/main/resources/application.yml
@@ -12,7 +12,7 @@ spring: profiles: active: pro active: dev # JSON返回配置 jackson: # 默认时区 server/services/db/db_change.sql
@@ -418,10 +418,10 @@ -- ============================================================ -- 2026/04/15 订单物品明细表添加就地存取单价字段 -- 2026/04/15 订单物品明细表添加就地寄存单价字段 -- ============================================================ ALTER TABLE `orders_detail` ADD COLUMN `LOCALLY_PRICE` BIGINT DEFAULT NULL COMMENT '就地存取单价(分/天)' AFTER `EXTRA_PRICE`; ALTER TABLE `orders_detail` ADD COLUMN `LOCALLY_PRICE` BIGINT DEFAULT NULL COMMENT '就地寄存单价(分/天)' AFTER `EXTRA_PRICE`; -- ============================================================ server/services/src/main/java/com/doumee/config/alipay/AlipayFundTransUniTransfer.java
@@ -74,11 +74,10 @@ AlipayFundTransUniTransferModel data = new AlipayFundTransUniTransferModel(); // 设置商家侧唯一订单号 data.setOutBizNo(dto.getOutBizNo()); // 设置订单总金额 data.setTransAmount("0.1"); // 设置描述特定的业务场景 data.setOutBizNo(dto.getOutBizNo()); // data.setTransAmount(dto.getTransAmount().setScale(2, BigDecimal.ROUND_HALF_UP).toPlainString()); // 设置订单总金额 data.setTransAmount(dto.getTransAmount().setScale(2, BigDecimal.ROUND_HALF_UP).toPlainString()); data.setBizScene("DIRECT_TRANSFER"); // 设置业务产品码 data.setProductCode("TRANS_ACCOUNT_NO_PWD"); server/services/src/main/java/com/doumee/core/utils/GeoUtils.java
@@ -29,10 +29,10 @@ } public static void main(String[] args) { double lat1 = 30.660622; // 纽约纬度 double lon1 = 114.172; // 纽约经度 double lat2 = 30.621857; // 洛杉矶纬度 double lon2 = 114.12311; // 洛杉矶经度 double lat1 = 31.969801; // 纽约纬度 double lon1 = 118.797030; // 纽约经度 double lat2 = 31.969175; // 洛杉矶纬度 double lon2 = 118.797440; // 洛杉矶经度 double distance = haversineDistance(lat1, lon1, lat2, lon2); System.out.printf("Distance: %.2f km%n", distance); server/services/src/main/java/com/doumee/core/utils/geocode/MapUtil.java
@@ -1,8 +1,10 @@ package com.doumee.core.utils.geocode; import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONObject; import com.doumee.core.utils.Http; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; @@ -24,6 +26,9 @@ /** 逆地理解析 */ private static final String GEO_URL = "https://restapi.amap.com/v3/geocode/regeo"; /** 正向地理解析 */ private static final String GEOCODE_URL = "https://restapi.amap.com/v3/geocode/geo"; /** 驾车路径规划 */ private static final String DRIVING_URL = "https://restapi.amap.com/v3/direction/driving"; @@ -36,6 +41,52 @@ } /** * 正向地理解析 - 根据地址获取经纬度 * * @param address 地址文本(如"四川省成都市") * @return "lat,lng" 格式的经纬度字符串,解析失败返回 null */ public static String geocode(String address) { try { String url = GEOCODE_URL + "?key=" + amapKey + "&address=" + URLEncoder.encode(address, "UTF-8"); log.info("高德地图正向地理解析请求: address={}", address); JSONObject json = new Http().build(url) .setConnectTimeout(5000) .setReadTimeout(10000) .get() .toJSONObject(); log.info("高德地图正向地理解析响应: {}", json); if (!"1".equals(json.getString("status"))) { log.warn("高德地图正向地理解析失败: {}", json.getString("info")); return null; } JSONArray geocodes = json.getJSONArray("geocodes"); if (geocodes == null || geocodes.isEmpty()) { log.warn("高德地图正向地理解析无结果: address={}", address); return null; } String location = geocodes.getJSONObject(0).getString("location"); // lng,lat if (StringUtils.isBlank(location)) { return null; } String[] parts = location.split(","); // 转为 lat,lng 格式 return parts[1] + "," + parts[0]; } catch (Exception e) { log.error("高德地图正向地理解析异常: address={}", address, e); return null; } } /** * 逆地理解析 - 根据经纬度获取地址信息 * 高德坐标系为 lng,lat(与腾讯 lat,lng 相反) * server/services/src/main/java/com/doumee/dao/business/model/Orders.java
@@ -57,8 +57,8 @@ @ExcelColumn(name = "会员主键") private Integer memberId; @ApiModelProperty(value = "寄存方式:0=就地存取;1=异地存取", example = "0") @ExcelColumn(name = "寄存方式", valueMapping = "0=就地存取;1=异地存取;") @ApiModelProperty(value = "寄存方式:0=就地寄存;1=同城寄送", example = "0") @ExcelColumn(name = "寄存方式", valueMapping = "0=就地寄存;1=同城寄送;") private Integer type; @ApiModelProperty(value = "是否转换订单:0=否;1=是(异地转就地)", example = "0") @@ -80,6 +80,10 @@ @ApiModelProperty(value = "关联主订单") @ExcelColumn(name = "关联主订单") private Integer relationOrderId; @TableField(exist = false) @ApiModelProperty(value = "关联订单号") private String relationOrderCode; @ApiModelProperty(value = "异常原因") @ExcelColumn(name = "异常原因") @@ -133,7 +137,7 @@ @ApiModelProperty(value = "取件纬度") private BigDecimal takeLgt; @ApiModelProperty(value = "距离(异地存取使用)") @ApiModelProperty(value = "距离(同城寄送使用)") @ExcelColumn(name = "距离") private BigDecimal distance; server/services/src/main/java/com/doumee/dao/business/model/OrdersDetail.java
@@ -73,24 +73,24 @@ @ExcelColumn(name = "单价") private Long unitPrice; @ApiModelProperty(value = "异地存取 - 配送起步里程") @ApiModelProperty(value = "同城寄送 - 配送起步里程") @ExcelColumn(name = "配送起步里程") private BigDecimal startDistance; @ApiModelProperty(value = "异地存取 - 配送起步里程每公里单价(分)") @ApiModelProperty(value = "同城寄送 - 配送起步里程每公里单价(分)") @ExcelColumn(name = "起步里程单价") private Long startPrice; @ApiModelProperty(value = "异地存取 - 超出首单里程公里数") @ApiModelProperty(value = "同城寄送 - 超出首单里程公里数") @ExcelColumn(name = "超出首单里程") private BigDecimal extraDistance; @ApiModelProperty(value = "异地存取 - 超出首单里程单价(分)") @ApiModelProperty(value = "同城寄送 - 超出首单里程单价(分)") @ExcelColumn(name = "超出首单里程单价") private Long extraPrice; @ApiModelProperty(value = "就地存取 - 单价(分)") @ExcelColumn(name = "就地存取 - 单价") @ApiModelProperty(value = "就地寄存 - 单价(分)") @ExcelColumn(name = "就地寄存 - 单价") private Long locallyPrice; } server/services/src/main/java/com/doumee/dao/business/model/PricingRule.java
@@ -48,8 +48,8 @@ @ApiModelProperty(value = "城市主键(area_id)", example = "1") private Integer cityId; @ApiModelProperty(value = "类型:0=就地存取规则;1=异地存取规则;2=预计时效;3=门店注册押金;4=分成比例", example = "0") @ExcelColumn(name = "类型", index = 2, width = 10, valueMapping = "0=就地存取规则;1=异地存取规则;2=预计失效;3=门店注册押金;4=分成比例;") @ApiModelProperty(value = "类型:0=就地寄存规则;1=同城寄送规则;2=预计时效;3=门店注册押金;4=分成比例", example = "0") @ExcelColumn(name = "类型", index = 2, width = 10, valueMapping = "0=就地寄存规则;1=同城寄送规则;2=预计失效;3=门店注册押金;4=分成比例;") private Integer type; @ApiModelProperty(value = "参数1:type (0/1)= 关联 物品尺寸(category type =4);type (2) (默认 1标速达;2=极速达) ; type (3) = 企业类型(0=企业;1=个人);type (4) = 类型(企业/个人/配送员)") server/services/src/main/java/com/doumee/dao/dto/CalculateLocalPriceDTO.java
@@ -12,13 +12,13 @@ import java.util.List; /** * 就地存取预估费用请求DTO * 就地寄存预估费用请求DTO * * @Author : Rk * @create 2026/4/14 */ @Data @ApiModel("就地存取预估费用请求") @ApiModel("就地寄存预估费用请求") public class CalculateLocalPriceDTO { @ApiModelProperty(value = "城市主键", required = true) server/services/src/main/java/com/doumee/dao/dto/CalculateRemotePriceDTO.java
@@ -11,13 +11,13 @@ import java.util.List; /** * 异地存取预估费用请求DTO * 同城寄送预估费用请求DTO * * @Author : Rk * @create 2026/4/14 */ @Data @ApiModel("异地存取预估费用请求") @ApiModel("同城寄送预估费用请求") public class CalculateRemotePriceDTO { @ApiModelProperty(value = "城市主键", required = true) server/services/src/main/java/com/doumee/dao/dto/LocalStoragePricingItemDTO.java
@@ -8,12 +8,12 @@ import java.io.Serializable; /** * 就地存取规则项 * 就地寄存规则项 * @author rk * @date 2026/04/08 */ @Data @ApiModel("就地存取规则项") @ApiModel("就地寄存规则项") public class LocalStoragePricingItemDTO implements Serializable { @ApiModelProperty(value = "物品规格主键(category.id, type=4)", required = true, example = "1") server/services/src/main/java/com/doumee/dao/dto/LocalStoragePricingSaveDTO.java
@@ -11,12 +11,12 @@ import java.util.List; /** * 就地存取规则批量保存请求 * 就地寄存规则批量保存请求 * @author rk * @date 2026/04/08 */ @Data @ApiModel("就地存取规则批量保存请求") @ApiModel("就地寄存规则批量保存请求") public class LocalStoragePricingSaveDTO implements Serializable { @ApiModelProperty(value = "城市主键", required = true, example = "1") server/services/src/main/java/com/doumee/dao/dto/OrdersRefundPageDTO.java
@@ -23,7 +23,7 @@ @ApiModelProperty(value = "物品信息") private String goodsInfo; @ApiModelProperty(value = "订单类型:0=就地存取;1=异地存取") @ApiModelProperty(value = "订单类型:0=就地寄存;1=同城寄送") private Integer orderType; @ApiModelProperty(value = "退款状态:0=退款中;1=退款成功;2=退款失败") server/services/src/main/java/com/doumee/dao/vo/ItemPriceVO.java
@@ -34,7 +34,7 @@ @ApiModelProperty("小计(分)") private Long subtotal; // ========== 异地存取额外字段 ========== // ========== 同城寄送额外字段 ========== @ApiModelProperty("起步距离(km)") private BigDecimal startDistance; @@ -48,6 +48,6 @@ @ApiModelProperty("超出距离单价(分)") private Long extraPrice; @ApiModelProperty("就地存取单价(分/天)") @ApiModelProperty("就地寄存单价(分/天)") private Long locallyPrice; } server/services/src/main/java/com/doumee/dao/vo/LocalStoragePricingVO.java
@@ -7,12 +7,12 @@ import java.io.Serializable; /** * 就地存取规则列表返回 * 就地寄存规则列表返回 * @author rk * @date 2026/04/08 */ @Data @ApiModel("就地存取规则项(列表返回)") @ApiModel("就地寄存规则项(列表返回)") public class LocalStoragePricingVO implements Serializable { @ApiModelProperty(value = "规则主键") server/services/src/main/java/com/doumee/dao/vo/MyOrderVO.java
@@ -23,7 +23,7 @@ @ApiModelProperty(value = "订单编号") private String code; @ApiModelProperty(value = "寄存方式:0=就地存取;1=异地存取") @ApiModelProperty(value = "寄存方式:0=就地寄存;1=同城寄送") private Integer type; @ApiModelProperty(value = "就地寄存状态:0=待支付;1=待寄存;2=已寄存;5=待取件;6=存在逾期;7=已完成;96:订单关闭(退款);97:取消逾期;98=取消中;99=已取消;" + server/services/src/main/java/com/doumee/dao/vo/OrderDispatchVO.java
@@ -21,7 +21,7 @@ @ApiModelProperty(value = "实付金额(元)") private Double payAmountYuan; @ApiModelProperty(value = "配送方式:0=就地存取;1=异地存取") @ApiModelProperty(value = "配送方式:0=就地寄存;1=同城寄送") private Integer type; @ApiModelProperty(value = "配送方式描述") server/services/src/main/java/com/doumee/dao/vo/OrdersExportVO.java
@@ -11,57 +11,60 @@ @ExcelColumn(name = "订单编号", index = 0) private String code; @ExcelColumn(name = "物品信息", index = 1) @ExcelColumn(name = "关联订单号", index = 1) private String relationOrderCode; @ExcelColumn(name = "物品信息", index = 2) private String goodsInfo; @ExcelColumn(name = "类型", index = 2) @ExcelColumn(name = "类型", index = 3) private String typeName; @ExcelColumn(name = "订单级别", index = 3) @ExcelColumn(name = "订单级别", index = 4) private String orderLevel; @ExcelColumn(name = "物品保费(元)", index = 4) @ExcelColumn(name = "物品保费(元)", index = 5) private String declaredFee; @ExcelColumn(name = "基础服务费(元)", index = 5) @ExcelColumn(name = "基础服务费(元)", index = 6) private String basicAmount; @ExcelColumn(name = "订单总价(元)", index = 6) @ExcelColumn(name = "订单总价(元)", index = 7) private String totalAmount; @ExcelColumn(name = "实付现金(元)", index = 7) @ExcelColumn(name = "实付现金(元)", index = 8) private String payAmount; @ExcelColumn(name = "加急费(元)", index = 8) @ExcelColumn(name = "加急费(元)", index = 9) private String urgentAmount; @ExcelColumn(name = "退款金额(元)", index = 9) @ExcelColumn(name = "退款金额(元)", index = 10) private String refundAmount; @ExcelColumn(name = "超时金额(元)", index = 10) @ExcelColumn(name = "超时金额(元)", index = 11) private String overdueAmount; @ExcelColumn(name = "异常金额(元)", index = 11) @ExcelColumn(name = "异常金额(元)", index = 12) private String exceptionAmount; @ExcelColumn(name = "优惠券折扣(元)", index = 12) @ExcelColumn(name = "优惠券折扣(元)", index = 13) private String deductionAmount; @ExcelColumn(name = "门店补偿费用(元)", index = 13) private String shopCompensationAmount; @ExcelColumn(name = "司机补偿费用(元)", index = 14) private String exceptionFee; @ExcelColumn(name = "订单状态", index = 15) @ExcelColumn(name = "门店保管补贴(元)", index = 15) private String shopCompensationAmount; @ExcelColumn(name = "订单状态", index = 16) private String statusDesc; @ExcelColumn(name = "结算状态", index = 16) @ExcelColumn(name = "结算状态", index = 17) private String settlementDesc; @ExcelColumn(name = "支付时间", index = 17, dateFormat = "yyyy-MM-dd HH:mm:ss", width = 16) @ExcelColumn(name = "支付时间", index = 18, dateFormat = "yyyy-MM-dd HH:mm:ss", width = 16) private Date payTime; @ExcelColumn(name = "创建时间", index = 18, dateFormat = "yyyy-MM-dd HH:mm:ss", width = 16) @ExcelColumn(name = "创建时间", index = 19, dateFormat = "yyyy-MM-dd HH:mm:ss", width = 16) private Date createTime; } server/services/src/main/java/com/doumee/dao/vo/OrdersRefundPageVO.java
@@ -32,8 +32,8 @@ @ApiModelProperty(value = "物品信息") private String goodsInfo; @ExcelColumn(name = "订单类型", valueMapping = "0=就地存取;1=异地存取;") @ApiModelProperty(value = "订单类型:0=就地存取;1=异地存取") @ExcelColumn(name = "订单类型", valueMapping = "0=就地寄存;1=同城寄送;") @ApiModelProperty(value = "订单类型:0=就地寄存;1=同城寄送") private Integer orderType; @ExcelColumn(name = "订单级别") server/services/src/main/java/com/doumee/service/business/AreasService.java
@@ -159,4 +159,9 @@ */ void updateStatus(Areas areas); /** * 一次性:为所有城市级别区划填充经纬度到info字段 */ String fillCityLocation(); } server/services/src/main/java/com/doumee/service/business/OrdersService.java
@@ -213,17 +213,17 @@ BigDecimal calculateInsuranceFee(BigDecimal declaredValue); /** * 计算就地存取预估费用 * 计算就地寄存预估费用 * * @param dto 就地存取计价请求参数 * @param dto 就地寄存计价请求参数 * @return 价格计算结果 */ PriceCalculateVO calculateLocalPrice(CalculateLocalPriceDTO dto); /** * 计算异地存取预估费用 * 计算同城寄送预估费用 * * @param dto 异地存取计价请求参数 * @param dto 同城寄送计价请求参数 * @return 价格计算结果 */ PriceCalculateVO calculateRemotePrice(CalculateRemotePriceDTO dto); @@ -451,7 +451,7 @@ int notifyArrivalPickUp(); /** * 订单异常处理:异地无取件门店已送达订单,创建就地存取新订单 * 订单异常处理:异地无取件门店已送达订单,创建就地寄存新订单 */ void handleOrderException(HandleOrderExceptionDTO dto); server/services/src/main/java/com/doumee/service/business/PricingRuleService.java
@@ -108,15 +108,15 @@ long count(PricingRule pricingRule); /** * 批量保存就地存取规则 * 批量保存就地寄存规则 * @param request 批量保存请求 */ void batchSaveLocalStoragePricing(LocalStoragePricingSaveDTO request); /** * 查询就地存取规则列表 * 查询就地寄存规则列表 * @param cityId 城市主键 * @return 就地存取规则列表 * @return 就地寄存规则列表 */ List<LocalStoragePricingVO> listLocalStoragePricing(Integer cityId); server/services/src/main/java/com/doumee/service/business/impl/AreasServiceImpl.java
@@ -12,6 +12,7 @@ import com.doumee.core.model.PageData; import com.doumee.core.model.PageWrap; import com.doumee.core.utils.PinYinUtil; import com.doumee.core.utils.geocode.MapUtil; import com.doumee.core.utils.Utils; import com.doumee.dao.business.AreasMapper; import com.doumee.dao.business.PricingRuleMapper; @@ -19,7 +20,9 @@ import com.doumee.dao.business.model.PricingRule; import com.doumee.service.business.AreasService; import com.github.yulichang.wrapper.MPJLambdaWrapper; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.checkerframework.checker.units.qual.A; import org.springframework.beans.BeanUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; @@ -35,6 +38,7 @@ * @author 江蹄蹄 * @date 2023/02/15 08:55 */ @Slf4j @Service public class AreasServiceImpl implements AreasService { public static List<Areas> ALL_AREA_LIST; @@ -71,6 +75,10 @@ areas.setCreateDate(new Date()); areasMapper.insert(areas); areas.setCode(areas.getId().toString()); // 城市级区划自动填充经纬度 if (Constants.equalsInteger(areas.getType(), Constants.ONE)) { areas.setInfo(geocodeCity(areas)); } areasMapper.updateById(areas); //刷新缓存数据 cacheData(); @@ -115,6 +123,14 @@ Areas update = new Areas(); update.setName(areas.getName()); update.setSortnum(areas.getSortnum()); // 城市级区划自动更新经纬度 Areas existing = areasMapper.selectById(areas.getId()); if (existing != null && Constants.equalsInteger(existing.getType(), Constants.ONE)) { String location = MapUtil.geocode(getParentName(existing.getParentId()) + areas.getName()); if (location != null) { update.setInfo(location); } } areasMapper.update(update,wrapper); //刷新缓存数据 cacheData(); @@ -598,4 +614,51 @@ areasMapper.updateById(update); } @Override public String fillCityLocation() { Areas query = new Areas(); query.setType(1); List<Areas> cities = areasMapper.selectList(new QueryWrapper<Areas>().lambda() .eq(Areas::getType, 1)); int success = 0, fail = 0; for (Areas city : cities) { if (StringUtils.isNotBlank(city.getInfo())) { continue; } String parentName = ""; if (city.getParentId() != null) { Areas parent = getById(city.getParentId()); if (parent != null) { parentName = parent.getName(); } } String address = parentName + city.getName(); String location = MapUtil.geocode(address); if (location != null) { city.setInfo(location); areasMapper.updateById(city); success++; log.info("城市经纬度填充成功: {} => {}", address, location); } else { fail++; log.warn("城市经纬度填充失败: {}", address); } try { Thread.sleep(200); } catch (InterruptedException ignored) {} } return "处理完成,成功: " + success + ",失败: " + fail + ",总计: " + cities.size(); } private String getParentName(Integer parentId) { if (parentId == null) { return ""; } Areas parent = getById(parentId); return parent != null ? parent.getName() : ""; } private String geocodeCity(Areas city) { String address = getParentName(city.getParentId()) + city.getName(); return MapUtil.geocode(address); } } server/services/src/main/java/com/doumee/service/business/impl/DriverInfoServiceImpl.java
@@ -226,6 +226,29 @@ if (Objects.isNull(driverInfo)) { throw new BusinessException(ResponseStatus.DATA_EMPTY); } // 查询审批人名称 if (driverInfo.getAuditUser() != null) { try { SystemUser auditUser = systemUserService.findById(driverInfo.getAuditUser()); if (auditUser != null) { driverInfo.setAuditUserName(auditUser.getRealname()); } } catch (Exception e) { // 审批人已删除等异常忽略 } } // 查询省市区信息 if (driverInfo.getAreaId() != null) { Areas district = areasBiz.resolveArea(driverInfo.getAreaId()); if (district != null) { driverInfo.setDistrictId(district.getId()); driverInfo.setDistrictName(district.getName()); driverInfo.setCityId(district.getCityId()); driverInfo.setCityName(district.getCityName()); driverInfo.setProvinceId(district.getProvinceId()); driverInfo.setProvinceName(district.getProvinceName()); } } return driverInfo; } @@ -977,6 +1000,18 @@ // 审批人已删除等异常忽略 } } // 查询省市区信息 if (driverInfo.getAreaId() != null) { Areas district = areasBiz.resolveArea(driverInfo.getAreaId()); if (district != null) { driverInfo.setDistrictId(district.getId()); driverInfo.setDistrictName(district.getName()); driverInfo.setCityId(district.getCityId()); driverInfo.setCityName(district.getCityName()); driverInfo.setProvinceId(district.getProvinceId()); driverInfo.setProvinceName(district.getProvinceName()); } } return driverInfo; } server/services/src/main/java/com/doumee/service/business/impl/InvoiceRecordServiceImpl.java
@@ -18,6 +18,9 @@ import com.doumee.dao.business.model.InvoiceRecord; import com.doumee.dao.business.model.Orders; import com.doumee.dao.dto.ApplyInvoiceDTO; import com.doumee.dao.dto.invoice.InvoiceA0001DTO; import com.doumee.dao.dto.invoice.InvoiceA0001ItemDTO; import com.doumee.dao.dto.invoice.InvoiceA0001Request; import com.doumee.dao.vo.InvoiceRecordSummaryVO; import com.doumee.service.business.InvoiceRecordService; import com.doumee.service.common.EmailService; @@ -206,6 +209,40 @@ record.setCreateTime(new Date()); invoiceRecordMapper.insert(record); InvoiceA0001Request invoiceA0001Request = new InvoiceA0001Request(); invoiceA0001Request.setAccess_token("");//请求token invoiceA0001Request.setServiceKey("ebi_InvoiceHandle_newBlueInvoice"); InvoiceA0001DTO invoiceA0001DTO = new InvoiceA0001DTO(); invoiceA0001DTO.setData_resources("API"); invoiceA0001DTO.setItype("026"); invoiceA0001DTO.setNsrsbh("");//销售方纳税人识别号 invoiceA0001DTO.setOrder_num("");//业务单据号;必须是唯一的 invoiceA0001DTO.setZsfs("0"); invoiceA0001DTO.setTspz("00"); invoiceA0001DTO.setXsf_yhzh("");//销售方开户行名称与银行账号 自贡市XX银行XX街支行 8888888888 invoiceA0001DTO.setXsf_mc("");//销售方名称 invoiceA0001DTO.setXsf_nsrsbh("");//销售方纳税人识别号 invoiceA0001DTO.setXsf_dzdh("");//销售方地址、电话 自贡市XX街6号悠悠大厦D8幢8单元8层 0830-66008888 invoiceA0001DTO.setGmf_mc(""); //购买方名称 invoiceA0001DTO.setKpr(""); //开票人 invoiceA0001DTO.setJshj("");//价税合计;单位:元(2位小数) 价税合计=合计金额(不含税)+合计税额 注意:不能使用商品的单价、数量、税率、税额来进行累加,最后四舍五入,只能是总合计金额+合计税额 invoiceA0001DTO.setHjje("");//合计金额 注意:不含税,单位:元(2位小数) invoiceA0001DTO.setHjse("");//合计税额单位:元(2位小数) List<InvoiceA0001ItemDTO> common_fpkj_xmxx = new ArrayList<>(); InvoiceA0001ItemDTO invoiceA0001ItemDTO = new InvoiceA0001ItemDTO(); invoiceA0001ItemDTO.setFphxz("0"); invoiceA0001ItemDTO.setXmmc("");//项目名称 invoiceA0001ItemDTO.setXmdj("");//项目单价 小数点后6位 注意:单价是含税单价,大于0的数字 invoiceA0001ItemDTO.setXmsl("1"); invoiceA0001ItemDTO.setXmje(""); invoiceA0001ItemDTO.setSe(""); invoiceA0001ItemDTO.setSl(""); common_fpkj_xmxx.add(invoiceA0001ItemDTO); invoiceA0001DTO.setCommon_fpkj_xmxx(common_fpkj_xmxx); invoiceA0001Request.setData(invoiceA0001DTO); // 更新订单发票状态为申请中 order.setInvoiceStatus(Constants.TWO); order.setUpdateTime(new Date()); server/services/src/main/java/com/doumee/service/business/impl/OrdersServiceImpl.java
@@ -236,10 +236,12 @@ .selectAll(Orders.class) .selectAs(Category::getDetail, Orders::getOrderLevel) .select("s1.name", Orders::getDepositShopName) .leftJoin(Category.class, Category::getId, Orders::getGoodType) .select("o2.code", Orders::getRelationOrderCode) .leftJoin(Category.class, Category::getId, Orders::getGoodLevel) .leftJoin(DriverInfo.class, DriverInfo::getId, Orders::getAcceptDriver) .leftJoin("shop_info s1 on s1.id = t.DEPOSIT_SHOP_ID") .leftJoin("shop_info s2 on s2.id = t.TAKE_SHOP_ID") ; .leftJoin("shop_info s2 on s2.id = t.TAKE_SHOP_ID") .leftJoin("orders o2 on o2.id = t.RELATION_ORDER_ID") ; Utils.MP.blankToNull(pageWrap.getModel()); queryWrapper.eq(pageWrap.getModel().getDeleted() != null, Orders::getDeleted, pageWrap.getModel().getDeleted()); @@ -348,7 +350,7 @@ } /** * 计算就地存取预估费用 * 计算就地寄存预估费用 * * 计算规则: * 1. 根据城市+物品类型 查询 pricing_rule(type=0),fieldA=categoryId, fieldB=单价(分/天) @@ -357,7 +359,7 @@ * 4. 保价费用 = 报价金额 × 保价费率(字典 INSURANCE_RATE),元转分 * 5. 总价格 = 物品价格 + 保价费用 * * @param dto 就地存取计价请求参数 * @param dto 就地寄存计价请求参数 * @return 价格计算结果 */ @Override @@ -447,7 +449,7 @@ } /** * 计算异地存取预估费用 * 计算同城寄送预估费用 * * 计算规则: * 1. 调用腾讯地图API计算寄件点与取件点的驾车距离(米→公里) @@ -462,7 +464,7 @@ * 7. 加急费用 = 物品价格 × 加急系数(字典 URGENT_COEFFICIENT) * 8. 总价格 = 物品价格 + 保价费用 + 加急费用 * * @param dto 异地存取计价请求参数 * @param dto 同城寄送计价请求参数 * @return 价格计算结果 */ @Override @@ -499,7 +501,7 @@ ruleMap.put(r.getFieldA(), r); } // 查询就地存取计价规则 pricing_rule type=0,用于获取 locallyPrice // 查询就地寄存计价规则 pricing_rule type=0,用于获取 locallyPrice List<PricingRule> localRules = pricingRuleMapper.selectList(new QueryWrapper<PricingRule>().lambda() .eq(PricingRule::getDeleted, Constants.ZERO) .eq(PricingRule::getType, Constants.ZERO) @@ -553,7 +555,7 @@ long subtotal = unitPrice * item.getQuantity(); // 就地存取单价 // 就地寄存单价 PricingRule localRule = localRuleMap.get(String.valueOf(item.getCategoryId())); Long locallyPrice = localRule != null ? Long.parseLong(localRule.getFieldB()) : null; @@ -812,7 +814,7 @@ throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "请选择取件店铺或输入自选取件地址"); } } else { // 就地存取:取件门店同寄件门店 // 就地寄存:取件门店同寄件门店 takeShop = depositShop; } @@ -862,6 +864,7 @@ orders.setPayStatus(Constants.ZERO); // 未支付 orders.setCommentStatus(Constants.ZERO); // 未评价 orders.setSettlementStatus(Constants.ZERO); // 未结算 orders.setExceptionStatus(Constants.ZERO); // 非异常 orders.setDeleted(Constants.ZERO); orders.setCreateTime(now); orders.setUpdateTime(now); @@ -1283,7 +1286,7 @@ vo.setCode(order.getCode()); vo.setPayAmountYuan(order.getPayAmount() != null ? Constants.getFormatMoney(order.getPayAmount()) : 0); vo.setType(order.getType()); vo.setTypeDesc(order.getType() != null && order.getType() == Constants.ONE ? "异地存取" : "就地存取"); vo.setTypeDesc(order.getType() != null && order.getType() == Constants.ONE ? "同城寄送" : "就地寄存"); vo.setDetailList(buildDetailList(id)); return vo; @@ -1302,9 +1305,9 @@ throw new BusinessException(ResponseStatus.DATA_EMPTY); } // 前置条件校验:异地存取 + 已寄存 // 前置条件校验:同城寄送 + 已寄存 if (!Constants.ONE.equals(order.getType())) { throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "仅支持异地存取订单派单"); throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "仅支持同城寄送订单派单"); } if (!Integer.valueOf(Constants.OrderStatus.deposited.getStatus()).equals(order.getStatus())) { throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "仅已寄存状态订单可派单"); @@ -1534,7 +1537,7 @@ * * @param orders 订单实体(需要 totalAmount、cityId 已设置) * @param depositShop 寄件门店(需要 companyType) * @param takeShop 取件门店(需要 companyType,就地存取时与 depositShop 相同) * @param takeShop 取件门店(需要 companyType,就地寄存时与 depositShop 相同) */ private void calculateAndSetFeeAllocation(Orders orders, ShopInfo depositShop, ShopInfo takeShop) { Long totalAmount = orders.getTotalAmount() != null ? orders.getTotalAmount() : 0L; @@ -1746,8 +1749,13 @@ // 评价状态 vo.setCommentStatus(o.getCommentStatus()); String dateStr = new SimpleDateFormat("dd").format(o.getPayTime() != null ? o.getPayTime() : new Date()); String autoNumStr = String.format("%03d", o.getAutoNum() != null ? o.getAutoNum() : 0); String sort = o.getDepositShopId() + "-" + dateStr + "-" + autoNumStr; //序号 vo.setSortnum(Constants.formatIntegerNum(o.getDepositShopId())+"-"+o.getId()); vo.setSortnum(sort); if(o.getTakeShopId()!=null){ vo.setSortnumTake(Constants.formatIntegerNum(o.getTakeShopId())+"-"+o.getId()); } @@ -2164,6 +2172,10 @@ throw new BusinessException(ResponseStatus.DATA_EMPTY); } if (Constants.equalsInteger(order.getExceptionStatus(), Constants.ONE)) { throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "异常订单无法取消"); } Integer status = order.getStatus(); if (status == null) { throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "订单状态异常"); @@ -2199,8 +2211,6 @@ "orderNo", order.getCode()); // 短信通知会员:订单已取消 Member cancelMember2 = memberMapper.selectById(memberId); sendSmsNotify(cancelMember2 != null ? cancelMember2.getTelephone() : null, Constants.SmsNotify.MEMBER_CANCELLED, "orderNo", order.getCode()); // 调用微信退款V3,全额退款 String outRefundNo = ID.nextGUID(); @@ -2238,6 +2248,8 @@ throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "退款失败,请联系客服处理"); } ordersRefundMapper.insert(refund); sendSmsNotify(cancelMember2 != null ? cancelMember2.getTelephone() : null, Constants.SmsNotify.MEMBER_CANCELLED, "orderNo", order.getCode()); restoreCoupon(order); return; } @@ -2406,9 +2418,10 @@ if (Constants.equalsInteger(order.getManualRefund(), Constants.ONE)) { throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "该订单已手动退款"); } // 异常订单不允许手动退款 if (Constants.equalsInteger(order.getExceptionStatus(), Constants.ONE)) { throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "异常订单不支持手动退款"); // 就地寄存异常订单不允许手动退款 if (Constants.equalsInteger(order.getExceptionStatus(), Constants.ONE) && Constants.equalsInteger(order.getType(), Constants.ZERO)) { throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "就地寄存异常订单不支持手动退款"); } // 2. 校验退款金额 @@ -2851,13 +2864,27 @@ if (otherOrders.getOrderId() != null) { Orders order = ordersMapper.selectById(otherOrders.getOrderId()); if (order != null) { order.setOverdueStatus(Constants.TWO); // 2=已支付 // 总金额 = 原金额 + 逾期费用 Long overdueFee = otherOrders.getPayAccount() != null ? otherOrders.getPayAccount() : 0L; long newTotal = (order.getTotalAmount() != null ? order.getTotalAmount() : 0L) + overdueFee; // 异常就地寄存订单:同时更新主订单实际逾期费用 boolean isAbnormal = Constants.equalsInteger(order.getExceptionStatus(), Constants.ONE) && Constants.equalsInteger(order.getType(), Constants.ZERO); if(isAbnormal){ long shopException = isAbnormal ? (order.getShopCompensationAmount() != null ? order.getShopCompensationAmount() : 0L) : 0L; long driverException = isAbnormal ? (order.getExceptionFee() != null ? order.getExceptionFee() : 0L) : 0L; long actualOverdueFee = isAbnormal ? (overdueFee - shopException - driverException) : 0L; if(actualOverdueFee!=order.getOverdueAmount()){ order.setOverdueAmount(actualOverdueFee); } } order.setOverdueStatus(Constants.TWO); // 2=已支付 order.setTotalAmount(newTotal); order.setUpdateTime(now); ordersMapper.updateById(order); // 重算三方收益 calculateAndSaveOrderFees(order.getId()); } @@ -3348,6 +3375,37 @@ } // 寄存成功赠送优惠券 giftOrderCoupon(order.getMemberId()); // 异常订单寄存核销:标记原订单完成 if (Constants.equalsInteger(order.getExceptionStatus(), Constants.ONE) && order.getRelationOrderId() != null) { Orders originalOrder = ordersMapper.selectById(order.getRelationOrderId()); if (originalOrder != null) { originalOrder.setStatus(Constants.OrderStatus.finished.getStatus()); originalOrder.setInvoiceStatus(Constants.ONE); originalOrder.setSettlementStatus(Constants.ZERO); originalOrder.setFinishTime(now); originalOrder.setUpdateTime(now); ordersMapper.updateById(originalOrder); // 触发原订单收益计算 calculateAndSaveOrderFees(originalOrder.getId()); generateRevenueRecords(originalOrder.getId()); // 记录原订单日志 saveShopVerifyLog(originalOrder, Constants.OrderLogType.shopTake, "异常订单核销,原订单完成", remark, shopId); // 通知会员:订单已完成 sendOrderNotice(originalOrder.getMemberId(), Constants.MemberOrderNotify.FINISHED, originalOrder.getId(), "orderNo", originalOrder.getCode()); // 通知存件门店和取件门店 String settleDays = operationConfigBiz.getConfig().getSettlementDate(); notifyBothShops(originalOrder, Constants.ShopOrderNotify.FINISHED, "orderNo", originalOrder.getCode(), "settleDays", settleDays != null ? settleDays : "7"); // 通知司机:订单已完成 if (originalOrder.getAcceptDriver() != null) { sendDriverNotice(originalOrder.getAcceptDriver(), Constants.DriverOrderNotify.FINISHED, originalOrder.getId(), "orderNo", originalOrder.getCode(), "settleDays", settleDays != null ? settleDays : "7"); } } } } else if (Constants.equalsInteger(status, Constants.OrderStatus.arrived.getStatus())) { // 异地寄存 + 无取件门店 → 无法核销(客户自取,无门店操作) if (Constants.equalsInteger(order.getType(), Constants.ONE) && order.getTakeShopId() == null) { @@ -3516,30 +3574,7 @@ sendOrderNotice(order.getMemberId(), Constants.MemberOrderNotify.WAIT_PICKUP_REMIND, order.getId(), "orderNo", order.getCode(), "shopName", shopName); } // 异常订单寄存核销:标记原订单完成 if (Constants.equalsInteger(order.getExceptionStatus(), Constants.ONE) && order.getRelationOrderId() != null) { Orders originalOrder = ordersMapper.selectById(order.getRelationOrderId()); if (originalOrder != null) { originalOrder.setStatus(Constants.OrderStatus.finished.getStatus()); originalOrder.setInvoiceStatus(Constants.ONE); originalOrder.setFinishTime(now); originalOrder.setUpdateTime(now); ordersMapper.updateById(originalOrder); // 触发原订单收益计算 calculateAndSaveOrderFees(originalOrder.getId()); generateRevenueRecords(originalOrder.getId()); // 通知会员:订单已完成 sendOrderNotice(originalOrder.getMemberId(), Constants.MemberOrderNotify.FINISHED, originalOrder.getId(), "orderNo", originalOrder.getCode()); // 通知司机:订单已完成 if (originalOrder.getAcceptDriver() != null) { String settleDays = operationConfigBiz.getConfig().getSettlementDate(); sendDriverNotice(originalOrder.getAcceptDriver(), Constants.DriverOrderNotify.FINISHED, originalOrder.getId(), "orderNo", originalOrder.getCode(), "settleDays", settleDays != null ? settleDays : "7"); } } } } else if (Constants.equalsInteger(status, Constants.OrderStatus.arrived.getStatus())) { // 异地寄存 + 无取件门店 → 无法核销(客户自取,无门店操作) if (Constants.equalsInteger(order.getType(), Constants.ONE) && order.getTakeShopId() == null) { @@ -3767,13 +3802,17 @@ } Long totalAmount = order.getTotalAmount() != null ? order.getTotalAmount() : 0L; Long shopCompensationAmount = order.getShopCompensationAmount() != null ? order.getShopCompensationAmount() : 0L; Long exceptionFee = order.getExceptionFee() != null ? order.getExceptionFee() : 0L; // 分成基数 = 总金额 - 门店异常金额 - 司机异常金额 Long feeBase = totalAmount - shopCompensationAmount - exceptionFee; // 费率(为空时默认0) BigDecimal depositRate = order.getDepositShopFeeRata() != null ? order.getDepositShopFeeRata() : BigDecimal.ZERO; BigDecimal takeRate = order.getTakeShopFeeRata() != null ? order.getTakeShopFeeRata() : BigDecimal.ZERO; BigDecimal driverRate = order.getDriverFeeRata() != null ? order.getDriverFeeRata() : BigDecimal.ZERO; //存件门店收益 Long depositShopFee = new BigDecimal(totalAmount) Long depositShopFee = new BigDecimal(feeBase) .multiply(depositRate) .setScale(0, RoundingMode.HALF_UP) .longValue(); @@ -3783,14 +3822,14 @@ if (Constants.equalsInteger(order.getType(), Constants.ONE)) { // 异地寄存:存件门店 + 司机 driverFee = new BigDecimal(totalAmount) driverFee = new BigDecimal(feeBase) .multiply(driverRate) .setScale(0, RoundingMode.HALF_UP) .longValue(); // 异地寄存且有取件门店:加上取件门店收益 if (order.getTakeShopId() != null) { takeShopFee = new BigDecimal(totalAmount) takeShopFee = new BigDecimal(feeBase) .multiply(takeRate) .setScale(0, RoundingMode.HALF_UP) .longValue(); @@ -3828,6 +3867,29 @@ } } // 异常订单:存件门店异常补偿收益(单独一条记录,type=5) if (Constants.equalsInteger(order.getExceptionStatus(), Constants.ONE) && order.getShopCompensationAmount() != null && order.getShopCompensationAmount() > 0 && order.getDepositShopId() != null) { ShopInfo depositShop = shopInfoMapper.selectById(order.getDepositShopId()); if (depositShop != null && depositShop.getId() != null) { Revenue shopExRevenue = new Revenue(); shopExRevenue.setMemberId(depositShop.getId()); shopExRevenue.setMemberType(Constants.TWO); // 2=门店 shopExRevenue.setType(5); // 5=异常金额 shopExRevenue.setOptType(Constants.ONE); // 1=收入 shopExRevenue.setAmount(order.getShopCompensationAmount()); shopExRevenue.setVaildStatus(Constants.ZERO); shopExRevenue.setObjId(orderId); shopExRevenue.setObjType(Constants.ZERO); shopExRevenue.setStatus(Constants.ZERO); shopExRevenue.setOrderNo(order.getCode()); shopExRevenue.setDeleted(Constants.ZERO); shopExRevenue.setCreateTime(now); revenueMapper.insert(shopExRevenue); } } // 取件门店收益(异地寄存且有取件门店) if (takeShopFee > 0 && order.getTakeShopId() != null) { ShopInfo takeShop = shopInfoMapper.selectById(order.getTakeShopId()); @@ -3846,27 +3908,33 @@ } } // 异常订单:司机异常补偿(异地 + 异常标记 + 有异常补偿金额) // 异常订单:司机异常补偿(异地 + 异常标记,从关联异常子订单获取exceptionFee) if (Constants.equalsInteger(order.getType(), Constants.ONE) && Constants.equalsInteger(order.getExceptionStatus(), Constants.ONE) && order.getExceptionFee() != null && order.getExceptionFee() > 0 && order.getAcceptDriver() != null) { DriverInfo driver = driverInfoMapper.selectById(order.getAcceptDriver()); if (driver != null && driver.getMemberId() != null) { Revenue exRevenue = new Revenue(); exRevenue.setMemberId(driver.getMemberId()); exRevenue.setMemberType(Constants.ONE); // 1=司机 exRevenue.setType(5); // 5=异常金额 exRevenue.setOptType(Constants.ONE); // 1=收入 exRevenue.setAmount(order.getExceptionFee()); exRevenue.setVaildStatus(Constants.ZERO); exRevenue.setObjId(orderId); exRevenue.setObjType(Constants.ZERO); exRevenue.setStatus(Constants.ZERO); exRevenue.setOrderNo(order.getCode()); exRevenue.setDeleted(Constants.ZERO); exRevenue.setCreateTime(now); revenueMapper.insert(exRevenue); Orders childOrder = ordersMapper.selectOne(new QueryWrapper<Orders>().lambda() .eq(Orders::getRelationOrderId, orderId) .eq(Orders::getExceptionStatus, Constants.ONE) .eq(Orders::getDeleted, Constants.ZERO) .last("limit 1")); if (childOrder != null && childOrder.getExceptionFee() != null && childOrder.getExceptionFee() > 0) { DriverInfo driver = driverInfoMapper.selectById(order.getAcceptDriver()); if (driver != null && driver.getMemberId() != null) { Revenue exRevenue = new Revenue(); exRevenue.setMemberId(driver.getMemberId()); exRevenue.setMemberType(Constants.ONE); // 1=司机 exRevenue.setType(5); // 5=异常金额 exRevenue.setOptType(Constants.ONE); // 1=收入 exRevenue.setAmount(childOrder.getExceptionFee()); exRevenue.setVaildStatus(Constants.ZERO); exRevenue.setObjId(orderId); exRevenue.setObjType(Constants.ZERO); exRevenue.setStatus(Constants.ZERO); exRevenue.setOrderNo(order.getCode()); exRevenue.setDeleted(Constants.ZERO); exRevenue.setCreateTime(now); revenueMapper.insert(exRevenue); } } } @@ -4100,8 +4168,7 @@ if (Constants.equalsInteger(order.getExceptionStatus(), Constants.ONE) && order.getRelationOrderId() != null) { Orders originalOrder = ordersMapper.selectById(order.getRelationOrderId()); long driverExceptionFee = (originalOrder != null && originalOrder.getExceptionFee() != null) ? originalOrder.getExceptionFee() : 0L; long driverExceptionFee = order.getExceptionFee() != null ? order.getExceptionFee() : 0L; long shopExceptionFee = order.getShopCompensationAmount() != null ? order.getShopCompensationAmount() : 0L; long totalExceptionFee = driverExceptionFee + shopExceptionFee; @@ -4115,13 +4182,14 @@ overdueFee = totalExceptionFee; overdueDays = totalExceptionFee > 0 ? 1 : 0; } else { // 非当天取件:正常逾期计算 + 司机异常费用(不含门店异常费用) // 非当天取件:正常逾期计算 + 司机异常费用(不含门店异常费用),门店异常金额清零 OverdueFeeVO normalOverdue = calculateOverdueFeeInternal(order, details); long normalFee = (normalOverdue != null && normalOverdue.getOverdueFee() != null) ? normalOverdue.getOverdueFee() : 0L; overdueFee = normalFee + driverExceptionFee; overdueDays = (normalOverdue != null && normalOverdue.getOverdueDays() != null) ? normalOverdue.getOverdueDays() : 0; order.setShopCompensationAmount(0L); } order.setConfirmArriveTime(now); @@ -5108,14 +5176,14 @@ targetLat = order.getDepositLat(); targetLgt = order.getDepositLgt(); } else if (Constants.equalsInteger(order.getStatus(), Constants.OrderStatus.arrived.getStatus())&&Constants.equalsInteger(order.getType(), Constants.ZERO)) { // 就地存取 → 对比存件门店 // 就地寄存 → 对比存件门店 if (!Constants.equalsInteger(order.getDepositShopId(), userId)) { throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "无权操作该订单"); } targetLat = order.getDepositLat(); targetLgt = order.getDepositLgt(); } else if ((Constants.equalsInteger(order.getStatus(), Constants.OrderStatus.delivering.getStatus())||Constants.equalsInteger(order.getStatus(), Constants.OrderStatus.arrived.getStatus()))&&Constants.equalsInteger(order.getType(), Constants.ONE)) { // 异地存取 → 对比取件门店 // 同城寄送 → 对比取件门店 if (!Constants.equalsInteger(order.getTakeShopId(), userId)) { throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "无权操作该订单"); } @@ -5181,7 +5249,7 @@ Date now = new Date(); // ========== B. 创建新订单(就地存取) ========== // ========== B. 创建新订单(就地寄存) ========== String orderCode = "JC" + new java.text.SimpleDateFormat("yyyyMMddHHmmss").format(now) + String.format("%04d", new java.util.Random().nextInt(10000)); String orderTradeNo = generateOrderTradeNo(); @@ -5222,7 +5290,7 @@ } } // 存件门店分成占比(就地存取) // 存件门店分成占比(就地寄存) Integer cityId = Integer.valueOf(original.getCityId()); boolean isCompany = Constants.equalsInteger(newShop.getCompanyType(), Constants.ONE); int fallbackFieldA = isCompany ? Constants.FIVE : Constants.SIX; @@ -5232,7 +5300,7 @@ newOrder.setCode(orderCode); newOrder.setOutTradeNo(orderTradeNo); newOrder.setMemberId(original.getMemberId()); newOrder.setType(Constants.ZERO); // 就地存取 newOrder.setType(Constants.ZERO); // 就地寄存 newOrder.setCityId(original.getCityId()); newOrder.setStatus(Constants.ONE); // 待寄存 newOrder.setPayStatus(Constants.ONE); // 已支付 @@ -5283,8 +5351,8 @@ newOrder.setDeclaredAmount(0L); newOrder.setDeclaredFee(0L); newOrder.setPrice(price); newOrder.setBasicAmount(basicAmount); newOrder.setEstimatedAmount(basicAmount); newOrder.setBasicAmount(0L);//); newOrder.setEstimatedAmount(0L);//basicAmount); newOrder.setTotalAmount(0L); newOrder.setPayAmount(0L); newOrder.setManualRefund(Constants.ZERO); @@ -5299,6 +5367,8 @@ // 门店补偿金额 newOrder.setShopCompensationAmount(dto.getShopCompensation()); // 司机异常补偿金额 newOrder.setExceptionFee(dto.getDriverCompensation()); newOrder.setRemark(dto.getRemark()); newOrder.setPlatformSmsNotified(Constants.ZERO); @@ -5355,7 +5425,6 @@ // ========== E. 更新原订单 ========== ordersMapper.update(new UpdateWrapper<Orders>().lambda() .set(Orders::getExceptionStatus, Constants.ONE) .set(Orders::getExceptionFee, dto.getDriverCompensation()) .set(Orders::getUpdateTime, now) .eq(Orders::getId, original.getId())); server/services/src/main/java/com/doumee/service/business/impl/ShopInfoServiceImpl.java
@@ -1801,15 +1801,15 @@ private List<String> validateCityPricingRules(Integer cityId) { List<String> errors = new ArrayList<>(); // type=0 就地存取规则:至少1条,fieldB不为空 // type=0 就地寄存规则:至少1条,fieldB不为空 List<PricingRule> type0 = pricingRuleMapper.selectList(new QueryWrapper<PricingRule>().lambda() .eq(PricingRule::getDeleted, Constants.ZERO) .eq(PricingRule::getType, Constants.ZERO) .eq(PricingRule::getCityId, cityId)); if (type0.isEmpty()) { errors.add("缺少就地存取规则"); errors.add("缺少就地寄存规则"); } else if (type0.stream().allMatch(r -> StringUtils.isBlank(r.getFieldB()))) { errors.add("就地存取规则未配置收费单价"); errors.add("就地寄存规则未配置收费单价"); } // type=1 异地寄送规则:至少1条,fieldB/C/D/E不为空 server/services/src/main/java/com/doumee/service/business/impl/WithdrawalOrdersServiceImpl.java
@@ -151,7 +151,7 @@ // 司机端:关联 DriverInfo 表 queryWrapper.selectAs(DriverInfo::getName, WithdrawalOrders::getMemberName) .selectAs(DriverInfo::getTelephone, WithdrawalOrders::getMemberTelephone) .leftJoin(DriverInfo.class, DriverInfo::getMemberId, WithdrawalOrders::getMemberId); .leftJoin(DriverInfo.class, DriverInfo::getId, WithdrawalOrders::getMemberId); } else { // 店铺端 / 不筛选:关联 ShopInfo 表 queryWrapper.selectAs(ShopInfo::getName, WithdrawalOrders::getShopName) server/web/src/main/java/com/doumee/api/web/ConfigApi.java
@@ -91,6 +91,12 @@ return ApiResponse.success("门店初始化 " + shopCount + " 条,司机初始化 " + driverCount + " 条"); } @ApiOperation("一次性:为所有城市级别区划填充经纬度到info字段") @PostMapping("/fillCityLocation") public ApiResponse<String> fillCityLocation() { return ApiResponse.success(areasService.fillCityLocation()); } @ApiOperation("全部区划树形查询") @PostMapping("/treeList") public ApiResponse<List<Areas>> treeList (@RequestBody AreasDto pageWrap) { @@ -161,7 +167,7 @@ } @LoginRequired @ApiOperation(value = "计算就地存取预估费用", notes = "根据城市、天数、物品类型和数量计算就地存取预估费用") @ApiOperation(value = "计算就地寄存预估费用", notes = "根据城市、天数、物品类型和数量计算就地寄存预估费用") @PostMapping("/calculateLocalPrice") public ApiResponse<PriceCalculateVO> calculateLocalPrice(@RequestBody @Valid CalculateLocalPriceDTO dto) { dto.setMemberId(getMemberId()); @@ -169,7 +175,7 @@ } @LoginRequired @ApiOperation(value = "计算异地存取预估费用", notes = "根据距离、物品类型和数量计算异地存取预估费用") @ApiOperation(value = "计算同城寄送预估费用", notes = "根据距离、物品类型和数量计算同城寄送预估费用") @PostMapping("/calculateRemotePrice") public ApiResponse<PriceCalculateVO> calculateRemotePrice(@RequestBody @Valid CalculateRemotePriceDTO dto) { dto.setMemberId(getMemberId());