From 440f86d3fb52f7f587073c8561fe487178a1fe75 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=A2=81=E5=AE=87=E5=A5=87?= Date: Tue, 15 Apr 2025 22:35:57 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E8=AE=A2=E5=8D=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/common/CommonController.java | 9 +- .../web/controller/xkt/ExpressController.java | 6 + .../src/main/resources/application.yml | 25 ++ .../ruoyi/common/core/redis/RedisCache.java | 5 + .../config/properties/OSSProperties.java | 2 + .../xkt/dto/express/zt/CreateOrderReqDTO.java | 271 ++++++++++++++++++ .../com/ruoyi/xkt/enums/EOrderAction.java | 1 + .../manager/impl/ZtExpressManagerImpl.java | 15 + .../ruoyi/xkt/service/IStoreOrderService.java | 17 +- .../service/impl/StoreOrderServiceImpl.java | 180 +++++++++++- 10 files changed, 508 insertions(+), 23 deletions(-) create mode 100644 xkt/src/main/java/com/ruoyi/xkt/dto/express/zt/CreateOrderReqDTO.java diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/common/CommonController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/common/CommonController.java index d8963ec73..61de924e5 100644 --- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/common/CommonController.java +++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/common/CommonController.java @@ -37,11 +37,6 @@ public class CommonController { private OSSProperties ossProperties; @Autowired private RedisCache redisCache; - /** - * STS缓存时间(秒) - */ - @Value("${sts_cache_duration:1800}") - private Integer stsCacheDuration; @ApiOperation("获取OSS临时访问凭证") @GetMapping("/oss/getCredentials") @@ -63,11 +58,11 @@ public class CommonController { vo.setBucketName(ossProperties.getBucketName()); vo.setRegionId(ossProperties.getRegionId()); vo.setEndPoint(ossProperties.getEndPoint()); - vo.setExpiredDuration(ossProperties.getExpiredDuration() - stsCacheDuration); + vo.setExpiredDuration(ossProperties.getExpiredDuration() - ossProperties.getStsCacheDuration()); vo.setHttpsFlag(ossProperties.isHttps()); //缓存 redisCache.setCacheObject(CacheConstants.USER_STS_KEY + currentUserId, JSONUtil.toJsonStr(vo), - stsCacheDuration, TimeUnit.SECONDS); + ossProperties.getStsCacheDuration(), TimeUnit.SECONDS); return R.ok(vo); } diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/xkt/ExpressController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/xkt/ExpressController.java index b33bfb927..081bd2424 100644 --- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/xkt/ExpressController.java +++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/xkt/ExpressController.java @@ -5,6 +5,8 @@ import com.ruoyi.common.core.controller.XktBaseController; import com.ruoyi.common.core.domain.R; import com.ruoyi.web.controller.xkt.vo.express.ExpressRegionTreeNodeVO; import com.ruoyi.xkt.dto.express.ExpressRegionTreeNodeDTO; +import com.ruoyi.xkt.manager.ExpressManager; +import com.ruoyi.xkt.manager.impl.ZtExpressManagerImpl; import com.ruoyi.xkt.service.IExpressService; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; @@ -27,6 +29,10 @@ public class ExpressController extends XktBaseController { @Autowired private IExpressService expressService; + @Autowired + private List expressManagers; + @Autowired + private ZtExpressManagerImpl ztExpressManager; @PreAuthorize("@ss.hasPermi('system:express:query')") @ApiOperation("获取行政规划树") diff --git a/ruoyi-admin/src/main/resources/application.yml b/ruoyi-admin/src/main/resources/application.yml index f67d0b761..13674db96 100644 --- a/ruoyi-admin/src/main/resources/application.yml +++ b/ruoyi-admin/src/main/resources/application.yml @@ -22,6 +22,7 @@ oss: roleArn: acs:ram::1919425406190533:role/sts-role expiredDuration: 3600 tempDir: E:/temp/ + stsCacheDuration: 1800 es: #多个用","分割 hosts: 49.234.41.39:9222 @@ -161,3 +162,27 @@ xss: excludes: /system/notice # 匹配链接 urlPatterns: /system/*,/monitor/*,/tool/* + +# 物流配置 +express: + default: + province: 510000 + city: 510100 + county: 510114 + +# 中通配置 +zt: + appKey: 95dc4ecf72fce1a2fbe79 + appSecret: 694ea7e3ea89e3b6aa21aea1a0285d25 + gatewayUrl: https://japi-test.zto.com/ + +# 支付宝配置 +alipay: + appId: 9021000144616672 + privateKey: MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC3x52ARikELwpOPvPcpY9jj7aEWIPivfBwkf3YRyUKnM7L6mOTxD1v3b7QLcL1+l0QmvOPSGgt2O3Qbjtvq+5ih4T32TlAzHGe8VqGVqrEv7ANQicsXz600ze5LdxCDRgBZWhO/GroGJKfenHf7K+arN4KXWWmHyZHCYD5z85TEvZZoA9e9MTMskXeDS8+fwP6McuNf4fR07kVuzblks+wWm1PsWfxFM7qNwSYKXbmEoyDe7+M9vBr7cwuj2OB3PEtj/FZjKMxVnFyVm61KiFAGUf3oUqWmPASTPDkFboRCS/njv980hk3sPba/qMDfMEpjoMZrcLBVzoj747oEi/DAgMBAAECggEAcVoXlRSxG7l/278MXl1nUXtEkeCeh+2rLWN+dDV9bUxGaJOLE4sIccUNeg2foGPpnuJTs15vk0endtVmp3weLntz0gMTQxpWQjiPIyi1b2Djz2msC7w7SwCz7+2PWtYEpmfLrFwX/Eubs+2r6vdrYDWbRj1RAuNXkp0UBgDcO3P9AFeGln5gUWxni4biN6B9sGGdsSwcm1A9biBPRsH2zMSVVWkhLVq+S73smm2Sh7WTIVEyeAuWEDeMs5oI2jQjPHMlUKmWW6JZ3uD5xbRm3Nkvve/nvfJ4ZXx58ABTI9EWzcBlEuLYef4T+P9q4KHZQljpJ4UliIxUVIDSk3GNMQKBgQDevjYnLW2FBNDYQvPf6FkD2iNzKFe80cQYR0+/jiSBgkmtQhXZgyJ2ZqQ5t20MjgLpeY0WJL2twBlFcYGico6Vnv+JMiJDtIjTu1UozAqV2VPeJ34nX34nqJptGwehiPXJupAiulAWtvTqsiYWlFHsr3dMtj6z07M+gDV8PU7P/QKBgQDTOCGgdrS3XYD680eH9vGKbH1DpIOMr3JokLk6kv4yui9Jxk5DMCxcJWkEQRnCrw2UYM8PfX17FqXrwhccmR9hskSmmbLONYzk4SDB73fM2nPqBw+VLO6jbWctylUsGaYfVxDOLDWPQkktKUsHK8pQHLNQ4jwlP5SGQUoIM/OqvwKBgHfRrmPIxh9GBeovqeyKmke+Mk+iJgBGfsvooHeUyQJ5yZRP9lz5c7JpaHI7v4d/ZQWfA0wkG3y5115JvshaA2VtEF0HAPOWy/vJy/eUOyV8sObSK8SWU9CVm+yRG7vDZyRLHXnw62AsrvcJOf/vbVp60RwM9RHbEZLPePYKLLkpAoGADPMaDK56ceuHptsXfZyEPopcO7NwZUW0a/jDgnXUo+OKVqmTzsa7UYLxp1MeczMsT/aHe1mkQdGnpoalyBkTNXgqgVRXBBGAa9/plDpMTADwrl50dB7nGpnwg3wuMJ/58V3zJ9DKD9huiBhKA0yKANNhownbyiTVxE1oboxQ2h0CgYEAkV4hjGe4t6mu5rhqvuIZkDskjuSOwO0dZsGXBZ/sOZusKNmskxeNZht4BajnATN4EaPg265k8ytWnOEQH041J8Wac1M+jAQQp6D1nkQWZZlrclTu7xvM+p6ypVtqNFTseIQtEhtyPw+fcsYrXM4u8LHpGlAzlwQ30lFg+K/Q++Y= + alipayPublicKey: MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAkiTTeQLIkyVHnYiNmRKEtsdlwKftUySN1SLkrhn6CgmHl5ovjPeYteweZEZmsf2kt6wRnaLkODVP7xUQiRVC2cu6StdJyvDzyiYI00u72PvSOvaWHcpzgKqTFpGiQseJQlHnI8U3ob4PxfJylBy8RDQHG9fZwNY1WOCsnSb3m2ufV1EQIjndzTq13yQE6jCz639rO8atlAG3PtJW/QRiGUzyGaOuKsS4HRzPbbpmVtsXoN76+x+WLWkeqlTBEu35X4Hdbkf1C36wp3b68sI5fVyLksF6elRv/It4aUzjXSXbO/Dx+zvMIN01FgwaFV6nLh++k3qlmo87p4I+hvsGiQIDAQAB + notifyUrl: + returnUrl: + signType: RSA2 + charset: UTF-8 + gatewayUrl: https://openapi-sandbox.dl.alipaydev.com/gateway.do diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/core/redis/RedisCache.java b/ruoyi-common/src/main/java/com/ruoyi/common/core/redis/RedisCache.java index d0a6de49b..1f6835da0 100644 --- a/ruoyi-common/src/main/java/com/ruoyi/common/core/redis/RedisCache.java +++ b/ruoyi-common/src/main/java/com/ruoyi/common/core/redis/RedisCache.java @@ -49,6 +49,11 @@ public class RedisCache redisTemplate.opsForValue().set(key, value, timeout, timeUnit); } + public void setCacheObject(final String key, final T value, final Long timeout, final TimeUnit timeUnit) + { + redisTemplate.opsForValue().set(key, value, timeout, timeUnit); + } + /** * 设置有效时间 * diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/config/properties/OSSProperties.java b/ruoyi-framework/src/main/java/com/ruoyi/framework/config/properties/OSSProperties.java index ae59eec9a..a07d84a12 100644 --- a/ruoyi-framework/src/main/java/com/ruoyi/framework/config/properties/OSSProperties.java +++ b/ruoyi-framework/src/main/java/com/ruoyi/framework/config/properties/OSSProperties.java @@ -28,4 +28,6 @@ public class OSSProperties { private Long expiredDuration; private String tempDir; + + private Long stsCacheDuration; } diff --git a/xkt/src/main/java/com/ruoyi/xkt/dto/express/zt/CreateOrderReqDTO.java b/xkt/src/main/java/com/ruoyi/xkt/dto/express/zt/CreateOrderReqDTO.java new file mode 100644 index 000000000..3c6e12fc4 --- /dev/null +++ b/xkt/src/main/java/com/ruoyi/xkt/dto/express/zt/CreateOrderReqDTO.java @@ -0,0 +1,271 @@ +package com.ruoyi.xkt.dto.express.zt; + +import lombok.Data; + +import java.math.BigDecimal; +import java.util.Date; +import java.util.List; + +/** + * @author liangyq + * @date 2025-04-15 19:20 + */ +@Data +public class CreateOrderReqDTO { + /** + * 合作模式 ,1:集团客户;2:非集团客户 + */ + private String partnerType; + /** + * partnerType为1时,orderType:1:全网件 2:预约件。 partnerType为2时,orderType:1:全网件 2:预约件(返回运单号) 3:预约件(不返回运单号) 4:星联全网件 + */ + private String orderType; + /** + * 合作商订单号 + */ + private String partnerOrderCode; + /** + * 账号信息 ,AccountDto + */ + private AccountInfo accountInfo; + /** + * 运单号 + */ + private String billCode; + /** + * 发件人信息 ,SenderInfoInput + */ + private SenderInfo senderInfo; + /** + * 收件人信息 ,ReceiveInfoInput + */ + private ReceiveInfo receiveInfo; + /** + * 增值服务信息 + */ + private List orderVasList; + /** + * 门店/仓库编码(partnerType为1时可使用) + */ + private String hallCode; + /** + * 网点code(orderVasList.vasType为receiveReturnService必填) + */ + private String siteCode; + /** + * 网点名称(orderVasList.vasType为receiveReturnService必填) + */ + private String siteName; + /** + * 汇总信息 ,SummaryDto + */ + private SummaryInfo summaryInfo; + /** + * 备注 + */ + private String remark; + /** + * 物品信息 + */ + private List orderItems; + /** + * 机柜信息 ,ExpressCabinetDto + */ + private Cabinet cabinet; + + @Data + public static class AccountInfo { + /** + * 电子面单账号(partnerType为2,orderType传1,2,4时必传) + */ + private String accountId; + /** + * 电子面单密码(测试环境传ZTO123) + */ + private String accountPassword; + /** + * 单号类型:1.普通电子面单;74.星联电子面单;默认是1 + */ + private Integer type; + /** + * 集团客户编码(partnerType传1时必传) + */ + private String customerId; + } + + @Data + public static class SenderInfo { + /** + * senderInfo + */ + private String senderId; + /** + * 发件人姓名 + */ + private String senderName; + /** + * 发件人座机(与senderMobile二者不能同时为空) + */ + private String senderPhone; + /** + * 发件人手机号(与senderPhone二者不能同时为空) + */ + private String senderMobile; + /** + * 发件人省 + */ + private String senderProvince; + /** + * 发件人市 + */ + private String senderCity; + /** + * 发件人区 + */ + private String senderDistrict; + /** + * 发件人详细地址 + */ + private String senderAddress; + } + + @Data + public static class ReceiveInfo { + /** + * 收件人姓名 + */ + private String receiverName; + /** + * 收件人座机(与receiverMobile二者不能同时为空) + */ + private String receiverPhone; + /** + * 收件人手机号(与 receiverPhone二者不能同时为空) + */ + private String receiverMobile; + /** + * 收件人省 + */ + private String receiverProvince; + /** + * 收件人市 + */ + private String receiverCity; + /** + * 收件人区 + */ + private String receiverDistrict; + /** + * 收件人详细地址 + */ + private String receiverAddress; + } + + @Data + public static class OrderVas { + /** + * 增值类型 (COD:代收; vip:中通标快; insured:保价; receiveReturnService:签单返回; twoHour:两小时;standardExpress:中通好快) + */ + private String vasType; + /** + * 增值价格,如果增值类型涉及金额会校验,vasType为COD、insured时不能为空,单位:分 + */ + private Long vasAmount; + /** + * 增值价格(暂时不用) + */ + private Long vasPrice; + /** + * 增值详情 + */ + private String vasDetail; + /** + * 代收账号(有代收货款增值时必填) + */ + private String accountNo; + } + + @Data + public static class SummaryInfo { + /** + * 订单包裹大小(单位:厘米、格式:”长,宽,高”,用半角的逗号来分隔) + */ + private String size; + /** + * 订单包裹内货物总数量 + */ + private Integer quantity; + /** + * 商品总价值(单位:元) + */ + private BigDecimal price; + /** + * 运输费(单位:元) + */ + private BigDecimal freight; + /** + * 险费(单位:元) + */ + private BigDecimal premium; + /** + * 取件开始时间 + */ + private Date startTime; + /** + * 取件截止时间 + */ + private Date endTime; + } + + @Data + public static class OrderItem { + /** + * 货品名称 + */ + private String name; + /** + * 商品分类 + */ + private String category; + /** + * 商品材质 + */ + private String material; + /** + * 大小(长,宽,高)(单位:厘米), 用半角的逗号来分隔长宽高 + */ + private String size; + /** + * 重量(单位:克) + */ + private Long weight; + /** + * 单价(单位:元) + */ + private Integer unitprice; + /** + * 货品数量 + */ + private Integer quantity; + /** + * 货品备注 + */ + private String remark; + } + + @Data + public static class Cabinet { + /** + * 地址 + */ + private String address; + /** + * 格口规格 格口大小( 1 大 2 中 3 小) + */ + private Integer specification; + /** + * 开箱码 + */ + private String code; + } +} diff --git a/xkt/src/main/java/com/ruoyi/xkt/enums/EOrderAction.java b/xkt/src/main/java/com/ruoyi/xkt/enums/EOrderAction.java index 11082a9ab..18ab7e98d 100644 --- a/xkt/src/main/java/com/ruoyi/xkt/enums/EOrderAction.java +++ b/xkt/src/main/java/com/ruoyi/xkt/enums/EOrderAction.java @@ -16,6 +16,7 @@ public enum EOrderAction { DELETE(3, "删除"), PAY(4, "支付"), CANCEL(5, "取消"), + SHIP(6, "发货"), ; private final Integer value; diff --git a/xkt/src/main/java/com/ruoyi/xkt/manager/impl/ZtExpressManagerImpl.java b/xkt/src/main/java/com/ruoyi/xkt/manager/impl/ZtExpressManagerImpl.java index acb8be478..9247ccae4 100644 --- a/xkt/src/main/java/com/ruoyi/xkt/manager/impl/ZtExpressManagerImpl.java +++ b/xkt/src/main/java/com/ruoyi/xkt/manager/impl/ZtExpressManagerImpl.java @@ -3,6 +3,7 @@ package com.ruoyi.xkt.manager.impl; import com.ruoyi.xkt.enums.EExpressChannel; import com.ruoyi.xkt.manager.ExpressManager; import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; /** @@ -12,6 +13,20 @@ import org.springframework.stereotype.Component; @Slf4j @Component public class ZtExpressManagerImpl implements ExpressManager { + + private static final String CREATE_ORDER_URI = "zto.open.createOrder"; + + private static final String STRUCTURE_ADDRESS_URI = "zto.innovate.structureNamePhoneAddress"; + + @Value("${zt.appKey:}") + private String appKey; + + @Value("${zt.appSecret:}") + private String appSecret; + + @Value("${zt.gatewayUrl:}") + private String gatewayUrl; + @Override public EExpressChannel channel() { return EExpressChannel.ZT; diff --git a/xkt/src/main/java/com/ruoyi/xkt/service/IStoreOrderService.java b/xkt/src/main/java/com/ruoyi/xkt/service/IStoreOrderService.java index e97fb5b0f..ed9b101c1 100644 --- a/xkt/src/main/java/com/ruoyi/xkt/service/IStoreOrderService.java +++ b/xkt/src/main/java/com/ruoyi/xkt/service/IStoreOrderService.java @@ -90,7 +90,22 @@ public interface IStoreOrderService { * @param storeOrderId * @param storeOrderDetailIds * @param expressId + * @param operatorId * @return */ - StoreOrderExt preparePlaceOrder(Long storeOrderId, List storeOrderDetailIds, Long expressId); + StoreOrderExt prepareShipOrderByPlatform(Long storeOrderId, List storeOrderDetailIds, Long expressId, + Long operatorId); + + /** + * 发货(档口物流) + * + * @param storeOrderId + * @param storeOrderDetailIds + * @param expressId + * @param expressWaybillNo + * @param operatorId + * @return + */ + StoreOrderExt shipOrderByStore(Long storeOrderId, List storeOrderDetailIds, Long expressId, + String expressWaybillNo, Long operatorId); } diff --git a/xkt/src/main/java/com/ruoyi/xkt/service/impl/StoreOrderServiceImpl.java b/xkt/src/main/java/com/ruoyi/xkt/service/impl/StoreOrderServiceImpl.java index 5b06c6160..5549b9d1d 100644 --- a/xkt/src/main/java/com/ruoyi/xkt/service/impl/StoreOrderServiceImpl.java +++ b/xkt/src/main/java/com/ruoyi/xkt/service/impl/StoreOrderServiceImpl.java @@ -4,6 +4,7 @@ import cn.hutool.core.bean.BeanUtil; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.date.DateUtil; import cn.hutool.core.lang.Assert; +import cn.hutool.core.util.IdUtil; import cn.hutool.core.util.NumberUtil; import com.baomidou.mybatisplus.core.toolkit.Wrappers; import com.github.pagehelper.Page; @@ -19,6 +20,7 @@ import com.ruoyi.xkt.dto.express.ExpressRegionDTO; import com.ruoyi.xkt.dto.order.*; import com.ruoyi.xkt.dto.storeProductFile.StoreProdMainPicDTO; import com.ruoyi.xkt.enums.*; +import com.ruoyi.xkt.manager.ExpressManager; import com.ruoyi.xkt.manager.PaymentManager; import com.ruoyi.xkt.mapper.*; import com.ruoyi.xkt.service.IExpressService; @@ -71,6 +73,8 @@ public class StoreOrderServiceImpl implements IStoreOrderService { private IVoucherSequenceService voucherSequenceService; @Autowired private List paymentManagers; + @Autowired + private List expressManagers; @Transactional(rollbackFor = Exception.class) @Override @@ -210,10 +214,7 @@ public class StoreOrderServiceImpl implements IStoreOrderService { @Override public StoreOrderExt modifyOrder(StoreOrderUpdateDTO storeOrderUpdateDTO) { //原订单 - StoreOrder order = storeOrderMapper.selectById(storeOrderUpdateDTO.getId()); - if (!BeanValidators.exists(order)) { - throw new ServiceException("订单[" + storeOrderUpdateDTO.getId() + "]不存在"); - } + StoreOrder order = getAndBaseCheck(storeOrderUpdateDTO.getId()); Long orderUserId = storeOrderUpdateDTO.getOrderUserId(); Long storeId = storeOrderUpdateDTO.getStoreId(); Long expressId = storeOrderUpdateDTO.getExpressId(); @@ -441,12 +442,10 @@ public class StoreOrderServiceImpl implements IStoreOrderService { @Transactional(rollbackFor = Exception.class) @Override public StoreOrderExt preparePayOrder(Long storeOrderId, EPayChannel payChannel) { - Assert.notNull(storeOrderId); Assert.notNull(payChannel); - StoreOrder order = storeOrderMapper.selectById(storeOrderId); + StoreOrder order = getAndBaseCheck(storeOrderId); Assert.isTrue(EOrderType.SALES_ORDER.getValue().equals(order.getOrderType()), "非销售订单无法发起支付"); - Assert.isTrue(BeanValidators.exists(order), "订单不存在"); if (payChannel != EPayChannel.of(order.getPayChannel())) { throw new ServiceException("订单支付渠道不允许修改"); } @@ -474,11 +473,9 @@ public class StoreOrderServiceImpl implements IStoreOrderService { @Transactional(rollbackFor = Exception.class) @Override public StoreOrderExt paySuccess(Long storeOrderId, BigDecimal totalAmount, BigDecimal realTotalAmount) { - Assert.notNull(storeOrderId); - StoreOrder order = storeOrderMapper.selectById(storeOrderId); + StoreOrder order = getAndBaseCheck(storeOrderId); Assert.isTrue(EOrderType.SALES_ORDER.getValue().equals(order.getOrderType()), "订单类型异常"); - Assert.isTrue(BeanValidators.exists(order), "订单不存在"); if (!order.getPayStatus().equals(EPayStatus.PAYING.getValue()) || !order.getOrderStatus().equals(EOrderStatus.PENDING_PAYMENT.getValue())) { log.error("订单状态异常,更新支付结果失败: id = {}", storeOrderId); @@ -526,9 +523,7 @@ public class StoreOrderServiceImpl implements IStoreOrderService { @Transactional(rollbackFor = Exception.class) @Override public void cancelOrder(OrderOptDTO opt) { - Assert.notNull(opt.getStoreOrderId()); - StoreOrder order = storeOrderMapper.selectById(opt.getStoreOrderId()); - Assert.isTrue(BeanValidators.exists(order), "订单不存在"); + StoreOrder order = getAndBaseCheck(opt.getStoreOrderId()); EOrderStatus oStatus = EOrderStatus.of(order.getOrderStatus()); EPayStatus pStatus = EPayStatus.of(order.getPayStatus()); if (EOrderStatus.PENDING_PAYMENT != oStatus) { @@ -567,9 +562,139 @@ public class StoreOrderServiceImpl implements IStoreOrderService { opt.getOperatorId(), new Date()); } + @Transactional(rollbackFor = Exception.class) @Override - public StoreOrderExt preparePlaceOrder(Long storeOrderId, List storeOrderDetailIds, Long expressId) { - return null; + public StoreOrderExt prepareShipOrderByPlatform(Long storeOrderId, List storeOrderDetailIds, Long expressId, + Long operatorId) { + Assert.notEmpty(storeOrderDetailIds); +// ExpressManager expressManager = getExpressManager(expressId); + Express express = expressService.getById(expressId); + if (!BeanValidators.exists(express) || !express.getSystemDeliverAccess()) { + throw new ServiceException("快递[" + expressId + "]不可用"); + } + StoreOrder order = getAndBaseCheck(storeOrderId); + if (!EOrderStatus.PENDING_SHIPMENT.getValue().equals(order.getOrderStatus()) + && !EOrderStatus.SHIPPED.getValue().equals(order.getOrderStatus())) { + throw new ServiceException("订单[" + order.getId() + "]当前状态无法发货"); + } + List containDetails = storeOrderDetailMapper.selectList( + Wrappers.lambdaQuery(StoreOrderDetail.class) + .eq(StoreOrderDetail::getStoreOrderId, order.getId()) + .eq(SimpleEntity::getDelFlag, Constants.UNDELETED)); + for (StoreOrderDetail containDetail : containDetails) { + if (EDeliveryType.SHIP_COMPLETE.getValue().equals(order.getDeliveryType())) { + //如果是货齐再发,此次发货需要包含所有明细 + if (!storeOrderDetailIds.contains(containDetail.getId())) { + throw new ServiceException("订单[" + order.getId() + "]不可拆单发货"); + } + } + if (EExpressType.STORE.getValue().equals(containDetail.getExpressType())) { + //已存在档口发货的明细 + throw new ServiceException("订单[" + order.getId() + "]由档口物流发货!"); + } + } + List orderDetails = storeOrderDetailMapper.selectByIds(storeOrderDetailIds); + //订单->已发货 + order.setOrderStatus(EOrderStatus.SHIPPED.getValue()); + int orderSuccess = storeOrderMapper.updateById(order); + if (orderSuccess == 0) { + throw new ServiceException(Constants.VERSION_LOCK_ERROR_COMMON_MSG); + } + //生成请求号 + String expressReqNo = IdUtil.simpleUUID(); + List orderDetailIdList = new ArrayList<>(orderDetails.size()); + for (StoreOrderDetail orderDetail : orderDetails) { + if (!BeanValidators.exists(orderDetail)) { + throw new ServiceException("订单明细[" + orderDetail.getId() + "]不存在"); + } + if (!order.getId().equals(orderDetail.getStoreOrderId())) { + throw new ServiceException("发货订单[" + order.getId() + "]与明细[" + orderDetail.getId() + "]不匹配"); + } + if (!EOrderStatus.PENDING_SHIPMENT.getValue().equals(orderDetail.getDetailStatus())) { + throw new ServiceException("订单明细[" + order.getId() + "]当前状态无法发货"); + } + //明细->已发货 + orderDetail.setDetailStatus(EOrderStatus.SHIPPED.getValue()); + orderDetail.setExpressId(expressId); + orderDetail.setExpressType(EExpressType.PLATFORM.getValue()); + orderDetail.setExpressStatus(EExpressStatus.PLACING.getValue()); + orderDetail.setExpressReqNo(expressReqNo); + int orderDetailSuccess = storeOrderDetailMapper.updateById(orderDetail); + if (orderDetailSuccess == 0) { + throw new ServiceException(Constants.VERSION_LOCK_ERROR_COMMON_MSG); + } + orderDetailIdList.add(orderDetail.getId()); + } + //操作记录 + addOperationRecords(order.getId(), EOrderAction.SHIP, orderDetailIdList, EOrderAction.SHIP, + "平台物流发货", operatorId, new Date()); + return new StoreOrderExt(order, orderDetails); + } + + @Transactional(rollbackFor = Exception.class) + @Override + public StoreOrderExt shipOrderByStore(Long storeOrderId, List storeOrderDetailIds, Long expressId, + String expressWaybillNo, Long operatorId) { + Assert.notEmpty(storeOrderDetailIds); + Express express = expressService.getById(expressId); + if (!BeanValidators.exists(express) || !express.getStoreDeliverAccess()) { + throw new ServiceException("快递[" + expressId + "]不可用"); + } + StoreOrder order = getAndBaseCheck(storeOrderId); + if (!EOrderStatus.PENDING_SHIPMENT.getValue().equals(order.getOrderStatus()) + && !EOrderStatus.SHIPPED.getValue().equals(order.getOrderStatus())) { + throw new ServiceException("订单[" + order.getId() + "]当前状态无法发货"); + } + List containDetails = storeOrderDetailMapper.selectList( + Wrappers.lambdaQuery(StoreOrderDetail.class) + .eq(StoreOrderDetail::getStoreOrderId, order.getId()) + .eq(SimpleEntity::getDelFlag, Constants.UNDELETED)); + for (StoreOrderDetail containDetail : containDetails) { + if (EDeliveryType.SHIP_COMPLETE.getValue().equals(order.getDeliveryType())) { + //如果是货齐再发,此次发货需要包含所有明细 + if (!storeOrderDetailIds.contains(containDetail.getId())) { + throw new ServiceException("订单[" + order.getId() + "]不可拆单发货"); + } + } + if (EExpressType.PLATFORM.getValue().equals(containDetail.getExpressType())) { + //已存在平台发货的明细 + throw new ServiceException("订单[" + order.getId() + "]由平台物流发货!"); + } + } + List orderDetails = storeOrderDetailMapper.selectByIds(storeOrderDetailIds); + //订单->已发货 + order.setOrderStatus(EOrderStatus.SHIPPED.getValue()); + int orderSuccess = storeOrderMapper.updateById(order); + if (orderSuccess == 0) { + throw new ServiceException(Constants.VERSION_LOCK_ERROR_COMMON_MSG); + } + List orderDetailIdList = new ArrayList<>(orderDetails.size()); + for (StoreOrderDetail orderDetail : orderDetails) { + if (!BeanValidators.exists(orderDetail)) { + throw new ServiceException("订单明细[" + orderDetail.getId() + "]不存在"); + } + if (!order.getId().equals(orderDetail.getStoreOrderId())) { + throw new ServiceException("发货订单[" + order.getId() + "]与明细[" + orderDetail.getId() + "]不匹配"); + } + if (!EOrderStatus.PENDING_SHIPMENT.getValue().equals(orderDetail.getDetailStatus())) { + throw new ServiceException("订单明细[" + order.getId() + "]当前状态无法发货"); + } + //明细->已发货 + orderDetail.setDetailStatus(EOrderStatus.SHIPPED.getValue()); + orderDetail.setExpressId(expressId); + orderDetail.setExpressType(EExpressType.STORE.getValue()); + orderDetail.setExpressStatus(EExpressStatus.COMPLETED.getValue()); + orderDetail.setExpressWaybillNo(expressWaybillNo); + int orderDetailSuccess = storeOrderDetailMapper.updateById(orderDetail); + if (orderDetailSuccess == 0) { + throw new ServiceException(Constants.VERSION_LOCK_ERROR_COMMON_MSG); + } + orderDetailIdList.add(orderDetail.getId()); + } + //操作记录 + addOperationRecords(order.getId(), EOrderAction.SHIP, orderDetailIdList, EOrderAction.SHIP, + "档口物流发货", operatorId, new Date()); + return new StoreOrderExt(order, orderDetails); } private void checkPreparePayStatus(Integer payStatus) { @@ -729,6 +854,15 @@ public class StoreOrderServiceImpl implements IStoreOrderService { return new OrderDetailCheckRtn(spcsMap, spMap, scMap); } + private StoreOrder getAndBaseCheck(Long storeOrderId) { + Assert.notNull(storeOrderId); + StoreOrder order = storeOrderMapper.selectById(storeOrderId); + if (!BeanValidators.exists(order)) { + throw new ServiceException("订单[" + storeOrderId + "]不存在"); + } + return order; + } + /** * 根据支付渠道匹配支付类 * @@ -747,6 +881,22 @@ public class StoreOrderServiceImpl implements IStoreOrderService { throw new ServiceException("未知支付渠道"); } + /** + * 匹配物流类 + * + * @param expressId + * @return + */ + private ExpressManager getExpressManager(Long expressId) { + Assert.notNull(expressId); + for (ExpressManager expressManager : expressManagers) { + if (expressManager.channel().getExpressId().equals(expressId)) { + return expressManager; + } + } + throw new ServiceException("未知物流渠道"); + } + @Data @AllArgsConstructor @NoArgsConstructor