feat: 订单

pull/1121/head
梁宇奇 2025-04-14 19:08:18 +08:00
parent 8b743d9dd7
commit 856e4056c2
26 changed files with 1039 additions and 23 deletions

View File

@ -1,9 +1,11 @@
package com.ruoyi.web.controller.xkt;
import cn.hutool.core.bean.BeanUtil;
import com.github.pagehelper.Page;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.common.core.controller.XktBaseController;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.common.core.page.PageVO;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.SecurityUtils;
@ -18,6 +20,7 @@ import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import javax.validation.Valid;
@ -53,7 +56,7 @@ public class StoreOrderController extends XktBaseController {
return success(respVO);
}
@PreAuthorize("@ss.hasPermi('system:order:add')")
@PreAuthorize("@ss.hasPermi('system:order:edit')")
@Log(title = "订单", businessType = BusinessType.UPDATE)
@ApiOperation("修改订单")
@PutMapping("edit")
@ -61,6 +64,7 @@ public class StoreOrderController extends XktBaseController {
StoreOrderUpdateDTO dto = BeanUtil.toBean(vo, StoreOrderUpdateDTO.class);
dto.setOrderUserId(SecurityUtils.getUserId());
StoreOrderExt result = storeOrderService.modifyOrder(dto);
//TODO 非下单人,不允许修改
return success(result.getOrder().getId());
}
@ -78,6 +82,19 @@ public class StoreOrderController extends XktBaseController {
return success(respVO);
}
@PreAuthorize("@ss.hasPermi('system:order:edit')")
@Log(title = "订单", businessType = BusinessType.UPDATE)
@PutMapping("cancel")
public R cancel(@Valid @RequestBody StoreOrderCancelReqVO vo) {
OrderOptDTO dto = OrderOptDTO.builder()
.storeOrderId(vo.getStoreOrderId())
.operatorId(SecurityUtils.getUserId())
.build();
storeOrderService.cancelOrder(dto);
//TODO 非下单人,不允许取消
return success();
}
@PreAuthorize("@ss.hasPermi('system:order:query')")
@ApiOperation(value = "订单详情")
@GetMapping(value = "/{id}")
@ -87,6 +104,21 @@ public class StoreOrderController extends XktBaseController {
return success(BeanUtil.toBean(infoDTO, StoreOrderInfoVO.class));
}
@PreAuthorize("@ss.hasPermi('system:order:list')")
@ApiOperation(value = "订单分页查询")
@PostMapping("/page")
public R<PageVO<StoreOrderPageItemVO>> page(@Validated @RequestBody StoreOrderQueryVO vo) {
StoreOrderQueryDTO queryDTO = BeanUtil.toBean(vo, StoreOrderQueryDTO.class);
if (1 == vo.getSrcPage()) {
queryDTO.setOrderUserId(SecurityUtils.getUserId());
} else {
//TODO 当前档口
}
Page<StoreOrderPageItemDTO> pageDTO = storeOrderService.page(queryDTO);
return success(PageVO.of(pageDTO, StoreOrderPageItemVO.class));
}
/**
*
*

View File

@ -0,0 +1,20 @@
package com.ruoyi.web.controller.xkt.vo.order;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import javax.validation.constraints.NotNull;
/**
* @author liangyq
* @date 2025-04-07 18:16
*/
@ApiModel
@Data
public class StoreOrderCancelReqVO {
@NotNull(message = "订单ID不能为空")
@ApiModelProperty(value = "订单ID")
private Long storeOrderId;
}

View File

@ -25,6 +25,16 @@ public class StoreOrderInfoVO {
*/
@ApiModelProperty(value = "档口ID")
private Long storeId;
/**
*
*/
@ApiModelProperty(value = "档口名称")
private String storeName;
/**
*
*/
@ApiModelProperty(value = "品牌名称")
private String brandName;
/**
* ID
*/

View File

@ -0,0 +1,399 @@
package com.ruoyi.web.controller.xkt.vo.order;
import com.ruoyi.xkt.dto.order.StoreOrderDTO;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
/**
* @author liangyq
* @date 2025-04-14 11:18
*/
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class StoreOrderPageItemVO extends StoreOrderDTO {
/**
* ID
*/
@ApiModelProperty(value = "订单ID")
private Long id;
/**
* ID
*/
@ApiModelProperty(value = "档口ID")
private Long storeId;
/**
*
*/
@ApiModelProperty(value = "档口名称")
private String storeName;
/**
*
*/
@ApiModelProperty(value = "品牌名称")
private String brandName;
/**
* ID
*/
@ApiModelProperty(value = "下单用户ID")
private Long orderUserId;
/**
*
*/
@ApiModelProperty(value = "订单号")
private String orderNo;
/**
* [1: 2:退]
*/
@ApiModelProperty(value = "订单类型[1:销售订单 2:退货订单]")
private Integer orderType;
/**
* 12退[10: 11: 12: 13: 14: 21: 22: 23: 24:]
*/
@ApiModelProperty(value = "订单状态1开头为销售订单状态2开头为退货订单状态[10:已取消 11:待付款 12:待发货 13:已发货 14:已完成 21:售后中 22:售后拒绝 23:平台介入 24:售后完成]")
private Integer orderStatus;
/**
* [1: 2: 3:]
*/
@ApiModelProperty(value = "支付状态[1:初始 2:支付中 3:已支付]")
private Integer payStatus;
/**
*
*/
@ApiModelProperty(value = "订单备注")
private String orderRemark;
/**
*
*/
@ApiModelProperty(value = "商品数量")
private Integer goodsQuantity;
/**
*
*/
@ApiModelProperty(value = "商品金额")
private BigDecimal goodsAmount;
/**
*
*/
@ApiModelProperty(value = "快递费")
private BigDecimal expressFee;
/**
* +
*/
@ApiModelProperty(value = "总金额")
private BigDecimal totalAmount;
/**
* -
*/
@ApiModelProperty(value = "实际总金额")
private BigDecimal realTotalAmount;
/**
* 退ID
*/
@ApiModelProperty(value = "退货原订单ID")
private Long refundOrderId;
/**
* 退
*/
@ApiModelProperty(value = "退货原因")
private Integer refundReasonCode;
/**
* 退
*/
@ApiModelProperty(value = "退货拒绝原因")
private String refundRejectReason;
/**
* ID
*/
@ApiModelProperty(value = "物流ID")
private Long expressId;
/**
* -
*/
@ApiModelProperty(value = "发货人-名称")
private String originContactName;
/**
* -
*/
@ApiModelProperty(value = "发货人-电话")
private String originContactPhoneNumber;
/**
* -
*/
@ApiModelProperty(value = "发货人-省编码")
private String originProvinceCode;
/**
* -
*/
@ApiModelProperty(value = "发货人-市编码")
private String originCityCode;
/**
* -
*/
@ApiModelProperty(value = "发货人-区县编码")
private String originCountyCode;
/**
* -
*/
@ApiModelProperty(value = "发货人-详细地址")
private String originDetailAddress;
/**
* -
*/
@ApiModelProperty(value = "收货人-名称")
private String destinationContactName;
/**
* -
*/
@ApiModelProperty(value = "收货人-电话")
private String destinationContactPhoneNumber;
/**
* -
*/
@ApiModelProperty(value = "收货人-省编码")
private String destinationProvinceCode;
/**
* -
*/
@ApiModelProperty(value = "收货人-市编码")
private String destinationCityCode;
/**
* -
*/
@ApiModelProperty(value = "收货人-区县编码")
private String destinationCountyCode;
/**
* -
*/
@ApiModelProperty(value = "收货人-详细地址")
private String destinationDetailAddress;
/**
* [1: 2:]
*/
@ApiModelProperty(value = "发货方式[1:货其再发 2:有货先发]")
private Integer deliveryType;
/**
*
*/
@ApiModelProperty(value = "最晚发货时间")
private Date deliveryEndTime;
/**
*
*/
@ApiModelProperty(value = "自动完成时间")
private Date autoEndTime;
/**
*
*/
@ApiModelProperty(value = "凭证日期")
private Date voucherDate;
/**
* 0 2
*/
@ApiModelProperty(value = "删除标志0代表存在 2代表删除")
private String delFlag;
/**
*
*/
@ApiModelProperty(value = "创建者")
private String createBy;
/**
*
*/
@ApiModelProperty(value = "创建时间")
private Date createTime;
/**
*
*/
@ApiModelProperty(value = "更新者")
private String updateBy;
/**
*
*/
@ApiModelProperty(value = "更新时间")
private Date updateTime;
@ApiModelProperty(value = "快递名")
private String expressName;
@ApiModelProperty(value = "发货人-省名称")
private String originProvinceName;
@ApiModelProperty(value = "发货人-市名称")
private String originCityName;
@ApiModelProperty(value = "发货人-区县名称")
private String originCountyName;
@ApiModelProperty(value = "收货人-省名称")
private String destinationProvinceName;
@ApiModelProperty(value = "收货人-市名称")
private String destinationCityName;
@ApiModelProperty(value = "收货人-区县名称")
private String destinationCountyName;
@ApiModelProperty(value = "订单明细")
private List<Detail> orderDetails;
@ApiModel
@Data
public static class Detail {
/**
* url
*/
@ApiModelProperty(value = "预览图url")
private String firstMainPicUrl;
/**
* ID
*/
@ApiModelProperty(value = "订单明细ID")
private Long id;
/**
* ID
*/
@ApiModelProperty(value = "订单ID")
private Long storeOrderId;
/**
* ID
*/
@ApiModelProperty(value = "商品颜色尺码ID")
private Long storeProdColorSizeId;
/**
* ID
*/
@ApiModelProperty(value = "商品ID")
private Long storeProdId;
/**
* [10: 11: 12: 13: 14: 21: 22: 23: 24:]
*/
@ApiModelProperty(value = "订单明细状态(同订单状态)[10:已取消 11:待付款 12:待发货 13:已发货 14:已完成 21:售后中 22:售后拒绝 23:平台介入 24:售后完成]")
private Integer detailStatus;
/**
* [1: 2: 3:]
*/
@ApiModelProperty(value = "支付状态[1:初始 2:支付中 3:已支付]")
private Integer payStatus;
/**
* ID
*/
@ApiModelProperty(value = "物流ID")
private Long expressId;
/**
* [1: 2:]
*/
@ApiModelProperty(value = "物流类型[1:平台物流 2:档口物流]")
private Integer expressType;
/**
* [1: 2: 3: 4: 5: 6: 99:]
*/
@ApiModelProperty(value = "物流状态[1:初始 2:下单中 3:已下单 4:取消中 5:已揽件 6:拦截中 99:已结束]")
private Integer expressStatus;
/**
*
*/
@ApiModelProperty(value = "物流请求单号")
private String expressReqNo;
/**
* /使,
*/
@ApiModelProperty(value = "物流运单号(快递单号),档口/用户自己填写时可能存在多个,使用“,”分割")
private String expressWaybillNo;
/**
*
*/
@ApiModelProperty(value = "商品单价")
private BigDecimal goodsPrice;
/**
*
*/
@ApiModelProperty(value = "商品数量")
private Integer goodsQuantity;
/**
* *
*/
@ApiModelProperty(value = "商品金额")
private BigDecimal goodsAmount;
/**
*
*/
@ApiModelProperty(value = "快递费")
private BigDecimal expressFee;
/**
* +
*/
@ApiModelProperty(value = "总金额")
private BigDecimal totalAmount;
/**
* -
*/
@ApiModelProperty(value = "实际总金额")
private BigDecimal realTotalAmount;
/**
* 退ID
*/
@ApiModelProperty(value = "退货原订单明细ID")
private Long refundOrderDetailId;
/**
* 退
*/
@ApiModelProperty(value = "退货原因")
private Integer refundReasonCode;
/**
* 退
*/
@ApiModelProperty(value = "退货拒绝原因")
private String refundRejectReason;
/**
* 0 2
*/
@ApiModelProperty(value = "删除标志0代表存在 2代表删除")
private String delFlag;
/**
*
*/
@ApiModelProperty(value = "创建者")
private String createBy;
/**
*
*/
@ApiModelProperty(value = "创建时间")
private Date createTime;
/**
*
*/
@ApiModelProperty(value = "更新者")
private String updateBy;
/**
*
*/
@ApiModelProperty(value = "更新时间")
private Date updateTime;
@ApiModelProperty(value = "档口商品名称")
private String prodName;
@ApiModelProperty(value = "商品货号")
private String prodArtNum;
@ApiModelProperty(value = "商品标题")
private String prodTitle;
@ApiModelProperty(value = "档口颜色ID")
private Long storeColorId;
@ApiModelProperty(value = "颜色名称")
private String colorName;
@ApiModelProperty(value = "商品尺码")
private Integer size;
}
}

View File

@ -0,0 +1,93 @@
package com.ruoyi.web.controller.xkt.vo.order;
import com.ruoyi.web.controller.xkt.vo.BasePageVO;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import javax.validation.constraints.NotNull;
import java.util.Date;
/**
* @author liangyq
* @date 2025-04-14 12:54
*/
@ApiModel
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class StoreOrderQueryVO extends BasePageVO {
/**
* ID
*/
@ApiModelProperty(value = "档口ID")
private Long storeId;
// /**
// * 下单用户ID
// */
// @ApiModelProperty(value = "下单用户ID")
// private Long orderUserId;
/**
*
*/
@ApiModelProperty(value = "订单号(模糊)")
private String orderNo;
/**
* 12退[10: 11: 12: 13: 14: 21: 22: 23: 24:]
*/
@ApiModelProperty(value = "订单状态1开头为销售订单状态2开头为退货订单状态[10:已取消 11:待付款 12:待发货 13:已发货 14:已完成 21:售后中 22:售后拒绝 23:平台介入 24:售后完成]")
private Integer orderStatus;
/**
* -
*/
@ApiModelProperty(value = "收货人-名称(模糊)")
private String destinationContactName;
/**
* -
*/
@ApiModelProperty(value = "收货人-电话(模糊)")
private String destinationContactPhoneNumber;
/**
* [1: 2:]
*/
@ApiModelProperty(value = "发货方式[1:货其再发 2:有货先发]")
private Integer deliveryType;
/**
*
*/
@ApiModelProperty(value = "下单开始时间")
private Date orderTimeBegin;
/**
*
*/
@ApiModelProperty(value = "下单结束时间")
private Date orderTimeEnd;
/**
*
*/
@ApiModelProperty(value = "支付开始时间")
private Date payTimeBegin;
/**
*
*/
@ApiModelProperty(value = "支付结束时间")
private Date payTimeEnd;
/**
*
*/
@ApiModelProperty(value = "物流运单号(模糊)")
private String expressWaybillNo;
/**
*
*/
@ApiModelProperty(value = "商品货号(模糊)")
private String prodArtNum;
@NotNull(message = "来源页面不能为空")
@ApiModelProperty(value = "来源页面[1:卖家订单列表 2:档口订单列表]")
private Integer srcPage;
}

View File

@ -204,6 +204,8 @@ public class Constants
public static final String VERSION_LOCK_ERROR_COMMON_MSG = "系统繁忙,请稍后再试";
public static final String REGION_MAP_CACHE_KEY = "REGION_MAP";

View File

@ -2,7 +2,6 @@ package com.ruoyi.common.core.page;
import cn.hutool.core.bean.BeanUtil;
import com.github.pagehelper.PageInfo;
import com.ruoyi.common.constant.HttpStatus;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@ -58,6 +57,15 @@ public class Page<T> implements Serializable {
return page;
}
public static <T> Page<T> convert(com.github.pagehelper.Page<T> srcPage) {
Page<T> page = new Page<>();
page.setTotal(srcPage.getTotal());
page.setPageNum(srcPage.getPageNum());
page.setPageSize(srcPage.getPageSize());
page.setList(srcPage.getResult());
return page;
}
public static <T> Page<T> empty(int pageSize, int pageNum) {
Page<T> page = new Page<>();

View File

@ -0,0 +1,48 @@
package com.ruoyi.common.core.page;
import cn.hutool.core.bean.BeanUtil;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;
import java.io.Serializable;
import java.util.List;
/**
* Page
*
* @author ruoyi
*/
@NoArgsConstructor
@AllArgsConstructor
@Data
@Accessors(chain = true)
public class PageVO<T> implements Serializable {
private static final long serialVersionUID = 1L;
@ApiModelProperty("当前页")
private Long pageNum;
@ApiModelProperty("每页记录数")
private Long pageSize;
@ApiModelProperty("总记录数")
private Long total;
@ApiModelProperty("结果集")
private List<T> list;
public static <T> PageVO<T> of(Page page, Class<T> clazz) {
return new PageVO<>(page.getPageNum(), page.getPageSize(), page.getTotal(),
BeanUtil.copyToList(page.getList(), clazz));
}
public static <T> PageVO<T> of(com.github.pagehelper.Page page, Class<T> clazz) {
return new PageVO<>((long) page.getPageNum(), (long) page.getPageSize(), page.getTotal(),
BeanUtil.copyToList(page.getResult(), clazz));
}
}

View File

@ -6,6 +6,8 @@ import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import java.io.Serializable;
/**
*
*
@ -15,7 +17,7 @@ import lombok.ToString;
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class ExpressRegion extends SimpleEntity {
public class ExpressRegion extends SimpleEntity implements Serializable {
/**
*
*/

View File

@ -26,7 +26,7 @@ public class StoreOrderOperationRecord extends SimpleEntity {
*/
private Integer targetType;
/**
* [1: 2: 3: 4: 5: 6: 7: 8: 9: 10:]
*
*/
private Integer action;
/**

View File

@ -0,0 +1,23 @@
package com.ruoyi.xkt.dto.order;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* @author liangyq
* @date 2025-04-14 18:52
*/
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class OrderOptDTO {
private Long storeOrderId;
private Long operatorId;
private String remark;
}

View File

@ -15,6 +15,10 @@ import java.util.List;
@ToString(callSuper = true)
public class StoreOrderInfoDTO extends StoreOrderDTO {
private String storeName;
private String brandName;
private String expressName;
private String originProvinceName;

View File

@ -19,7 +19,7 @@ public class StoreOrderOperationRecordAddDTO {
*/
private Integer targetType;
/**
* [1: 2: 3: 4: 5: 6: 7: 8: 9: 10:]
*
*/
private Integer action;
/**

View File

@ -25,7 +25,7 @@ public class StoreOrderOperationRecordDTO {
*/
private Integer targetType;
/**
* [1: 2: 3: 4: 5: 6: 7: 8: 9: 10:]
*
*/
private Integer action;
/**

View File

@ -0,0 +1,46 @@
package com.ruoyi.xkt.dto.order;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import java.util.List;
/**
* @author liangyq
* @date 2025-04-14 11:18
*/
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class StoreOrderPageItemDTO extends StoreOrderDTO {
private String storeName;
private String brandName;
private String expressName;
private String originProvinceName;
private String originCityName;
private String originCountyName;
private String destinationProvinceName;
private String destinationCityName;
private String destinationCountyName;
private List<Detail> orderDetails;
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public static class Detail extends StoreOrderDetailDTO {
private String firstMainPicUrl;
}
}

View File

@ -0,0 +1,73 @@
package com.ruoyi.xkt.dto.order;
import com.ruoyi.xkt.dto.BasePageDTO;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import java.util.Date;
/**
* @author liangyq
* @date 2025-04-14 12:54
*/
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class StoreOrderQueryDTO extends BasePageDTO {
/**
* ID
*/
private Long storeId;
/**
* ID
*/
private Long orderUserId;
/**
*
*/
private String orderNo;
/**
* 12退[10: 11: 12: 13: 14: 21: 22: 23: 24:]
*/
private Integer orderStatus;
/**
* -
*/
private String destinationContactName;
/**
* -
*/
private String destinationContactPhoneNumber;
/**
* [1: 2:]
*/
private Integer deliveryType;
/**
*
*/
private Date orderTimeBegin;
/**
*
*/
private Date orderTimeEnd;
/**
*
*/
private Date payTimeBegin;
/**
*
*/
private Date payTimeEnd;
/**
*
*/
private String expressWaybillNo;
/**
*
*/
private String prodArtNum;
}

View File

@ -15,6 +15,7 @@ public enum EOrderAction {
UPDATE(2, "修改"),
DELETE(3, "删除"),
PAY(4, "支付"),
CANCEL(5, "取消"),
;
private final Integer value;

View File

@ -1,5 +1,6 @@
package com.ruoyi.xkt.enums;
import com.ruoyi.common.exception.ServiceException;
import lombok.AllArgsConstructor;
import lombok.Getter;

View File

@ -25,4 +25,13 @@ public interface PaymentManager {
*/
String payOrder(StoreOrderExt order, EPayPage payFrom);
/**
*
* true
*
* @param orderNo
* @return
*/
boolean isOrderPaid(String orderNo);
}

View File

@ -1,11 +1,16 @@
package com.ruoyi.xkt.manager.impl;
import cn.hutool.core.lang.Assert;
import com.alibaba.fastjson2.JSON;
import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.diagnosis.DiagnosisUtils;
import com.alipay.api.domain.AlipayTradeQueryModel;
import com.alipay.api.request.AlipayTradePagePayRequest;
import com.alipay.api.request.AlipayTradeQueryRequest;
import com.alipay.api.request.AlipayTradeWapPayRequest;
import com.alipay.api.response.AlipayTradeQueryResponse;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.xkt.dto.finance.AlipayReqDTO;
import com.ruoyi.xkt.dto.order.StoreOrderExt;
@ -13,7 +18,6 @@ import com.ruoyi.xkt.enums.EPayChannel;
import com.ruoyi.xkt.enums.EPayPage;
import com.ruoyi.xkt.enums.EPayStatus;
import com.ruoyi.xkt.manager.PaymentManager;
import io.jsonwebtoken.lang.Assert;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
@ -119,4 +123,47 @@ public class AliPaymentMangerImpl implements PaymentManager {
}
}
@Override
public boolean isOrderPaid(String orderNo) {
Assert.notEmpty(orderNo);
AlipayClient alipayClient = new DefaultAlipayClient(gatewayUrl, appId, privateKey, DEFAULT_FORMAT, charset,
alipayPublicKey, signType);
// 构造请求参数以调用接口
AlipayTradeQueryRequest request = new AlipayTradeQueryRequest();
AlipayTradeQueryModel model = new AlipayTradeQueryModel();
model.setOutTradeNo(orderNo);
request.setBizModel(model);
AlipayTradeQueryResponse response = null;
try {
response = alipayClient.execute(request);
if (response.isSuccess()) {
String tradeStatus = JSON.parseObject(response.getBody())
.getJSONObject("alipay_trade_query_response")
.getString("trade_status");
//交易支付成功
if ("TRADE_SUCCESS".equals(tradeStatus)
//交易结束,不可退款
|| "TRADE_FINISHED".equals(tradeStatus)) {
return true;
}
return false;
} else {
//获取诊断链接
String diagnosisUrl = DiagnosisUtils.getDiagnosisUrl(response);
log.warn("查询订单支付结果异常: {}", diagnosisUrl);
//获取错误码
String subCode = JSON.parseObject(response.getBody())
.getJSONObject("alipay_trade_query_response")
.getString("sub_code");
if ("ACQ.TRADE_NOT_EXIST".equals(subCode)) {
//交易不存在
return false;
}
}
} catch (Exception e) {
log.error("查询订单支付结果异常", e);
}
throw new ServiceException("查询订单支付结果失败");
}
}

View File

@ -2,12 +2,18 @@ package com.ruoyi.xkt.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.ruoyi.xkt.domain.StoreOrder;
import com.ruoyi.xkt.dto.order.StoreOrderPageItemDTO;
import com.ruoyi.xkt.dto.order.StoreOrderQueryDTO;
import org.springframework.stereotype.Repository;
import java.util.List;
/**
* @author liangyq
* @date 2025-04-02 12:48
*/
@Repository
public interface StoreOrderMapper extends BaseMapper<StoreOrder> {
List<StoreOrderPageItemDTO> listStoreOrderPageItem(StoreOrderQueryDTO queryDTO);
}

View File

@ -7,6 +7,7 @@ import com.ruoyi.xkt.dto.express.ExpressContactDTO;
import java.util.Collection;
import java.util.List;
import java.util.Map;
/**
* @author liangyq
@ -55,4 +56,11 @@ public interface IExpressService {
* @return
*/
List<ExpressRegion> listRegionByCode(Collection<String> regionCodes);
/**
*
*
* @return
*/
Map<String, ExpressRegion> getRegionMapCache();
}

View File

@ -1,5 +1,6 @@
package com.ruoyi.xkt.service;
import com.github.pagehelper.Page;
import com.ruoyi.xkt.domain.StoreOrder;
import com.ruoyi.xkt.dto.order.*;
import com.ruoyi.xkt.enums.EPayChannel;
@ -48,6 +49,14 @@ public interface IStoreOrderService {
*/
StoreOrderInfoDTO getInfo(Long storeOrderId);
/**
*
*
* @param queryDTO
* @return
*/
Page<StoreOrderPageItemDTO> page(StoreOrderQueryDTO queryDTO);
/**
*
*
@ -65,4 +74,11 @@ public interface IStoreOrderService {
* @return
*/
StoreOrderExt paySuccess(Long storeOrderId, BigDecimal totalAmount, BigDecimal realTotalAmount);
/**
*
*
* @param opt
*/
void cancelOrder(OrderOptDTO opt);
}

View File

@ -4,6 +4,8 @@ import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.lang.Assert;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.ruoyi.common.constant.Constants;
import com.ruoyi.common.core.redis.RedisCache;
import com.ruoyi.common.utils.bean.BeanValidators;
import com.ruoyi.xkt.domain.Express;
import com.ruoyi.xkt.domain.ExpressFeeConfig;
@ -20,6 +22,7 @@ import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;
/**
@ -46,6 +49,8 @@ public class ExpressServiceImpl implements IExpressService {
private ExpressRegionMapper expressRegionMapper;
@Autowired
private StoreMapper storeMapper;
@Autowired
private RedisCache redisCache;
@Override
public void checkExpress(Long expressId) {
@ -115,4 +120,15 @@ public class ExpressServiceImpl implements IExpressService {
return expressRegionMapper.selectList(Wrappers.lambdaQuery(ExpressRegion.class)
.in(ExpressRegion::getRegionCode, regionCodes));
}
@Override
public Map<String, ExpressRegion> getRegionMapCache() {
Map<String, ExpressRegion> regionMap = redisCache.getCacheMap(Constants.REGION_MAP_CACHE_KEY);
if (regionMap == null || regionMap.isEmpty()) {
regionMap = expressRegionMapper.selectList(Wrappers.emptyWrapper()).stream()
.collect(Collectors.toMap(ExpressRegion::getRegionCode, Function.identity()));
redisCache.setCacheMap(Constants.REGION_MAP_CACHE_KEY, regionMap);
}
return regionMap;
}
}

View File

@ -6,6 +6,8 @@ import cn.hutool.core.date.DateUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.NumberUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.ruoyi.common.constant.Constants;
import com.ruoyi.common.core.domain.SimpleEntity;
import com.ruoyi.common.core.domain.XktBaseEntity;
@ -14,6 +16,7 @@ import com.ruoyi.common.utils.bean.BeanValidators;
import com.ruoyi.xkt.domain.*;
import com.ruoyi.xkt.dto.express.ExpressContactDTO;
import com.ruoyi.xkt.dto.order.*;
import com.ruoyi.xkt.dto.storeProductFile.StoreProdMainPicDTO;
import com.ruoyi.xkt.enums.*;
import com.ruoyi.xkt.manager.PaymentManager;
import com.ruoyi.xkt.mapper.*;
@ -34,6 +37,8 @@ import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;
import static com.ruoyi.common.constant.Constants.ORDER_NUM_1;
/**
* @author liangyq
* @date 2025-04-02 13:19
@ -46,6 +51,8 @@ public class StoreOrderServiceImpl implements IStoreOrderService {
@Autowired
private StoreOrderDetailMapper storeOrderDetailMapper;
@Autowired
private StoreMapper storeMapper;
@Autowired
private StoreProductMapper storeProductMapper;
@Autowired
private StoreProductColorSizeMapper storeProductColorSizeMapper;
@ -64,7 +71,7 @@ public class StoreOrderServiceImpl implements IStoreOrderService {
@Autowired
private List<PaymentManager> paymentManagers;
@Transactional
@Transactional(rollbackFor = Exception.class)
@Override
public StoreOrderAddResult createOrder(StoreOrderAddDTO storeOrderAddDTO, boolean beginPay, EPayChannel payChannel,
EPayPage payPage) {
@ -196,7 +203,7 @@ public class StoreOrderServiceImpl implements IStoreOrderService {
return new StoreOrderAddResult(orderExt, rtnStr);
}
@Transactional
@Transactional(rollbackFor = Exception.class)
@Override
public StoreOrderExt modifyOrder(StoreOrderUpdateDTO storeOrderUpdateDTO) {
//原订单
@ -348,21 +355,28 @@ public class StoreOrderServiceImpl implements IStoreOrderService {
List<StoreOrderDetailInfoDTO> detailInfos = BeanUtil.copyToList(details,
StoreOrderDetailInfoDTO.class);
orderInfo.setOrderDetails(detailInfos);
//档口信息
Store store = storeMapper.selectById(order.getStoreId());
if (store != null) {
orderInfo.setStoreName(store.getStoreName());
orderInfo.setBrandName(store.getBrandName());
}
//物流信息
Express express = expressService.getById(order.getExpressId());
orderInfo.setExpressName(Optional.ofNullable(express).map(Express::getExpressName).orElse(null));
Map<String, String> regionNameMap = expressService.listRegionByCode(Arrays
.asList(order.getDestinationProvinceCode(), order.getDestinationCityCode(),
order.getDestinationCountyCode(), order.getOriginProvinceCode(),
order.getOriginCityCode(), order.getOriginCountyCode()))
.stream()
.collect(Collectors.toMap(ExpressRegion::getRegionCode, ExpressRegion::getRegionName));
orderInfo.setDestinationProvinceName(regionNameMap.get(orderInfo.getDestinationProvinceCode()));
orderInfo.setDestinationCityName(regionNameMap.get(orderInfo.getDestinationCityCode()));
orderInfo.setDestinationCountyName(regionNameMap.get(orderInfo.getDestinationCountyCode()));
orderInfo.setOriginProvinceName(regionNameMap.get(orderInfo.getOriginProvinceCode()));
orderInfo.setOriginCityName(regionNameMap.get(orderInfo.getOriginCityCode()));
orderInfo.setOriginCountyName(regionNameMap.get(orderInfo.getOriginCountyCode()));
Map<String, ExpressRegion> regionMap = expressService.getRegionMapCache();
orderInfo.setDestinationProvinceName(Optional.ofNullable(regionMap.get(orderInfo.getDestinationProvinceCode()))
.map(ExpressRegion::getParentRegionName).orElse(null));
orderInfo.setDestinationCityName(Optional.ofNullable(regionMap.get(orderInfo.getDestinationCityCode()))
.map(ExpressRegion::getParentRegionName).orElse(null));
orderInfo.setDestinationCountyName(Optional.ofNullable(regionMap.get(orderInfo.getDestinationCountyCode()))
.map(ExpressRegion::getParentRegionName).orElse(null));
orderInfo.setOriginProvinceName(Optional.ofNullable(regionMap.get(orderInfo.getOriginProvinceCode()))
.map(ExpressRegion::getParentRegionName).orElse(null));
orderInfo.setOriginCityName(Optional.ofNullable(regionMap.get(orderInfo.getOriginCityCode()))
.map(ExpressRegion::getParentRegionName).orElse(null));
orderInfo.setOriginCountyName(Optional.ofNullable(regionMap.get(orderInfo.getOriginCountyCode()))
.map(ExpressRegion::getParentRegionName).orElse(null));
//商品信息
for (StoreOrderDetailInfoDTO detailInfo : detailInfos) {
detailInfo.setFileList(storeProductFileMapper.selectListByStoreProdId(detailInfo.getStoreProdId()));
@ -370,7 +384,52 @@ public class StoreOrderServiceImpl implements IStoreOrderService {
return orderInfo;
}
@Transactional
@Override
public Page<StoreOrderPageItemDTO> page(StoreOrderQueryDTO queryDTO) {
Page<StoreOrderPageItemDTO> page = PageHelper.startPage(queryDTO.getPageNum(), queryDTO.getPageSize());
storeOrderMapper.listStoreOrderPageItem(queryDTO);
if (CollUtil.isNotEmpty(page.getResult())) {
List<StoreOrderPageItemDTO> list = page.getResult();
Set<Long> soIds = list.stream().map(StoreOrderPageItemDTO::getId).collect(Collectors.toSet());
List<StoreOrderDetail> orderDetailList = storeOrderDetailMapper.selectList(Wrappers
.lambdaQuery(StoreOrderDetail.class).eq(SimpleEntity::getDelFlag, Constants.UNDELETED)
.in(StoreOrderDetail::getStoreOrderId, soIds));
List<Long> spIds = orderDetailList.stream().map(StoreOrderDetail::getStoreProdId).distinct()
.collect(Collectors.toList());
Map<Long, String> mainPicMap = storeProductFileMapper.selectMainPicByStoreProdIdList(spIds,
FileType.MAIN_PIC.getValue(), ORDER_NUM_1).stream()
.collect(Collectors.toMap(StoreProdMainPicDTO::getStoreProdId, StoreProdMainPicDTO::getFileUrl,
(o, n) -> n));
Map<Long, List<StoreOrderPageItemDTO.Detail>> orderDetailGroup = BeanUtil.copyToList(orderDetailList,
StoreOrderPageItemDTO.Detail.class)
.stream()
.collect(Collectors.groupingBy(StoreOrderDetailDTO::getStoreOrderId));
Map<String, ExpressRegion> regionMap = expressService.getRegionMapCache();
for (StoreOrderPageItemDTO order : list) {
//物流信息
order.setDestinationProvinceName(Optional.ofNullable(regionMap.get(order.getDestinationProvinceCode()))
.map(ExpressRegion::getParentRegionName).orElse(null));
order.setDestinationCityName(Optional.ofNullable(regionMap.get(order.getDestinationCityCode()))
.map(ExpressRegion::getParentRegionName).orElse(null));
order.setDestinationCountyName(Optional.ofNullable(regionMap.get(order.getDestinationCountyCode()))
.map(ExpressRegion::getParentRegionName).orElse(null));
order.setOriginProvinceName(Optional.ofNullable(regionMap.get(order.getOriginProvinceCode()))
.map(ExpressRegion::getParentRegionName).orElse(null));
order.setOriginCityName(Optional.ofNullable(regionMap.get(order.getOriginCityCode()))
.map(ExpressRegion::getParentRegionName).orElse(null));
order.setOriginCountyName(Optional.ofNullable(regionMap.get(order.getOriginCountyCode()))
.map(ExpressRegion::getParentRegionName).orElse(null));
order.setOrderDetails(orderDetailGroup.get(order.getId()));
for (StoreOrderPageItemDTO.Detail detail : order.getOrderDetails()) {
//首图
detail.setFirstMainPicUrl(mainPicMap.get(detail.getStoreProdId()));
}
}
}
return page;
}
@Transactional(rollbackFor = Exception.class)
@Override
public StoreOrderExt preparePayOrder(Long storeOrderId) {
Assert.notNull(storeOrderId);
@ -399,7 +458,7 @@ public class StoreOrderServiceImpl implements IStoreOrderService {
return new StoreOrderExt(order, orderDetails);
}
@Transactional
@Transactional(rollbackFor = Exception.class)
@Override
public StoreOrderExt paySuccess(Long storeOrderId, BigDecimal totalAmount, BigDecimal realTotalAmount) {
Assert.notNull(storeOrderId);
@ -451,6 +510,51 @@ public class StoreOrderServiceImpl implements IStoreOrderService {
return new StoreOrderExt(order, orderDetails);
}
@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), "订单不存在");
EOrderStatus oStatus = EOrderStatus.of(order.getOrderStatus());
EPayStatus pStatus = EPayStatus.of(order.getPayStatus());
if (EOrderStatus.PENDING_PAYMENT != oStatus) {
throw new ServiceException("订单[" + order.getOrderNo() + "]状态为[" + oStatus.getLabel() + "],无法取消");
}
if (EPayStatus.PAID == pStatus) {
throw new ServiceException("订单[" + order.getOrderNo() + "]已支付完成,无法取消");
}
//目前只有支付宝
PaymentManager paymentManager = getPaymentManager(EPayChannel.ALI_PAY);
boolean isPaid = paymentManager.isOrderPaid(order.getOrderNo());
if (isPaid) {
throw new ServiceException("订单[" + order.getOrderNo() + "]已支付,无法取消");
}
//订单已取消
order.setOrderStatus(EOrderStatus.CANCELLED.getValue());
int orderSuccess = storeOrderMapper.updateById(order);
if (orderSuccess == 0) {
throw new ServiceException(Constants.VERSION_LOCK_ERROR_COMMON_MSG);
}
List<StoreOrderDetail> orderDetails = storeOrderDetailMapper.selectList(
Wrappers.lambdaQuery(StoreOrderDetail.class)
.eq(StoreOrderDetail::getStoreOrderId, order.getId())
.eq(SimpleEntity::getDelFlag, Constants.UNDELETED));
List<Long> orderDetailIdList = new ArrayList<>(orderDetails.size());
for (StoreOrderDetail orderDetail : orderDetails) {
//明细已取消
orderDetail.setDetailStatus(EOrderStatus.CANCELLED.getValue());
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.CANCEL, orderDetailIdList, EOrderAction.CANCEL,
opt.getOperatorId(), new Date());
}
private void checkPreparePayStatus(Integer payStatus) {
if (!EPayStatus.INIT.getValue().equals(payStatus) && !EPayStatus.PAYING.getValue().equals(payStatus)) {
throw new ServiceException("订单状态异常无法发起支付");

View File

@ -2,4 +2,52 @@
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.ruoyi.xkt.mapper.StoreOrderMapper">
<select id="listStoreOrderPageItem" parameterType="com.ruoyi.xkt.dto.order.StoreOrderQueryDTO"
resultType="com.ruoyi.xkt.dto.order.StoreOrderPageItemDTO">
SELECT
so.*,
s.store_name,
s.brand_name,
e.express_name
FROM
store_order so
LEFT JOIN store s ON so.store_id = s.id
LEFT JOIN express e ON so.express_id = e.id
<where>
so.del_flag = '0'
<if test="storeId != null">
AND so.store_id = #{storeId}
</if>
<if test="orderUserId != null">
AND so.order_user_id = #{orderUserId}
</if>
<if test="orderNo != null and orderNo !=''">
AND so.order_no LIKE CONCAT('%', #{orderNo}, '%')
</if>
<if test="orderStatus != null">
AND so.order_status = #{orderStatus}
</if>
<if test="destinationContactName != null and destinationContactName !=''">
AND so.destination_contact_name LIKE CONCAT('%', #{destinationContactName}, '%')
</if>
<if test="destinationContactPhoneNumber != null and destinationContactPhoneNumber !=''">
AND so.destination_contact_phone_number LIKE CONCAT('%', #{destinationContactPhoneNumber}, '%')
</if>
<if test="deliveryType != null">
AND so.delivery_type = #{deliveryType}
</if>
<if test="orderTimeBegin != null and orderTimeEnd != null">
AND EXISTS (SELECT 1 FROM store_order_operation_record r WHERE r.target_type = 1 AND r.target_id = so.id AND r.action = 1 AND r.operation_time BETWEEN #{orderTimeBegin} AND #{orderTimeEnd})
</if>
<if test="payTimeBegin != null and payTimeEnd != null">
AND EXISTS (SELECT 1 FROM store_order_operation_record r WHERE r.target_type = 1 AND r.target_id = so.id AND r.action = 4 AND r.operation_time BETWEEN #{payTimeBegin} AND #{payTimeEnd})
</if>
<if test="expressWaybillNo != null and expressWaybillNo !=''">
AND EXISTS (SELECT 1 FROM store_order_detail sod WHERE sod.store_order_id = so.id AND sod.del_flag = '0' AND sod.express_waybill_no LIKE CONCAT('%', #{expressWaybillNo}, '%'))
</if>
<if test="prodArtNum != null and prodArtNum !=''">
AND EXISTS (SELECT 1 FROM store_order_detail sod WHERE sod.store_order_id = so.id AND sod.del_flag = '0' AND sod.prod_art_num LIKE CONCAT('%', #{prodArtNum}, '%'))
</if>
</where>
</select>
</mapper>