Browse Source

对接拼团数据

master
wangfukang 1 week ago
parent
commit
81b875d41e
  1. 6
      hiver-core/src/main/java/cc/hiver/core/serviceimpl/WorkerServiceImpl.java
  2. 40
      hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/controller/MallDeliveryOrderController.java
  3. 14
      hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/controller/MallOrderController.java
  4. 43
      hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/controller/MallRefundRecordController.java
  5. 247
      hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/controller/WechatPayController.java
  6. 8
      hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/dao/mapper/MallDeliveryOrderMapper.java
  7. 13
      hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/dao/mapper/MallReturnOrderGoodsMapper.java
  8. 26
      hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/entity/MallDeliveryOrder.java
  9. 6
      hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/entity/MallOrder.java
  10. 2
      hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/entity/MallOrderGoods.java
  11. 13
      hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/entity/MallRefundRecord.java
  12. 4
      hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/pojo/dto/CreateOrderDTO.java
  13. 6
      hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/pojo/query/MallOrderPageQuery.java
  14. 14
      hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/service/mybatis/MallDeliveryOrderService.java
  15. 5
      hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/service/mybatis/MallOrderService.java
  16. 2
      hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/service/mybatis/MallRefundRecordService.java
  17. 4
      hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/serviceimpl/UnifiedOrderService.java
  18. 75
      hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/serviceimpl/mybatis/MallDeliveryOrderServiceImpl.java
  19. 41
      hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/serviceimpl/mybatis/MallOrderGroupServiceImpl.java
  20. 76
      hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/serviceimpl/mybatis/MallOrderServiceImpl.java
  21. 35
      hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/serviceimpl/mybatis/MallRefundRecordServiceImpl.java
  22. 25
      hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/utils/KeyUtils.java
  23. 2
      hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/utils/WechatPayConfig.java
  24. 4
      hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/utils/WechatPaySigner.java
  25. 92
      hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/utils/WechatPayUtil.java
  26. 63
      hiver-modules/hiver-mall/src/main/resources/mapper/MallDeliveryOrderMapper.xml
  27. 5
      hiver-modules/hiver-mall/src/main/resources/mapper/MallOrderGoodsMapper.xml
  28. 41
      hiver-modules/hiver-mall/src/main/resources/mapper/MallOrderMapper.xml
  29. 3
      hiver-modules/hiver-mall/src/main/resources/mapper/MallRefundRecordMapper.xml
  30. 8
      hiver-modules/hiver-mall/src/main/resources/mapper/WorkerRelaPriceMapper.xml
  31. 129
      hiver-modules/hiver-social/src/main/java/cc/hiver/social/controller/WechatPayController.java

6
hiver-core/src/main/java/cc/hiver/core/serviceimpl/WorkerServiceImpl.java

@ -65,7 +65,7 @@ public class WorkerServiceImpl implements WorkerService {
final Path<Integer> workerStatusField = root.get("workerStatus"); final Path<Integer> workerStatusField = root.get("workerStatus");
final Path<String> mobileField = root.get("mobile"); final Path<String> mobileField = root.get("mobile");
final Path<Date> createTimeField = root.get("createTime"); final Path<Date> createTimeField = root.get("createTime");
final Path<Date> signPersonField = root.get("signPerson"); //final Path<Date> signPersonField = root.get("signPerson");
final Path<String> isOnLineField = root.get("isOnLine"); final Path<String> isOnLineField = root.get("isOnLine");
final Path<String> userIdField = root.get("userId"); final Path<String> userIdField = root.get("userId");
@ -80,9 +80,9 @@ public class WorkerServiceImpl implements WorkerService {
list.add(cb.equal(userIdField, worker.getUserId())); list.add(cb.equal(userIdField, worker.getUserId()));
} }
if (CharSequenceUtil.isNotBlank(worker.getSignPerson())) { /*if (CharSequenceUtil.isNotBlank(worker.getSignPerson())) {
list.add(cb.equal(signPersonField, worker.getSignPerson())); list.add(cb.equal(signPersonField, worker.getSignPerson()));
} }*/
// 模糊搜素 // 模糊搜素
if (CharSequenceUtil.isNotBlank(worker.getWorkerName())) { if (CharSequenceUtil.isNotBlank(worker.getWorkerName())) {
list.add(cb.like(workerNameField, '%' + worker.getWorkerName() + '%')); list.add(cb.like(workerNameField, '%' + worker.getWorkerName() + '%'));

40
hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/controller/MallDeliveryOrderController.java

@ -19,6 +19,8 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.util.List;
import java.util.Map;
/** /**
* 配送订单接口 * 配送订单接口
@ -101,13 +103,25 @@ public class MallDeliveryOrderController {
return new ResultUtil<Object>().setData(mallDeliveryOrderService.pageDelivery(q)); return new ResultUtil<Object>().setData(mallDeliveryOrderService.pageDelivery(q));
} }
@PostMapping("/countOrderByStatus")
@ApiOperation(value = "查询当前配送员指派单和已接单数量")
public Result<List<Map<Integer, Integer>>> countOrderByStatus(@RequestParam String workerId) {
return new ResultUtil<List<Map<Integer, Integer>>>().setData(mallDeliveryOrderService.countOrdersByStatus(workerId));
}
@PostMapping("/pagebyworker")
@ApiOperation(value = "分页查询配送员配送单")
public Result<Object> pageByWorker(@RequestBody MallDeliveryOrderPageQuery q) {
return new ResultUtil<Object>().setData(mallDeliveryOrderService.pageDeliveryByStatus(q));
}
/** /**
* 配送员接单 * 配送员接单
*/ */
@PostMapping("/accept") @PostMapping("/accept")
@ApiOperation(value = "配送员接单", notes = "抢单大厅单或指派单均通过此接口接单") @ApiOperation(value = "配送员接单", notes = "抢单大厅单或指派单均通过此接口接单")
public Result accept(@RequestParam String deliveryId, public Result accept(@RequestParam String deliveryId,
@RequestParam String workerId,@RequestParam String regionId,@RequestParam String groupId) { @RequestParam String workerId,@RequestParam String workerName,@RequestParam String regionId,@RequestParam String groupId) {
try { try {
if(StrUtil.isBlank(workerId)){ if(StrUtil.isBlank(workerId)){
//当前人没有注册兼职,先赋予兼职身份 //当前人没有注册兼职,先赋予兼职身份
@ -123,7 +137,7 @@ public class MallDeliveryOrderController {
worker.setScore(BigDecimal.valueOf(5)); worker.setScore(BigDecimal.valueOf(5));
workerService.save(worker); workerService.save(worker);
} }
Integer result = mallDeliveryOrderService.workerAccept(deliveryId, workerId,groupId); Integer result = mallDeliveryOrderService.workerAccept(deliveryId, workerId,workerName,groupId);
if(result == 0){ if(result == 0){
return ResultUtil.success("配送单不存在"); return ResultUtil.success("配送单不存在");
}else if (result == 1){ }else if (result == 1){
@ -134,7 +148,7 @@ public class MallDeliveryOrderController {
return ResultUtil.success("接单成功"); return ResultUtil.success("接单成功");
} }
}else{ }else{
Integer result = mallDeliveryOrderService.workerAccept(deliveryId, workerId,groupId); Integer result = mallDeliveryOrderService.workerAccept(deliveryId, workerId,workerName,groupId);
if(result == 0){ if(result == 0){
return ResultUtil.success("配送单不存在"); return ResultUtil.success("配送单不存在");
}else if (result == 1){ }else if (result == 1){
@ -151,6 +165,22 @@ public class MallDeliveryOrderController {
} }
} }
/**
* 配送员到店
*/
@PostMapping("/arriveShop")
@ApiOperation("配送员到店)")
public Result arriveShop(@RequestParam String deliveryId,
@RequestParam String workerId) {
try {
mallDeliveryOrderService.arriveShop(deliveryId, workerId);
return ResultUtil.success("到店成功");
} catch (Exception e) {
log.error("到店失败: {}", e.getMessage(), e);
return ResultUtil.error(e.getMessage());
}
}
/** /**
* 配送员取货 * 配送员取货
*/ */
@ -160,7 +190,7 @@ public class MallDeliveryOrderController {
@RequestParam String workerId) { @RequestParam String workerId) {
try { try {
mallDeliveryOrderService.workerPickup(deliveryId, workerId); mallDeliveryOrderService.workerPickup(deliveryId, workerId);
return ResultUtil.success("已取货,配送中"); return ResultUtil.success("取货成功");
} catch (Exception e) { } catch (Exception e) {
log.error("取货失败: {}", e.getMessage(), e); log.error("取货失败: {}", e.getMessage(), e);
return ResultUtil.error(e.getMessage()); return ResultUtil.error(e.getMessage());
@ -176,7 +206,7 @@ public class MallDeliveryOrderController {
@RequestParam String workerId) { @RequestParam String workerId) {
try { try {
mallDeliveryOrderService.workerComplete(deliveryId, workerId); mallDeliveryOrderService.workerComplete(deliveryId, workerId);
return ResultUtil.success("送达"); return ResultUtil.success("送达成功");
} catch (Exception e) { } catch (Exception e) {
log.error("送达操作失败: {}", e.getMessage(), e); log.error("送达操作失败: {}", e.getMessage(), e);
return ResultUtil.error(e.getMessage()); return ResultUtil.error(e.getMessage());

14
hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/controller/MallOrderController.java

@ -93,14 +93,14 @@ public class MallOrderController {
/** /**
* 商家接单 * 商家接单
*/ */
@PostMapping("/shopAccept") @PostMapping("/shopMakeTime")
@ApiOperation(value = "支付成功商家自动接单", notes = "将订单从「待商家接单」推进到下一状态") @ApiOperation(value = "商家出餐")
public Result shopAccept(@ApiParam("订单ID") @RequestParam String orderId) { public Result shopMakeTime(@ApiParam("订单ID") @RequestParam String orderId) {
try { try {
mallOrderService.shopAccept(orderId); mallOrderService.shopMakeTime(orderId);
return ResultUtil.success("接单成功"); return ResultUtil.success("出餐成功");
} catch (Exception e) { } catch (Exception e) {
log.error("接单失败: {}", e.getMessage(), e); log.error("出餐失败: {}", e.getMessage(), e);
return ResultUtil.error(e.getMessage()); return ResultUtil.error(e.getMessage());
} }
} }
@ -125,7 +125,7 @@ public class MallOrderController {
* 用户取消订单 * 用户取消订单
*/ */
@PostMapping("/cancel") @PostMapping("/cancel")
@ApiOperation(value = "用户取消订单", notes = "仅待支付/待成团状态可取消") @ApiOperation(value = "用户取消订单")
public Result cancelOrder(@RequestParam String orderId, public Result cancelOrder(@RequestParam String orderId,
@RequestParam String userId) { @RequestParam String userId) {
try { try {

43
hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/controller/MallRefundRecordController.java

@ -0,0 +1,43 @@
package cc.hiver.mall.controller;
import cc.hiver.core.common.utils.ResultUtil;
import cc.hiver.core.common.vo.Result;
import cc.hiver.mall.entity.MallRefundRecord;
import cc.hiver.mall.service.mybatis.MallRefundRecordService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* 订单接口
*/
@Slf4j
@RestController
@Api(tags = "订单售后接口")
@RequestMapping("/hiver/mall/refund")
public class MallRefundRecordController {
@Autowired
private MallRefundRecordService mallRefundRecordService;
/**
* 下单普通购买 / 发起拼团 / 参团
*/
@PostMapping("/create")
@ApiOperation(value = "售后提交接口")
public Result create(@RequestBody MallRefundRecord mallRefundRecord) {
try {
mallRefundRecordService.create(mallRefundRecord);
return ResultUtil.success("提交售后成功");
} catch (Exception e) {
log.error("下单失败: {}", e.getMessage(), e);
return ResultUtil.error(e.getMessage());
}
}
}

247
hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/controller/WechatPayController.java

@ -0,0 +1,247 @@
package cc.hiver.mall.controller;
import cc.hiver.mall.entity.MallOrder;
import cc.hiver.mall.service.mybatis.MallOrderService;
import cc.hiver.mall.serviceimpl.UnifiedOrderService;
import cc.hiver.mall.utils.KeyUtils;
import cc.hiver.mall.utils.WechatPayConfig;
import cc.hiver.mall.utils.WechatPaySigner;
import com.fasterxml.jackson.databind.ObjectMapper;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.PostConstruct;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.security.PrivateKey;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
@RestController
@RequestMapping("/hiver/api/wechat/pay")
public class WechatPayController {
private static final Logger log = LoggerFactory.getLogger(WechatPayController.class);
@Autowired
private UnifiedOrderService orderService;
@Autowired
private WechatPayConfig config;
@Autowired
private MallOrderService mallOrderService;
@Autowired
private WechatPaySigner signer;
@Autowired
private ResourceLoader resourceLoader;
private PrivateKey privateKey;
private final OkHttpClient httpClient = new OkHttpClient();
private final ObjectMapper objectMapper = new ObjectMapper();
@PostConstruct
public void init() throws Exception {
Resource resource = resourceLoader.getResource(config.getPrivateKeyPath());
byte[] keyBytes;
try (InputStream is = resource.getInputStream()) {
keyBytes = readAllBytes(is);
}
String key = new String(keyBytes, StandardCharsets.UTF_8)
.replace("-----BEGIN PRIVATE KEY-----", "")
.replace("-----END PRIVATE KEY-----", "")
.replaceAll("\\s+", "");
byte[] decodedKey = Base64.getDecoder().decode(key);
privateKey = KeyUtils.loadPrivateKey(decodedKey);
}
private byte[] readAllBytes(InputStream inputStream) throws IOException {
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
byte[] data = new byte[1024];
int nRead;
while ((nRead = inputStream.read(data, 0, data.length)) != -1) {
buffer.write(data, 0, nRead);
}
return buffer.toByteArray();
}
@PostMapping("/unified-order")
public ResponseEntity<Map<String, String>> jsapiPay(@RequestBody Map<String, String> request) throws Exception {
String outTradeNo = "ORDER_" + request.get("outTradeNo");
String description = request.get("description");
String openid = request.get("openid");
long amount = Long.parseLong(request.get("amount")); // 单位:分
Map<String, Object> orderResult = orderService.createJsapiOrder(outTradeNo, description, openid, amount);
String prepayId = (String) orderResult.get("prepay_id");
if (prepayId == null) {
Map<String, String> payParams = new HashMap<>();
payParams.put("code","101");
payParams.put("message","调起微信支付失败");
return ResponseEntity.ok(payParams);
}else{
// 2. 生成前端支付参数
Map<String, String> payParams = buildPaySign(prepayId);
payParams.put("code","200");
return ResponseEntity.ok(payParams);
}
}
@PostMapping("/paySuccess")
public ResponseEntity<Map<String, String>> paySuccess(@RequestBody Map<String, String> request) throws Exception {
//订单支付成功逻辑
mallOrderService.paySuccess(request.get("outTradeNo"));
Map<String, String> payParams = new HashMap<>();
payParams.put("code","200");
payParams.put("message","支付成功订单更新");
return ResponseEntity.ok(payParams);
}
public Map<String, String> buildPaySign(String prepayId) throws Exception {
// 1. 生成参数
String timeStamp = String.valueOf(System.currentTimeMillis() / 1000); // 秒
String nonceStr = UUID.randomUUID().toString().replace("-", "").substring(0, 32);
String packageValue = "prepay_id=" + prepayId;
String signType = "RSA";
// 2. 构建签名字符串
String message = String.join("\n",
config.getAppId(),
timeStamp,
nonceStr,
packageValue,
"" // 最后一个 \n
);
// 3. 使用商户私钥签名(和 API v3 同一套私钥)
String paySign = KeyUtils.signWithSha256Rsa(message, privateKey); // ← 复用之前的签名方法
// 4. 返回给前端
Map<String, String> result = new HashMap<>();
result.put("timeStamp", timeStamp);
result.put("nonceStr", nonceStr);
result.put("package", packageValue);
result.put("signType", signType);
result.put("paySign", paySign);
return result;
}
/**
* 微信退款通用方法
* 传入 orderId根据订单信息发起微信支付退款全额退款
*/
@PostMapping("/refund")
public ResponseEntity<Map<String, String>> refund(@RequestBody Map<String, String> request) {
Map<String, String> result = new HashMap<>();
String orderId = request.get("orderId");
try {
// 1. 查询订单信息
MallOrder order = mallOrderService.getById(orderId);
if (order == null) {
result.put("code", "101");
result.put("message", "订单不存在");
return ResponseEntity.ok(result);
}
// 2. 构建退款请求参数
// 原支付交易号(与下单时一致,带 ORDER_ 前缀)
String outTradeNo = "ORDER_" + orderId;
// 退款单号(唯一,使用 REFUND_ + orderId + 时间戳避免重复)
String outRefundNo = "REFUND_" + orderId + "_" + System.currentTimeMillis();
// 订单总金额(元 → 分)
long totalFee = order.getTotalAmount()
.multiply(new java.math.BigDecimal("100"))
.longValue();
// 退款金额(默认全额退款,如果前端传了 refundAmount 则使用前端的值)
long refundFee = totalFee;
if (request.get("refundAmount") != null) {
refundFee = new java.math.BigDecimal(request.get("refundAmount"))
.multiply(new java.math.BigDecimal("100"))
.longValue();
}
// 退款原因
String reason = request.get("reason") != null ? request.get("reason") : "订单退款";
// 3. 构建请求 Body
Map<String, Object> reqBody = new HashMap<>();
reqBody.put("out_trade_no", outTradeNo);
reqBody.put("out_refund_no", outRefundNo);
reqBody.put("reason", reason);
Map<String, Object> amountMap = new HashMap<>();
amountMap.put("refund", refundFee);
amountMap.put("total", totalFee);
amountMap.put("currency", "CNY");
reqBody.put("amount", amountMap);
String jsonBody = objectMapper.writeValueAsString(reqBody);
// 4. 签名并调用微信退款 API
String refundUrl = WechatPayConfig.REFUND_URL;
String authorization = signer.sign("POST", refundUrl, jsonBody);
// 【修改点】使用标准的 create 方法,参数顺序是 (MediaType, String)
okhttp3.RequestBody body = okhttp3.RequestBody.create(
MediaType.parse("application/json; charset=utf-8"),
jsonBody
);
Request httpRequest = new Request.Builder()
.url(refundUrl)
.post(body)
.addHeader("Authorization", "WECHATPAY2-SHA256-RSA2048 " + authorization)
.addHeader("Content-Type", "application/json")
.addHeader("Accept", "application/json")
.addHeader("User-Agent", "MyApp/1.0")
.build();
try (Response response = httpClient.newCall(httpRequest).execute()) {
String responseBody = response.body() != null ? response.body().string() : "";
if (response.isSuccessful()) {
// 退款申请成功(注意:微信退款是异步的,此处只表示申请提交成功)
log.info("微信退款申请成功, orderId={}, outRefundNo={}, response={}", orderId, outRefundNo, responseBody);
result.put("code", "200");
result.put("message", "退款申请成功");
result.put("outRefundNo", outRefundNo);
result.put("refundResponse", responseBody);
} else {
log.error("微信退款申请失败, orderId={}, httpCode={}, response={}", orderId, response.code(), responseBody);
result.put("code", "102");
result.put("message", "微信退款申请失败: " + responseBody);
}
}
} catch (Exception e) {
log.error("微信退款异常, orderId={}", orderId, e);
result.put("code", "500");
result.put("message", "退款异常: " + e.getMessage());
}
return ResponseEntity.ok(result);
}
}

8
hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/dao/mapper/MallDeliveryOrderMapper.java

@ -21,10 +21,18 @@ public interface MallDeliveryOrderMapper extends BaseMapper<MallDeliveryOrder> {
*/ */
IPage<MallDeliveryOrder> selectPageVO(IPage<?> page, @Param("q") MallDeliveryOrderPageQuery q); IPage<MallDeliveryOrder> selectPageVO(IPage<?> page, @Param("q") MallDeliveryOrderPageQuery q);
/**
* 分页查询配送单
*/
IPage<MallDeliveryOrder> selectPageVOByStatus(IPage<?> page, @Param("q") MallDeliveryOrderPageQuery q);
/** /**
* 统计配送员当前活跃单量待取货+配送中 * 统计配送员当前活跃单量待取货+配送中
*/ */
Map<String, Integer> countActiveOrdersByWorker(@Param("workerId") String workerId); Map<String, Integer> countActiveOrdersByWorker(@Param("workerId") String workerId);
List<Map<Integer, Integer>> countOrdersByType(@Param("regionId") String regionId); List<Map<Integer, Integer>> countOrdersByType(@Param("regionId") String regionId);
List<Map<Integer, Integer>> countOrdersByStatus(@Param("workerId") String workerId);
} }

13
hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/dao/mapper/MallReturnOrderGoodsMapper.java

@ -0,0 +1,13 @@
package cc.hiver.mall.dao.mapper;
import cc.hiver.mall.entity.MallReturnOrderGoods;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.springframework.stereotype.Repository;
/**
* 订单商品详情 Mapper 接口
*/
@Repository
public interface MallReturnOrderGoodsMapper extends BaseMapper<MallReturnOrderGoods> {
}

26
hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/entity/MallDeliveryOrder.java

@ -1,6 +1,7 @@
package cc.hiver.mall.entity; package cc.hiver.mall.entity;
import cc.hiver.core.common.utils.SnowFlakeUtil; import cc.hiver.core.common.utils.SnowFlakeUtil;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName; import com.baomidou.mybatisplus.annotation.TableName;
import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModel;
@ -10,9 +11,11 @@ import lombok.Data;
import javax.persistence.Entity; import javax.persistence.Entity;
import javax.persistence.Id; import javax.persistence.Id;
import javax.persistence.Table; import javax.persistence.Table;
import javax.persistence.Transient;
import java.io.Serializable; import java.io.Serializable;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.util.Date; import java.util.Date;
import java.util.List;
@Data @Data
@Entity @Entity
@ -30,6 +33,8 @@ public class MallDeliveryOrder implements Serializable {
private String groupId; private String groupId;
@ApiModelProperty(value = "配送员ID") @ApiModelProperty(value = "配送员ID")
private String workerId; private String workerId;
@ApiModelProperty(value = "配送员名称")
private String workerName;
@ApiModelProperty(value = "店铺ID") @ApiModelProperty(value = "店铺ID")
private String shopId; private String shopId;
@ApiModelProperty(value = "取货区域ID(订单商家的所在区域id)") @ApiModelProperty(value = "取货区域ID(订单商家的所在区域id)")
@ -40,7 +45,7 @@ public class MallDeliveryOrder implements Serializable {
private BigDecimal deliveryFee; private BigDecimal deliveryFee;
@ApiModelProperty(value = "平台额外佣金(接收的指派单才有)") @ApiModelProperty(value = "平台额外佣金(接收的指派单才有)")
private BigDecimal deliveryFeeMarketplace; private BigDecimal deliveryFeeMarketplace;
@ApiModelProperty(value = "配送状态 0:待接单 1:待取货 2:配送中 3:已送达 4:已取消") @ApiModelProperty(value = "配送状态 -1:待激活 0:待接单 1:待取货 2:配送中 3:已送达 4:已取消 5:待售后")
private Integer status; private Integer status;
@ApiModelProperty(value = "收货人姓名(快照)") @ApiModelProperty(value = "收货人姓名(快照)")
private String receiverName; private String receiverName;
@ -66,10 +71,29 @@ public class MallDeliveryOrder implements Serializable {
private Date getTime; private Date getTime;
@ApiModelProperty(value = "客户要求送达时间") @ApiModelProperty(value = "客户要求送达时间")
private Date mustFinishTime; private Date mustFinishTime;
@ApiModelProperty(value = "到店时间")
private Date arriveTime;
@ApiModelProperty(value = "送达时间") @ApiModelProperty(value = "送达时间")
private Date finishTime; private Date finishTime;
@ApiModelProperty(value = "订单类型 1:外卖 2:快递 3 跑腿") @ApiModelProperty(value = "订单类型 1:外卖 2:快递 3 跑腿")
private Integer deliveryType; private Integer deliveryType;
@ApiModelProperty(value = "商家-订单序号") @ApiModelProperty(value = "商家-订单序号")
private String numberCode; private String numberCode;
@ApiModelProperty(value = "总件数")
private Integer allCount;
@ApiModelProperty(value = "是否超重/超大 0不是 1是")
private Integer isBig;
@ApiModelProperty(value = "是否退款中 0不是 1是")
private Integer isReturn;
@ApiModelProperty(value = "手机号尾号")
private String phoneNumber;
@ApiModelProperty(value = "取件码 , 分割")
private String getCodes;
@ApiModelProperty(value = "取件码图片 , 分割")
private String getPictures;
@Transient
@TableField(exist = false)
@ApiModelProperty(value = "商品信息")
private List<MallOrderGoods> goodsList;
} }

6
hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/entity/MallOrder.java

@ -33,8 +33,10 @@ public class MallOrder implements Serializable {
private Integer orderType; private Integer orderType;
@ApiModelProperty(value = "配送方式 1:外卖配送 2:到店自取") @ApiModelProperty(value = "配送方式 1:外卖配送 2:到店自取")
private Integer deliveryType; private Integer deliveryType;
@ApiModelProperty(value = "订单状态 0:待支付 1:待商家接单 10:待成团 2待配送员接单 3:待取货(配送)/待消费(自取) 4:配送中 5:已完成 6:已取消 7:待商家同意退款 8:已退款") @ApiModelProperty(value = "订单状态 0:待支付 1:待商家接单 10:待成团 2待配送员接单 3:待取货(配送)/待消费(自取) 4:配送中 5:已完成 6:已取消 7:待商家同意退款 8:已退款 11: 售后中 售后处理后还变成4")
private Integer status; private Integer status;
@ApiModelProperty(value = "结算状态 0 未结算 1已结算")
private Integer settlementStatus;
@ApiModelProperty(value = "商家-订单序号") @ApiModelProperty(value = "商家-订单序号")
private String numberCode; private String numberCode;
@ApiModelProperty(value = "订单总金额(包含运费打包费等)") @ApiModelProperty(value = "订单总金额(包含运费打包费等)")
@ -69,6 +71,8 @@ public class MallOrder implements Serializable {
private Date createTime; private Date createTime;
@ApiModelProperty(value = "支付时间") @ApiModelProperty(value = "支付时间")
private Date payTime; private Date payTime;
@ApiModelProperty(value = "商家出餐时间")
private Date shopMakeTime;
@ApiModelProperty(value = "学校id") @ApiModelProperty(value = "学校id")
private String regionId; private String regionId;
} }

2
hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/entity/MallOrderGoods.java

@ -36,6 +36,8 @@ public class MallOrderGoods implements Serializable {
private String specs; private String specs;
@ApiModelProperty(value = "商品单价") @ApiModelProperty(value = "商品单价")
private BigDecimal price; private BigDecimal price;
@ApiModelProperty(value = "商品餐盒费")
private BigDecimal packageFee;
@ApiModelProperty(value = "商品数量") @ApiModelProperty(value = "商品数量")
private Integer quantity; private Integer quantity;
} }

13
hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/entity/MallRefundRecord.java

@ -10,9 +10,11 @@ import lombok.Data;
import javax.persistence.Entity; import javax.persistence.Entity;
import javax.persistence.Id; import javax.persistence.Id;
import javax.persistence.Table; import javax.persistence.Table;
import javax.persistence.Transient;
import java.io.Serializable; import java.io.Serializable;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.util.Date; import java.util.Date;
import java.util.List;
@Data @Data
@Entity @Entity
@ -31,10 +33,19 @@ public class MallRefundRecord implements Serializable {
private BigDecimal refundAmount; private BigDecimal refundAmount;
@ApiModelProperty(value = "退款原因") @ApiModelProperty(value = "退款原因")
private String reason; private String reason;
@ApiModelProperty(value = "退款状态 0:待商家同意 1:退款成功 2:商家拒绝退款") @ApiModelProperty(value = "退款图片")
private String pictures;
@ApiModelProperty(value = "退款状态 0:退款处理中 1:退款成功 2:商家拒绝退款 退款失败 3售后中 4已售后 5 拒绝售后 6 商家拒绝售后 7 配送员拒绝售后")
private Integer status; private Integer status;
@ApiModelProperty(value = "退款类型 1 退商品 2退配送费 3 全额退款")
private Integer refundType;
@ApiModelProperty(value = "全额退款类型 1 商家原因 2 配送原因 3 两者都有 4 平台退款")
private Integer refundTypeStatus;
@ApiModelProperty(value = "创建时间") @ApiModelProperty(value = "创建时间")
private Date createTime; private Date createTime;
@ApiModelProperty(value = "退款成功时间") @ApiModelProperty(value = "退款成功时间")
private Date successTime; private Date successTime;
@ApiModelProperty("售后商品列表")
@Transient
private List<MallReturnOrderGoods> items;
} }

4
hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/pojo/dto/CreateOrderDTO.java

@ -72,6 +72,8 @@ public class CreateOrderDTO {
private String specs; private String specs;
@ApiModelProperty(value = "下单价格(以此为准,由前端传入规格对应价格)", required = true) @ApiModelProperty(value = "下单价格(以此为准,由前端传入规格对应价格)", required = true)
private BigDecimal price; private BigDecimal price;
@ApiModelProperty(value = "餐盒费(以此为准,由前端传入规格对应价格)")
private BigDecimal packageFee;
@ApiModelProperty(value = "购买数量", required = true) @ApiModelProperty(value = "购买数量", required = true)
private Integer quantity; private Integer quantity;
@ApiModelProperty(value = "是否是拼团商品", required = false) @ApiModelProperty(value = "是否是拼团商品", required = false)
@ -94,6 +96,8 @@ public class CreateOrderDTO {
public static class WorkerParam { public static class WorkerParam {
@ApiModelProperty(value = "配送员ID", required = true) @ApiModelProperty(value = "配送员ID", required = true)
private String workerId; private String workerId;
@ApiModelProperty(value = "配送员名称", required = true)
private String workerName;
@ApiModelProperty(value = "配送员规则佣金 orderBkge", required = true) @ApiModelProperty(value = "配送员规则佣金 orderBkge", required = true)
private BigDecimal orderBkge; private BigDecimal orderBkge;
} }

6
hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/pojo/query/MallOrderPageQuery.java

@ -18,6 +18,9 @@ public class MallOrderPageQuery extends HiverBasePageQuery {
@ApiModelProperty("店铺ID") @ApiModelProperty("店铺ID")
private String shopId; private String shopId;
@ApiModelProperty("店铺名称")
private String shopName;
@ApiModelProperty("学校ID") @ApiModelProperty("学校ID")
private String regionId; private String regionId;
@ -33,6 +36,9 @@ public class MallOrderPageQuery extends HiverBasePageQuery {
@ApiModelProperty("订单类型 0:不区分 1:饭团 2:跑腿/快递 3:二手") @ApiModelProperty("订单类型 0:不区分 1:饭团 2:跑腿/快递 3:二手")
private Integer searchType; private Integer searchType;
@ApiModelProperty("订单状态 0:待支付 1:待成团 2:待消费 3:待接单4:待取货 5:待送达 6:已完成 7:待商家同意退款 8:已退款 9:已取消")
private Integer searchStatus;
@ApiModelProperty("拼团ID") @ApiModelProperty("拼团ID")
private String groupId; private String groupId;

14
hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/service/mybatis/MallDeliveryOrderService.java

@ -18,16 +18,26 @@ public interface MallDeliveryOrderService extends IService<MallDeliveryOrder> {
*/ */
IPage<MallDeliveryOrder> pageDelivery(MallDeliveryOrderPageQuery q); IPage<MallDeliveryOrder> pageDelivery(MallDeliveryOrderPageQuery q);
/**
* 分页查询配送员的配送单
*/
IPage<MallDeliveryOrder> pageDeliveryByStatus(MallDeliveryOrderPageQuery q);
/** /**
* 配送员接单抢单大厅或指派单 * 配送员接单抢单大厅或指派单
*/ */
Integer workerAccept(String deliveryId, String workerId,String groupId); Integer workerAccept(String deliveryId, String workerId, String workerName,String groupId);
/** /**
* 配送员取货 * 配送员取货
*/ */
void workerPickup(String deliveryId, String workerId); void workerPickup(String deliveryId, String workerId);
/**
* 配送员到带你
*/
void arriveShop(String deliveryId, String workerId);
/** /**
* 配送员送达完成 * 配送员送达完成
*/ */
@ -45,4 +55,6 @@ public interface MallDeliveryOrderService extends IService<MallDeliveryOrder> {
long countWaitGrabOrders(int deliveryType); long countWaitGrabOrders(int deliveryType);
List<Map<Integer, Integer>> countOrdersByType(String regionId); List<Map<Integer, Integer>> countOrdersByType(String regionId);
List<Map<Integer, Integer>> countOrdersByStatus(String workerId);
} }

5
hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/service/mybatis/MallOrderService.java

@ -58,6 +58,11 @@ public interface MallOrderService extends IService<MallOrder> {
*/ */
void agreeRefund(String orderId); void agreeRefund(String orderId);
/**
* 商家出餐
*/
void shopMakeTime(String orderId);
/** /**
* 商家拒绝退款 * 商家拒绝退款
*/ */

2
hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/service/mybatis/MallRefundRecordService.java

@ -7,4 +7,6 @@ import com.baomidou.mybatisplus.extension.service.IService;
* 退款记录 Service 接口 * 退款记录 Service 接口
*/ */
public interface MallRefundRecordService extends IService<MallRefundRecord> { public interface MallRefundRecordService extends IService<MallRefundRecord> {
void create(MallRefundRecord mallRefundRecord);
} }

4
hiver-modules/hiver-social/src/main/java/cc/hiver/social/controller/UnifiedOrderService.java → hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/serviceimpl/UnifiedOrderService.java

@ -1,5 +1,7 @@
package cc.hiver.social.controller; package cc.hiver.mall.serviceimpl;
import cc.hiver.mall.utils.WechatPayConfig;
import cc.hiver.mall.utils.WechatPaySigner;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import okhttp3.*; import okhttp3.*;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;

75
hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/serviceimpl/mybatis/MallDeliveryOrderServiceImpl.java

@ -1,9 +1,11 @@
package cc.hiver.mall.serviceimpl.mybatis; package cc.hiver.mall.serviceimpl.mybatis;
import cc.hiver.mall.dao.mapper.MallDeliveryOrderMapper; import cc.hiver.mall.dao.mapper.MallDeliveryOrderMapper;
import cc.hiver.mall.dao.mapper.MallOrderGoodsMapper;
import cc.hiver.mall.dao.mapper.MallOrderGroupMapper; import cc.hiver.mall.dao.mapper.MallOrderGroupMapper;
import cc.hiver.mall.entity.MallDeliveryOrder; import cc.hiver.mall.entity.MallDeliveryOrder;
import cc.hiver.mall.entity.MallOrder; import cc.hiver.mall.entity.MallOrder;
import cc.hiver.mall.entity.MallOrderGoods;
import cc.hiver.mall.entity.MallOrderGroup; import cc.hiver.mall.entity.MallOrderGroup;
import cc.hiver.mall.pojo.query.MallDeliveryOrderPageQuery; import cc.hiver.mall.pojo.query.MallDeliveryOrderPageQuery;
import cc.hiver.mall.service.mybatis.MallDeliveryOrderService; import cc.hiver.mall.service.mybatis.MallDeliveryOrderService;
@ -45,6 +47,7 @@ public class MallDeliveryOrderServiceImpl extends ServiceImpl<MallDeliveryOrderM
private static final int ORDER_STATUS_WAIT_DELIVERY = 2; // 待配送员接单 private static final int ORDER_STATUS_WAIT_DELIVERY = 2; // 待配送员接单
private static final int ORDER_STATUS_DELIVERING = 4; // 配送中 private static final int ORDER_STATUS_DELIVERING = 4; // 配送中
private static final int ORDER_STATUS_DONE = 5; // 已完成 private static final int ORDER_STATUS_DONE = 5; // 已完成
private static final int ORDER_STATUS_RETURN = 7; // 已完成
@Autowired @Autowired
@Lazy @Lazy
@ -53,6 +56,8 @@ public class MallDeliveryOrderServiceImpl extends ServiceImpl<MallDeliveryOrderM
@Autowired @Autowired
private MallOrderGroupMapper mallOrderGroupMapper; private MallOrderGroupMapper mallOrderGroupMapper;
@Autowired
private MallOrderGoodsMapper mallOrderGoodsMapper;
@Autowired @Autowired
private MerchantOrderSeqUtil merchantOrderSeqUtil; private MerchantOrderSeqUtil merchantOrderSeqUtil;
@ -70,10 +75,57 @@ public class MallDeliveryOrderServiceImpl extends ServiceImpl<MallDeliveryOrderM
page.setCurrent(actualPage); page.setCurrent(actualPage);
page = this.baseMapper.selectPageVO(page, q); page = this.baseMapper.selectPageVO(page, q);
} }
// 批量查询订单商品明细,避免 N+1 问题
List<MallDeliveryOrder> records = page.getRecords();
if (records != null && !records.isEmpty()) {
// 1. 收集所有订单ID
List<String> orderIds = records.stream()
.map(MallDeliveryOrder::getOrderId)
.collect(java.util.stream.Collectors.toList());
// 2. 一次 IN 查询所有商品明细
List<MallOrderGoods> allGoods = mallOrderGoodsMapper.selectByOrderIds(orderIds);
// 3. 按 orderId 分组
java.util.Map<String, List<MallOrderGoods>> goodsMap = allGoods.stream()
.collect(java.util.stream.Collectors.groupingBy(MallOrderGoods::getOrderId));
// 4. 组装到每个 VO
for (MallDeliveryOrder vo : records) {
vo.setGoodsList(goodsMap.getOrDefault(vo.getOrderId(), java.util.Collections.emptyList()));
}
}
return page; return page;
} }
@Override
public IPage<MallDeliveryOrder> pageDeliveryByStatus(MallDeliveryOrderPageQuery q) {
IPage<MallDeliveryOrder> page = new Page<>(q.getPageNum(), q.getPageSize());
page = this.baseMapper.selectPageVOByStatus(page,q);
// 批量查询订单商品明细,避免 N+1 问题
List<MallDeliveryOrder> records = page.getRecords();
if (records != null && !records.isEmpty()) {
// 1. 收集所有订单ID
List<String> orderIds = records.stream()
.map(MallDeliveryOrder::getOrderId)
.collect(java.util.stream.Collectors.toList());
// 2. 一次 IN 查询所有商品明细
List<MallOrderGoods> allGoods = mallOrderGoodsMapper.selectByOrderIds(orderIds);
// 3. 按 orderId 分组
java.util.Map<String, List<MallOrderGoods>> goodsMap = allGoods.stream()
.collect(java.util.stream.Collectors.groupingBy(MallOrderGoods::getOrderId));
// 4. 组装到每个
for (MallDeliveryOrder vo : records) {
vo.setGoodsList(goodsMap.getOrDefault(vo.getOrderId(), java.util.Collections.emptyList()));
}
}
return page;
}
/** /**
* 配送员接单 * 配送员接单
* - 抢单大厅workerId 为空的单任何配送员均可接 * - 抢单大厅workerId 为空的单任何配送员均可接
@ -81,7 +133,7 @@ public class MallDeliveryOrderServiceImpl extends ServiceImpl<MallDeliveryOrderM
*/ */
@Override @Override
@Transactional(rollbackFor = Exception.class) @Transactional(rollbackFor = Exception.class)
public Integer workerAccept(String deliveryId, String workerId,String groupId) { public Integer workerAccept(String deliveryId, String workerId,String workerName, String groupId) {
MallDeliveryOrder delivery = this.getById(deliveryId); MallDeliveryOrder delivery = this.getById(deliveryId);
if (delivery == null) return 0;//throw new RuntimeException("配送单不存在"); if (delivery == null) return 0;//throw new RuntimeException("配送单不存在");
if (delivery.getStatus() != STATUS_WAIT_ACCEPT) return 1;//throw new RuntimeException("配送单已被接取或已取消"); if (delivery.getStatus() != STATUS_WAIT_ACCEPT) return 1;//throw new RuntimeException("配送单已被接取或已取消");
@ -95,7 +147,7 @@ public class MallDeliveryOrderServiceImpl extends ServiceImpl<MallDeliveryOrderM
LambdaUpdateWrapper<MallDeliveryOrder> uw = new LambdaUpdateWrapper<>(); LambdaUpdateWrapper<MallDeliveryOrder> uw = new LambdaUpdateWrapper<>();
uw.eq(MallDeliveryOrder::getId, deliveryId) uw.eq(MallDeliveryOrder::getId, deliveryId)
.set(MallDeliveryOrder::getStatus, STATUS_WAIT_PICKUP) .set(MallDeliveryOrder::getStatus, STATUS_WAIT_PICKUP)
.set(MallDeliveryOrder::getWorkerId, workerId) .set(MallDeliveryOrder::getWorkerId, workerId).set(MallDeliveryOrder::getWorkerName, workerName)
.set(MallDeliveryOrder::getAcceptTime, new Date()); .set(MallDeliveryOrder::getAcceptTime, new Date());
MallOrder order = mallOrderService.getById(delivery.getOrderId()); MallOrder order = mallOrderService.getById(delivery.getOrderId());
@ -176,6 +228,14 @@ public class MallDeliveryOrderServiceImpl extends ServiceImpl<MallDeliveryOrderM
} }
} }
@Override
public void arriveShop(String deliveryId, String workerId) {
LambdaUpdateWrapper<MallDeliveryOrder> uw = new LambdaUpdateWrapper<>();
uw.eq(MallDeliveryOrder::getId, deliveryId)
.set(MallDeliveryOrder::getArriveTime, new Date());
this.update(uw);
}
/** /**
* 配送员送达状态配送中 -> 已送达 * 配送员送达状态配送中 -> 已送达
*/ */
@ -227,6 +287,12 @@ public class MallDeliveryOrderServiceImpl extends ServiceImpl<MallDeliveryOrderM
if (!workerId.equals(delivery.getWorkerId())) { if (!workerId.equals(delivery.getWorkerId())) {
throw new RuntimeException("非本单配送员,无权操作"); throw new RuntimeException("非本单配送员,无权操作");
} }
MallOrder order = mallOrderService.getById(delivery.getOrderId());
if(order != null){
if(order.getStatus() == ORDER_STATUS_RETURN){
throw new RuntimeException("订单申请退款中,无法操作");
}
}
return delivery; return delivery;
} }
@ -243,4 +309,9 @@ public class MallDeliveryOrderServiceImpl extends ServiceImpl<MallDeliveryOrderM
public List<Map<Integer, Integer>> countOrdersByType(String regionId) { public List<Map<Integer, Integer>> countOrdersByType(String regionId) {
return this.baseMapper.countOrdersByType(regionId); return this.baseMapper.countOrdersByType(regionId);
} }
@Override
public List<Map<Integer, Integer>> countOrdersByStatus(String workerId) {
return this.baseMapper.countOrdersByStatus(workerId);
}
} }

41
hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/serviceimpl/mybatis/MallOrderGroupServiceImpl.java

@ -2,14 +2,12 @@ package cc.hiver.mall.serviceimpl.mybatis;
import cc.hiver.core.entity.Worker; import cc.hiver.core.entity.Worker;
import cc.hiver.core.service.WorkerService; import cc.hiver.core.service.WorkerService;
import cc.hiver.mall.dao.mapper.MallDeliveryOrderMapper; import cc.hiver.mall.dao.mapper.*;
import cc.hiver.mall.dao.mapper.MallOrderGroupMapper;
import cc.hiver.mall.dao.mapper.MallRefundRecordMapper;
import cc.hiver.mall.dao.mapper.WorkerRelaPriceMapper;
import cc.hiver.mall.entity.*; import cc.hiver.mall.entity.*;
import cc.hiver.mall.service.mybatis.MallOrderGroupService; import cc.hiver.mall.service.mybatis.MallOrderGroupService;
import cc.hiver.mall.service.mybatis.MallOrderService; import cc.hiver.mall.service.mybatis.MallOrderService;
import cc.hiver.mall.utils.MerchantOrderSeqUtil; import cc.hiver.mall.utils.MerchantOrderSeqUtil;
import cc.hiver.mall.utils.WechatPayUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
@ -20,9 +18,12 @@ import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import java.math.BigDecimal;
import java.sql.Timestamp;
import java.util.Arrays; import java.util.Arrays;
import java.util.Date; import java.util.Date;
import java.util.List; import java.util.List;
import java.util.stream.Collectors;
/** /**
* 拼团主表 Service 实现 * 拼团主表 Service 实现
@ -59,9 +60,21 @@ public class MallOrderGroupServiceImpl extends ServiceImpl<MallOrderGroupMapper,
@Autowired @Autowired
private WorkerService workerService; private WorkerService workerService;
@Autowired
private MallOrderGoodsMapper mallOrderGoodsMapper;
@Autowired
private WechatPayUtil wechatPayUtil;
@Autowired
private ProductMapper productMapper;
@Autowired @Autowired
private WorkerRelaPriceMapper workerRelaPriceMapper; private WorkerRelaPriceMapper workerRelaPriceMapper;
@Autowired
private MallReturnOrderGoodsMapper mallReturnOrderGoodsMapper;
/** /**
* 检查是否成团满足则自动激活所有子订单 * 检查是否成团满足则自动激活所有子订单
*/ */
@ -153,6 +166,8 @@ public class MallOrderGroupServiceImpl extends ServiceImpl<MallOrderGroupMapper,
// 统一修改运单状态为0使其生效 // 统一修改运单状态为0使其生效
delivery.setStatus(0); delivery.setStatus(0);
Date createTime = new Timestamp(System.currentTimeMillis());
delivery.setCreateTime(createTime);
mallDeliveryOrderMapper.updateById(delivery); mallDeliveryOrderMapper.updateById(delivery);
} }
} }
@ -210,6 +225,24 @@ public class MallOrderGroupServiceImpl extends ServiceImpl<MallOrderGroupMapper,
refund.setStatus(0); refund.setStatus(0);
refund.setCreateTime(new Date()); refund.setCreateTime(new Date());
mallRefundRecordMapper.insert(refund); mallRefundRecordMapper.insert(refund);
wechatPayUtil.refund(order.getId(), order.getTotalAmount().multiply(new BigDecimal(100)).longValue());
List<MallOrderGoods> goodsList = mallOrderGoodsMapper.selectByOrderId(order.getId());
if (goodsList == null || goodsList.isEmpty()) return;
List<MallReturnOrderGoods> returnList = goodsList.stream()
.map(goods -> {
// 在这里为每个 MallOrderGoods 对象创建并填充对应的 MallOrderReturnGoods 对象
MallReturnOrderGoods returnGoods = new MallReturnOrderGoods();
returnGoods.setOrderId(refund.getId());
returnGoods.setProductId(goods.getProductId());
returnGoods.setProductName(goods.getProductName());
returnGoods.setProductPicture(goods.getProductPicture());
returnGoods.setSpecs(goods.getSpecs());
returnGoods.setPrice(goods.getPrice());
returnGoods.setQuantity(goods.getQuantity());
mallReturnOrderGoodsMapper.insert(returnGoods);
return returnGoods;
})
.collect(Collectors.toList());
} }
log.info("拼团 {} 已过期,取消 {} 条子订单并生成退款记录", groupId, waitingOrders.size()); log.info("拼团 {} 已过期,取消 {} 条子订单并生成退款记录", groupId, waitingOrders.size());

76
hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/serviceimpl/mybatis/MallOrderServiceImpl.java

@ -5,11 +5,10 @@ import cc.hiver.mall.entity.*;
import cc.hiver.mall.pojo.dto.CreateOrderDTO; import cc.hiver.mall.pojo.dto.CreateOrderDTO;
import cc.hiver.mall.pojo.query.MallOrderPageQuery; import cc.hiver.mall.pojo.query.MallOrderPageQuery;
import cc.hiver.mall.pojo.vo.MallOrderVO; import cc.hiver.mall.pojo.vo.MallOrderVO;
import cc.hiver.mall.service.mybatis.MallDeliveryOrderService;
import cc.hiver.mall.service.mybatis.MallOrderGroupService; import cc.hiver.mall.service.mybatis.MallOrderGroupService;
import cc.hiver.mall.service.mybatis.MallOrderService; import cc.hiver.mall.service.mybatis.MallOrderService;
import cc.hiver.mall.service.mybatis.MallRefundRecordService;
import cc.hiver.mall.utils.MerchantOrderSeqUtil; import cc.hiver.mall.utils.MerchantOrderSeqUtil;
import cc.hiver.mall.utils.WechatPayUtil;
import cn.hutool.json.JSONArray; import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject; import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil; import cn.hutool.json.JSONUtil;
@ -26,6 +25,7 @@ import org.springframework.transaction.annotation.Transactional;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.math.RoundingMode; import java.math.RoundingMode;
import java.sql.Timestamp;
import java.util.*; import java.util.*;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@ -51,6 +51,7 @@ public class MallOrderServiceImpl extends ServiceImpl<MallOrderMapper, MallOrder
// 配送方式常量 // 配送方式常量
private static final int DELIVERY_TYPE_EXPRESS = 1; // 外卖 private static final int DELIVERY_TYPE_EXPRESS = 1; // 外卖
private static final int DELIVERY_TYPE_SELF = 2; // 自取 private static final int DELIVERY_TYPE_SELF = 2; // 自取
private static final int IS_RETURN_EXPRESS = 1; // 外卖
// 订单类型常量 // 订单类型常量
private static final int ORDER_TYPE_NORMAL = 1; // 直接购买 private static final int ORDER_TYPE_NORMAL = 1; // 直接购买
@ -82,13 +83,13 @@ public class MallOrderServiceImpl extends ServiceImpl<MallOrderMapper, MallOrder
private MerchantOrderSeqUtil merchantOrderSeqUtil; private MerchantOrderSeqUtil merchantOrderSeqUtil;
@Autowired @Autowired
private MallDeliveryOrderService mallDeliveryOrderService; private ProductMapper productMapper;
@Autowired @Autowired
private MallRefundRecordService mallRefundRecordService; private WechatPayUtil wechatPayUtil;
@Autowired @Autowired
private ProductMapper productMapper; private MallReturnOrderGoodsMapper mallReturnOrderGoodsMapper;
@Autowired @Autowired
private UserAddressMapper userAddressMapper; private UserAddressMapper userAddressMapper;
@ -135,6 +136,7 @@ public class MallOrderServiceImpl extends ServiceImpl<MallOrderMapper, MallOrder
snapshot.setProductPicture(product.getProductPicture()); snapshot.setProductPicture(product.getProductPicture());
snapshot.setSpecs(item.getSpecs()); snapshot.setSpecs(item.getSpecs());
snapshot.setPrice(item.getPrice()); snapshot.setPrice(item.getPrice());
snapshot.setPackageFee(product.getLunchBox());
snapshot.setQuantity(item.getQuantity()); snapshot.setQuantity(item.getQuantity());
goodsSnapshots.add(snapshot); goodsSnapshots.add(snapshot);
} }
@ -401,9 +403,10 @@ public class MallOrderServiceImpl extends ServiceImpl<MallOrderMapper, MallOrder
if (DELIVERY_TYPE_EXPRESS == order.getDeliveryType()) { if (DELIVERY_TYPE_EXPRESS == order.getDeliveryType()) {
updateOrderStatus(orderId, STATUS_WAIT_DELIVERY); updateOrderStatus(orderId, STATUS_WAIT_DELIVERY);
// 激活配送单,状态改为待接单(0) // 激活配送单,状态改为待接单(0)
Date createTime = new Timestamp(System.currentTimeMillis());
LambdaUpdateWrapper<MallDeliveryOrder> duw = new LambdaUpdateWrapper<>(); LambdaUpdateWrapper<MallDeliveryOrder> duw = new LambdaUpdateWrapper<>();
duw.eq(MallDeliveryOrder::getOrderId, orderId) duw.eq(MallDeliveryOrder::getOrderId, orderId)
.set(MallDeliveryOrder::getStatus, 0); .set(MallDeliveryOrder::getStatus, 0).set(MallDeliveryOrder::getCreateTime, createTime);
mallDeliveryOrderMapper.update(null, duw); mallDeliveryOrderMapper.update(null, duw);
} else { } else {
String latestSeq = merchantOrderSeqUtil.generateOrderSequence(order.getShopId(), 2); String latestSeq = merchantOrderSeqUtil.generateOrderSequence(order.getShopId(), 2);
@ -793,12 +796,28 @@ public class MallOrderServiceImpl extends ServiceImpl<MallOrderMapper, MallOrder
mallRefundRecordMapper.update(null, uw); mallRefundRecordMapper.update(null, uw);
} }
@Override
public void shopMakeTime(String orderId) {
LambdaUpdateWrapper<MallOrder> uw = new LambdaUpdateWrapper<>();
uw.eq(MallOrder::getId, orderId).set(MallOrder::getShopMakeTime,new Date());
this.update(uw);
}
@Override @Override
@Transactional(rollbackFor = Exception.class) @Transactional(rollbackFor = Exception.class)
public void rejectRefund(String orderId, String reason) { public void rejectRefund(String orderId, String reason) {
getAndCheckOrder(orderId, STATUS_WAIT_REFUND); MallOrder order = getAndCheckOrder(orderId, STATUS_WAIT_REFUND);
// 退款拒绝,恢复到已完成(或待商家处理状态) //如果是自取订单,则恢复待消费状态
updateOrderStatus(orderId, STATUS_DONE); if(order.getDeliveryType() == DELIVERY_TYPE_SELF){
updateOrderStatusAndReturn(orderId, STATUS_WAIT_PICKUP);
}else{
MallDeliveryOrder delivery = findDeliveryByOrderId(orderId);
if(delivery.getStatus() == STATUS_WAIT_SHOP){
updateOrderStatusAndReturn(orderId, STATUS_WAIT_PICKUP);
}else if(delivery.getStatus() == DELIVERY_TYPE_SELF){
updateOrderStatusAndReturn(orderId, STATUS_DELIVERING);
}
}
// 更新退款记录为拒绝 // 更新退款记录为拒绝
LambdaUpdateWrapper<MallRefundRecord> uw = new LambdaUpdateWrapper<>(); LambdaUpdateWrapper<MallRefundRecord> uw = new LambdaUpdateWrapper<>();
uw.eq(MallRefundRecord::getOrderId, orderId) uw.eq(MallRefundRecord::getOrderId, orderId)
@ -999,6 +1018,7 @@ public class MallOrderServiceImpl extends ServiceImpl<MallOrderMapper, MallOrder
// 指定配送员 // 指定配送员
if (dto.getWorkerParam() != null && StringUtils.isNotBlank(dto.getWorkerParam().getWorkerId())) { if (dto.getWorkerParam() != null && StringUtils.isNotBlank(dto.getWorkerParam().getWorkerId())) {
delivery.setWorkerId(dto.getWorkerParam().getWorkerId()); delivery.setWorkerId(dto.getWorkerParam().getWorkerId());
delivery.setWorkerName(dto.getWorkerParam().getWorkerName());
if (order.getOrderType() == ORDER_TYPE_NORMAL) { if (order.getOrderType() == ORDER_TYPE_NORMAL) {
BigDecimal bonus = order.getGoodsAmount() BigDecimal bonus = order.getGoodsAmount()
.multiply(new BigDecimal("0.02")) .multiply(new BigDecimal("0.02"))
@ -1078,6 +1098,15 @@ public class MallOrderServiceImpl extends ServiceImpl<MallOrderMapper, MallOrder
this.update(uw); this.update(uw);
} }
/**
* 更新订单状态为商家拒绝退款
*/
private void updateOrderStatusAndReturn(String orderId, int status) {
LambdaUpdateWrapper<MallOrder> uw = new LambdaUpdateWrapper<>();
uw.eq(MallOrder::getId, orderId).set(MallOrder::getStatus, status);
this.update(uw);
}
/** /**
* 获取订单并校验状态 * 获取订单并校验状态
*/ */
@ -1101,6 +1130,8 @@ public class MallOrderServiceImpl extends ServiceImpl<MallOrderMapper, MallOrder
record.setReason(reason); record.setReason(reason);
record.setStatus(0); // 待商家同意 record.setStatus(0); // 待商家同意
record.setCreateTime(new Date()); record.setCreateTime(new Date());
record.setRefundType(3);
record.setRefundTypeStatus(4);
mallRefundRecordMapper.insert(record); mallRefundRecordMapper.insert(record);
} }
@ -1201,7 +1232,27 @@ public class MallOrderServiceImpl extends ServiceImpl<MallOrderMapper, MallOrder
record.setStatus(1); // 退款成功 record.setStatus(1); // 退款成功
record.setCreateTime(new Date()); record.setCreateTime(new Date());
record.setSuccessTime(new Date()); record.setSuccessTime(new Date());
record.setRefundType(3);
record.setRefundTypeStatus(4);
mallRefundRecordMapper.insert(record); mallRefundRecordMapper.insert(record);
wechatPayUtil.refund(order.getId(), order.getTotalAmount().multiply(new BigDecimal(100)).longValue());
List<MallOrderGoods> goodsList = mallOrderGoodsMapper.selectByOrderId(order.getId());
if (goodsList == null || goodsList.isEmpty()) return;
List<MallReturnOrderGoods> returnList = goodsList.stream()
.map(goods -> {
// 在这里为每个 MallOrderGoods 对象创建并填充对应的 MallReturnOrderGoods 对象
MallReturnOrderGoods returnGoods = new MallReturnOrderGoods();
returnGoods.setOrderId(record.getId());
returnGoods.setProductId(goods.getProductId());
returnGoods.setProductName(goods.getProductName());
returnGoods.setProductPicture(goods.getProductPicture());
returnGoods.setSpecs(goods.getSpecs());
returnGoods.setPrice(goods.getPrice());
returnGoods.setQuantity(goods.getQuantity());
mallReturnOrderGoodsMapper.insert(returnGoods);
return returnGoods;
})
.collect(Collectors.toList());
} }
/** /**
@ -1209,6 +1260,13 @@ public class MallOrderServiceImpl extends ServiceImpl<MallOrderMapper, MallOrder
*/ */
private void applyMerchantRefund(MallOrder order, String reason) { private void applyMerchantRefund(MallOrder order, String reason) {
updateOrderStatus(order.getId(), STATUS_WAIT_REFUND); updateOrderStatus(order.getId(), STATUS_WAIT_REFUND);
//如果是外卖,更新配送单状态
if(order.getDeliveryType() == DELIVERY_TYPE_EXPRESS){
LambdaUpdateWrapper<MallDeliveryOrder> duw = new LambdaUpdateWrapper<>();
duw.eq(MallDeliveryOrder::getOrderId, order.getId())
.set(MallDeliveryOrder::getIsReturn, IS_RETURN_EXPRESS);
mallDeliveryOrderMapper.update(null, duw);
}
createRefundRecord(order, order.getTotalAmount(), reason); createRefundRecord(order, order.getTotalAmount(), reason);
} }

35
hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/serviceimpl/mybatis/MallRefundRecordServiceImpl.java

@ -1,15 +1,50 @@
package cc.hiver.mall.serviceimpl.mybatis; package cc.hiver.mall.serviceimpl.mybatis;
import cc.hiver.mall.dao.mapper.MallRefundRecordMapper; import cc.hiver.mall.dao.mapper.MallRefundRecordMapper;
import cc.hiver.mall.dao.mapper.MallReturnOrderGoodsMapper;
import cc.hiver.mall.entity.MallOrder;
import cc.hiver.mall.entity.MallRefundRecord; import cc.hiver.mall.entity.MallRefundRecord;
import cc.hiver.mall.service.mybatis.MallOrderService;
import cc.hiver.mall.service.mybatis.MallRefundRecordService; import cc.hiver.mall.service.mybatis.MallRefundRecordService;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import java.util.Date;
/** /**
* 退款记录 Service 实现 * 退款记录 Service 实现
*/ */
@Service @Service
public class MallRefundRecordServiceImpl extends ServiceImpl<MallRefundRecordMapper, MallRefundRecord> public class MallRefundRecordServiceImpl extends ServiceImpl<MallRefundRecordMapper, MallRefundRecord>
implements MallRefundRecordService { implements MallRefundRecordService {
@Autowired
private MallRefundRecordMapper mallRefundRecordMapper;
@Autowired
private MallReturnOrderGoodsMapper mallReturnOrderGoodsMapper;
@Autowired
private MallOrderService mallOrderService;
@Override
public void create(MallRefundRecord mallRefundRecord) {
//更新订单为 待售后
LambdaUpdateWrapper<MallOrder> oUw = new LambdaUpdateWrapper<>();
oUw.eq(MallOrder::getId, mallRefundRecord.getOrderId())
.set(MallOrder::getStatus, 11);
mallOrderService.update(oUw);
mallRefundRecord.setStatus(3); // 申请售后
mallRefundRecord.setCreateTime(new Date());
mallRefundRecordMapper.insert(mallRefundRecord);
if(!mallRefundRecord.getItems().isEmpty()){
mallRefundRecord.getItems().forEach(item -> {
mallReturnOrderGoodsMapper.insert(item);
});
}
}
} }

25
hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/utils/KeyUtils.java

@ -0,0 +1,25 @@
package cc.hiver.mall.utils;
import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
import org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter;
import java.security.PrivateKey;
import java.security.Signature;
import java.util.Base64;
public class KeyUtils {
public static PrivateKey loadPrivateKey(byte[] keyBytes) throws Exception {
PrivateKeyInfo pkInfo = PrivateKeyInfo.getInstance(keyBytes);
JcaPEMKeyConverter converter = new JcaPEMKeyConverter();
return converter.getPrivateKey(pkInfo);
}
public static String signWithSha256Rsa(String message, PrivateKey privateKey) throws Exception {
Signature sign = Signature.getInstance("SHA256withRSA");
sign.initSign(privateKey);
sign.update(message.getBytes("utf-8"));
byte[] signed = sign.sign();
return Base64.getEncoder().encodeToString(signed);
}
}

2
hiver-modules/hiver-social/src/main/java/cc/hiver/social/controller/WechatPayConfig.java → hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/utils/WechatPayConfig.java

@ -1,4 +1,4 @@
package cc.hiver.social.controller; package cc.hiver.mall.utils;
import org.springframework.beans.factory.annotation.Value; import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;

4
hiver-modules/hiver-social/src/main/java/cc/hiver/social/controller/WechatPaySigner.java → hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/utils/WechatPaySigner.java

@ -1,6 +1,5 @@
package cc.hiver.social.controller; package cc.hiver.mall.utils;
import com.alipay.api.internal.util.file.IOUtils;
import okhttp3.HttpUrl; import okhttp3.HttpUrl;
import org.bouncycastle.jce.provider.BouncyCastleProvider; import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
@ -15,7 +14,6 @@ import java.io.InputStream;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.security.PrivateKey; import java.security.PrivateKey;
import java.security.Security; import java.security.Security;
import java.security.cert.X509Certificate;
import java.util.Base64; import java.util.Base64;
import java.util.UUID; import java.util.UUID;

92
hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/utils/WechatPayUtil.java

@ -0,0 +1,92 @@
package cc.hiver.mall.utils;
import com.fasterxml.jackson.databind.ObjectMapper;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.HashMap;
import java.util.Map;
/**
* 微信支付工具类
*
* @author Yazhi Li
*/
@Component
public class WechatPayUtil {
@Autowired
private WechatPaySigner signer;
private static final Logger log = LoggerFactory.getLogger(WechatPayUtil.class);
private final OkHttpClient httpClient = new OkHttpClient();
private final ObjectMapper objectMapper = new ObjectMapper();
public Boolean refund(String orderId,long totalFee) {
try {
// 2. 构建退款请求参数
// 原支付交易号(与下单时一致,带 ORDER_ 前缀)
String outTradeNo = "ORDER_" + orderId;
// 退款单号(唯一,使用 REFUND_ + orderId + 时间戳避免重复)
String outRefundNo = "REFUND_" + orderId + "_" + System.currentTimeMillis();
// 退款原因
String reason = "订单退款";
// 3. 构建请求 Body
Map<String, Object> reqBody = new HashMap<>();
reqBody.put("out_trade_no", outTradeNo);
reqBody.put("out_refund_no", outRefundNo);
reqBody.put("reason", reason);
Map<String, Object> amountMap = new HashMap<>();
amountMap.put("refund", totalFee);
amountMap.put("total", totalFee);
amountMap.put("currency", "CNY");
reqBody.put("amount", amountMap);
String jsonBody = objectMapper.writeValueAsString(reqBody);
// 4. 签名并调用微信退款 API
String refundUrl = "https://api.mch.weixin.qq.com/v3/refund/domestic/refunds";
String authorization = signer.sign("POST", refundUrl, jsonBody);
// 【修改点】使用标准的 create 方法,参数顺序是 (MediaType, String)
okhttp3.RequestBody body = okhttp3.RequestBody.create(
MediaType.parse("application/json; charset=utf-8"),
jsonBody
);
Request httpRequest = new Request.Builder()
.url(refundUrl)
.post(body)
.addHeader("Authorization", "WECHATPAY2-SHA256-RSA2048 " + authorization)
.addHeader("Content-Type", "application/json")
.addHeader("Accept", "application/json")
.addHeader("User-Agent", "MyApp/1.0")
.build();
try (Response response = httpClient.newCall(httpRequest).execute()) {
String responseBody = response.body() != null ? response.body().string() : "";
if (response.isSuccessful()) {
// 退款申请成功(注意:微信退款是异步的,此处只表示申请提交成功)
log.info("微信退款申请成功, orderId={}, outRefundNo={}, response={}", orderId, outRefundNo, responseBody);
return true;
} else {
log.error("微信退款申请失败, orderId={}, httpCode={}, response={}", orderId, response.code(), responseBody);
return false;
}
}
} catch (Exception e) {
log.error("微信退款异常, orderId={}", orderId, e);
return false;
}
}
}

63
hiver-modules/hiver-mall/src/main/resources/mapper/MallDeliveryOrderMapper.xml

@ -29,6 +29,14 @@
<result column="number_code" property="numberCode"/> <result column="number_code" property="numberCode"/>
<result column="region_id" property="regionId"/> <result column="region_id" property="regionId"/>
<result column="remark" property="remark"/> <result column="remark" property="remark"/>
<result column="all_count" property="allCount"/>
<result column="phone_number" property="phoneNumber"/>
<result column="get_codes" property="getCodes"/>
<result column="get_pictures" property="getPictures"/>
<result column="is_big" property="isBig"/>
<result column="is_return" property="isReturn"/>
<result column="worker_name" property="workerName"/>
<result column="arrive_time" property="arriveTime"/>
</resultMap> </resultMap>
<!-- 分页查询配送单,支持多条件过滤(抢单大厅:hallOnly=true时只查workerId为空的) --> <!-- 分页查询配送单,支持多条件过滤(抢单大厅:hallOnly=true时只查workerId为空的) -->
@ -39,7 +47,8 @@
d.status, d.create_time, d.accept_time, d.get_time, d.must_finish_time, d.finish_time, d.status, d.create_time, d.accept_time, d.get_time, d.must_finish_time, d.finish_time,
d.receiver_name, d.receiver_phone, d.receiver_address, d.receiver_name, d.receiver_phone, d.receiver_address,
d.shop_name, d.shop_phone, d.shop_address, d.delivery_type, d.number_code, d.shop_name, d.shop_phone, d.shop_address, d.delivery_type, d.number_code,
d.region_id,d.remark d.region_id,d.remark, d.all_count, d.phone_number, d.get_codes, d.get_pictures, d.is_big,
d.is_return,d.worker_name, d.arrive_time
FROM mall_delivery_order d FROM mall_delivery_order d
<where> <where>
<if test="q.regionId != null and q.regionId != ''"> <if test="q.regionId != null and q.regionId != ''">
@ -97,6 +106,52 @@
d.must_finish_time ASC,d.delivery_fee DESC d.must_finish_time ASC,d.delivery_fee DESC
</select> </select>
<select id="selectPageVOByStatus" resultMap="deliveryMap">
SELECT
d.id, d.order_id, d.group_id, d.worker_id, d.shop_id,
d.get_area_id, d.put_area_id, d.delivery_fee, d.delivery_fee_marketplace,
d.status, d.create_time, d.accept_time, d.get_time, d.must_finish_time, d.finish_time,
d.receiver_name, d.receiver_phone, d.receiver_address,
d.shop_name, d.shop_phone, d.shop_address, d.delivery_type, d.number_code,
d.region_id,d.remark, d.all_count, d.phone_number, d.get_codes, d.get_pictures, d.is_big,d.is_return,d.worker_name,d.arrive_time
FROM mall_delivery_order d
<where>
d.status not in (-1,4,0)
<if test="q.regionId != null and q.regionId != ''">
AND d.region_id = #{q.regionId}
</if>
<if test="q.workerId != null and q.workerId != ''">
AND d.worker_id = #{q.workerId}
</if>
<if test="q.shopId != null and q.shopId != ''">
AND d.shop_id = #{q.shopId}
</if>
<if test="q.status != null">
AND d.status = #{q.status}
</if>
<if test="q.getAreaId != null and q.getAreaId != ''">
AND d.get_area_id = #{q.getAreaId}
</if>
<if test="q.putAreaId != null and q.putAreaId != ''">
AND d.put_area_id = #{q.putAreaId}
</if>
<if test="q.hallOnly != null and q.hallOnly == true">
AND (d.worker_id IS NULL OR d.worker_id = '')
AND d.status = 0
</if>
<if test="q.startDate != null and q.startDate != ''">
AND DATE(d.create_time) &gt;= #{q.startDate}
</if>
<if test="q.endDate != null and q.endDate != ''">
AND DATE(d.create_time) &lt;= #{q.endDate}
</if>
<if test="q.deliveryType != null">
AND d.delivery_type = #{q.deliveryType}
</if>
</where>
ORDER BY (CASE WHEN d.must_finish_time IS NULL THEN 1 ELSE 0 END) ASC
</select>
<!-- <!--
统计配送员当前活跃单量 统计配送员当前活跃单量
返回:waitPickup(待取货数)、delivering(配送中数) 返回:waitPickup(待取货数)、delivering(配送中数)
@ -116,4 +171,10 @@
WHERE region_id = #{regionId} and worker_id is null and status = 0 group by delivery_type WHERE region_id = #{regionId} and worker_id is null and status = 0 group by delivery_type
</select> </select>
<select id="countOrdersByStatus" resultType="map">
SELECT status ,count(*) as orderCount FROM `mall_delivery_order` where `status` in (0,1,2)
and worker_id = #{workerId} GROUP BY status
</select>
</mapper> </mapper>

5
hiver-modules/hiver-mall/src/main/resources/mapper/MallOrderGoodsMapper.xml

@ -12,18 +12,19 @@
<result column="specs" property="specs"/> <result column="specs" property="specs"/>
<result column="price" property="price"/> <result column="price" property="price"/>
<result column="quantity" property="quantity"/> <result column="quantity" property="quantity"/>
<result column="package_fee" property="packageFee"/>
</resultMap> </resultMap>
<!-- 按单条订单ID查询商品明细 --> <!-- 按单条订单ID查询商品明细 -->
<select id="selectByOrderId" resultMap="goodsMap"> <select id="selectByOrderId" resultMap="goodsMap">
SELECT id, order_id, product_id, product_name, product_picture, specs, price, quantity SELECT id, order_id, product_id, product_name, product_picture, specs, price, quantity, package_fee
FROM mall_order_goods FROM mall_order_goods
WHERE order_id = #{orderId} WHERE order_id = #{orderId}
</select> </select>
<!-- 按多个订单ID批量查询 --> <!-- 按多个订单ID批量查询 -->
<select id="selectByOrderIds" resultMap="goodsMap"> <select id="selectByOrderIds" resultMap="goodsMap">
SELECT id, order_id, product_id, product_name, product_picture, specs, price, quantity SELECT id, order_id, product_id, product_name, product_picture, specs, price, quantity,package_fee
FROM mall_order_goods FROM mall_order_goods
WHERE order_id IN WHERE order_id IN
<foreach collection="orderIds" item="id" open="(" separator="," close=")"> <foreach collection="orderIds" item="id" open="(" separator="," close=")">

41
hiver-modules/hiver-mall/src/main/resources/mapper/MallOrderMapper.xml

@ -27,6 +27,8 @@
<result column="pay_time" property="payTime"/> <result column="pay_time" property="payTime"/>
<result column="number_code" property="numberCode"/> <result column="number_code" property="numberCode"/>
<result column="region_id" property="regionId"/> <result column="region_id" property="regionId"/>
<result column="settlement_status" property="settlementStatus"/>
<result column="shop_make_time" property="shopMakeTime"/>
</resultMap> </resultMap>
<!-- 分页查询订单(不挂载商品明细,由Service层补填) --> <!-- 分页查询订单(不挂载商品明细,由Service层补填) -->
@ -36,12 +38,17 @@
o.status, o.total_amount, o.goods_amount, o.delivery_fee, o.status, o.total_amount, o.goods_amount, o.delivery_fee,
o.package_fee, o.address_id, o.remark, o.create_time, o.pay_time, o.package_fee, o.address_id, o.remark, o.create_time, o.pay_time,
o.receiver_name, o.receiver_phone, o.receiver_address, o.receiver_name, o.receiver_phone, o.receiver_address,
o.shop_name, o.shop_phone, o.shop_address,o.number_code,o.region_id o.shop_name, o.shop_phone, o.shop_address,o.number_code,o.region_id,o.settlement_status,o.shop_make_time
FROM mall_order o FROM mall_order o
<where> <where>
<if test="q.userId != null and q.userId != ''"> <if test="q.userId != null and q.userId != ''">
AND o.user_id = #{q.userId} AND o.user_id = #{q.userId}
</if> </if>
<if test="q.shopName != null and q.shopName != ''">
and (
o.shop_name like concat('%',#{q.shopName},'%')
)
</if>
<if test="q.shopId != null and q.shopId != ''"> <if test="q.shopId != null and q.shopId != ''">
AND o.shop_id = #{q.shopId} AND o.shop_id = #{q.shopId}
</if> </if>
@ -63,6 +70,36 @@
<if test="q.searchType != null and q.searchType == 3"> <if test="q.searchType != null and q.searchType == 3">
AND o.order_type = 6 AND o.order_type = 6
</if> </if>
<if test="q.searchStatus != null and q.searchStatus == 0">
AND o.status = 0
</if>
<if test="q.searchStatus != null and q.searchStatus == 1">
AND o.status = 10
</if>
<if test="q.searchStatus != null and q.searchStatus == 2">
AND o.status = 3 and o.delivery_type = 2
</if>
<if test="q.searchStatus != null and q.searchStatus == 3">
AND o.status = 2
</if>
<if test="q.searchStatus != null and q.searchStatus == 4">
AND o.status = 3 and o.delivery_type = 1
</if>
<if test="q.searchStatus != null and q.searchStatus == 5">
AND o.status = 4
</if>
<if test="q.searchStatus != null and q.searchStatus == 6">
AND o.status = 5
</if>
<if test="q.searchStatus != null and q.searchStatus == 7">
AND o.status = 7
</if>
<if test="q.searchStatus != null and q.searchStatus == 8">
AND o.status = 8
</if>
<if test="q.searchStatus != null and q.searchStatus == 9">
AND o.status = 6
</if>
<if test="q.deliveryType != null"> <if test="q.deliveryType != null">
AND o.delivery_type = #{q.deliveryType} AND o.delivery_type = #{q.deliveryType}
</if> </if>
@ -82,7 +119,7 @@
o.status, o.total_amount, o.goods_amount, o.delivery_fee, o.status, o.total_amount, o.goods_amount, o.delivery_fee,
o.package_fee, o.address_id, o.remark, o.create_time, o.pay_time, o.package_fee, o.address_id, o.remark, o.create_time, o.pay_time,
o.receiver_name, o.receiver_phone, o.receiver_address, o.receiver_name, o.receiver_phone, o.receiver_address,
o.shop_name, o.shop_phone, o.shop_address,o.number_code,o.region_id o.shop_name, o.shop_phone, o.shop_address,o.number_code,o.region_id,o.settlement_status,o.shop_make_time
FROM mall_order o LEFT JOIN mall_order_group og ON o.id = og.head_order_id FROM mall_order o LEFT JOIN mall_order_group og ON o.id = og.head_order_id
<where> <where>
<if test="groupId != null and groupId != ''"> <if test="groupId != null and groupId != ''">

3
hiver-modules/hiver-mall/src/main/resources/mapper/MallRefundRecordMapper.xml

@ -12,6 +12,9 @@
<result column="status" property="status"/> <result column="status" property="status"/>
<result column="create_time" property="createTime"/> <result column="create_time" property="createTime"/>
<result column="success_time" property="successTime"/> <result column="success_time" property="successTime"/>
<result column="pictures" property="pictures"/>
<result column="refund_type" property="refundType"/>
<result column="refund_type_status" property="refundTypeStatus"/>
</resultMap> </resultMap>
</mapper> </mapper>

8
hiver-modules/hiver-mall/src/main/resources/mapper/WorkerRelaPriceMapper.xml

@ -90,9 +90,13 @@
INNER JOIN t_worker_rela_price p INNER JOIN t_worker_rela_price p
ON p.worker_id = w.worker_id ON p.worker_id = w.worker_id
AND p.get_push_order = 1 AND p.get_push_order = 1
AND p.get_area_id = #{shopAreaId} <if test="shopAreaId != null and shopAreaId != ''">
AND p.get_area_id = #{shopAreaId}
</if>
<if test="putAreaId != null and putAreaId != ''">
AND p.put_area_id = #{putAreaId}
</if>
AND p.order_type = #{orderType} AND p.order_type = #{orderType}
AND p.put_area_id = #{putAreaId}
/* 关联配送订单表:LEFT JOIN 保留无任何订单的配送员 */ /* 关联配送订单表:LEFT JOIN 保留无任何订单的配送员 */
LEFT JOIN mall_delivery_order d LEFT JOIN mall_delivery_order d
ON d.worker_id = w.worker_id ON d.worker_id = w.worker_id

129
hiver-modules/hiver-social/src/main/java/cc/hiver/social/controller/WechatPayController.java

@ -1,129 +0,0 @@
package cc.hiver.social.controller;
import cc.hiver.mall.service.mybatis.MallOrderService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.PostConstruct;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.security.PrivateKey;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
@RestController
@RequestMapping("/hiver/api/wechat/pay")
public class WechatPayController {
@Autowired
private UnifiedOrderService orderService;
@Autowired
private WechatPayConfig config;
@Autowired
private MallOrderService mallOrderService;
@Autowired
private ResourceLoader resourceLoader;
private PrivateKey privateKey;
@PostConstruct
public void init() throws Exception {
Resource resource = resourceLoader.getResource(config.getPrivateKeyPath());
byte[] keyBytes;
try (InputStream is = resource.getInputStream()) {
keyBytes = readAllBytes(is);
}
String key = new String(keyBytes, StandardCharsets.UTF_8)
.replace("-----BEGIN PRIVATE KEY-----", "")
.replace("-----END PRIVATE KEY-----", "")
.replaceAll("\\s+", "");
byte[] decodedKey = Base64.getDecoder().decode(key);
privateKey = KeyUtils.loadPrivateKey(decodedKey);
}
private byte[] readAllBytes(InputStream inputStream) throws IOException {
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
byte[] data = new byte[1024];
int nRead;
while ((nRead = inputStream.read(data, 0, data.length)) != -1) {
buffer.write(data, 0, nRead);
}
return buffer.toByteArray();
}
@PostMapping("/unified-order")
public ResponseEntity<Map<String, String>> jsapiPay(@RequestBody Map<String, String> request) throws Exception {
String outTradeNo = "ORDER_" + request.get("outTradeNo");
String description = request.get("description");
String openid = request.get("openid");
long amount = Long.parseLong(request.get("amount")); // 单位:分
Map<String, Object> orderResult = orderService.createJsapiOrder(outTradeNo, description, openid, amount);
String prepayId = (String) orderResult.get("prepay_id");
if (prepayId == null) {
Map<String, String> payParams = new HashMap<>();
payParams.put("code","101");
payParams.put("message","调起微信支付失败");
return ResponseEntity.ok(payParams);
}else{
// 2. 生成前端支付参数
Map<String, String> payParams = buildPaySign(prepayId);
payParams.put("code","200");
return ResponseEntity.ok(payParams);
}
}
@PostMapping("/paySuccess")
public ResponseEntity<Map<String, String>> paySuccess(@RequestBody Map<String, String> request) throws Exception {
//订单支付成功逻辑
mallOrderService.paySuccess(request.get("outTradeNo"));
Map<String, String> payParams = new HashMap<>();
payParams.put("code","200");
payParams.put("message","支付成功订单更新");
return ResponseEntity.ok(payParams);
}
public Map<String, String> buildPaySign(String prepayId) throws Exception {
// 1. 生成参数
String timeStamp = String.valueOf(System.currentTimeMillis() / 1000); // 秒
String nonceStr = UUID.randomUUID().toString().replace("-", "").substring(0, 32);
String packageValue = "prepay_id=" + prepayId;
String signType = "RSA";
// 2. 构建签名字符串
String message = String.join("\n",
config.getAppId(),
timeStamp,
nonceStr,
packageValue,
"" // 最后一个 \n
);
// 3. 使用商户私钥签名(和 API v3 同一套私钥)
String paySign = KeyUtils.signWithSha256Rsa(message, privateKey); // ← 复用之前的签名方法
// 4. 返回给前端
Map<String, String> result = new HashMap<>();
result.put("timeStamp", timeStamp);
result.put("nonceStr", nonceStr);
result.put("package", packageValue);
result.put("signType", signType);
result.put("paySign", paySign);
return result;
}
}
Loading…
Cancel
Save