Merge branch 'master' of https://gitea.zianxin.com/zax/biz-api-cloud-zax
This commit is contained in:
commit
c917418d73
15 files changed
+849
-23
No files matched your search
+4
@@ -22,4 +22,8 @@ public final class CanteenDeliveryOrderStatus {
|
||||
* 预约单:已到单但未达「提前 N 分钟派骑手」时间点,不展示在骑手待配送列表。
|
||||
*/
|
||||
public static final int SCHEDULED_PENDING = 5;
|
||||
/** 待商家接单(支付同步后或预约单到商家通知时间后) */
|
||||
public static final int MERCHANT_PENDING = 6;
|
||||
/** 已指派骑手,待骑手确认接单 */
|
||||
public static final int RIDER_PENDING_ACCEPT = 7;
|
||||
}
|
||||
+42
@@ -0,0 +1,42 @@
|
||||
package com.bsd.pjcloud.canteen.entity;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.*;
|
||||
import com.baomidou.mybatisplus.extension.activerecord.Model;
|
||||
import com.bsd.pjcloud.common.core.util.TenantTable;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@Data
|
||||
@TenantTable
|
||||
@TableName("canteen_delivery_accept_setting")
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Schema(description = "外送自动接单配置")
|
||||
public class CanteenDeliveryAcceptSettingEntity extends Model<CanteenDeliveryAcceptSettingEntity> {
|
||||
|
||||
@TableId(type = IdType.ASSIGN_ID)
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "商户ID")
|
||||
private String merchantId;
|
||||
|
||||
@Schema(description = "骑手用户ID")
|
||||
private Long riderUserId;
|
||||
|
||||
@Schema(description = "1自动接单 0手动")
|
||||
private Integer autoAccept;
|
||||
|
||||
@TableField(fill = FieldFill.INSERT)
|
||||
private LocalDateTime createTime;
|
||||
|
||||
@TableField(fill = FieldFill.INSERT_UPDATE)
|
||||
private LocalDateTime updateTime;
|
||||
|
||||
@TableLogic
|
||||
@TableField(fill = FieldFill.INSERT)
|
||||
private String delFlag;
|
||||
|
||||
private Long tenantId;
|
||||
}
|
||||
+28
@@ -36,6 +36,22 @@ public class CanteenDeliveryOrderEntity extends Model<CanteenDeliveryOrderEntity
|
||||
private String fullAddress;
|
||||
private Integer buyerGender;
|
||||
private String carListJson;
|
||||
|
||||
@Schema(description = "订单金额快照(分)")
|
||||
private Integer orderAmount;
|
||||
|
||||
@Schema(description = "商家是否已接单 0否1是")
|
||||
private Integer merchantAccepted;
|
||||
|
||||
@Schema(description = "商家接单时间")
|
||||
private LocalDateTime merchantAcceptTime;
|
||||
|
||||
@Schema(description = "骑手是否已接单 0否1是")
|
||||
private Integer riderAccepted;
|
||||
|
||||
@Schema(description = "骑手接单时间")
|
||||
private LocalDateTime riderAcceptTime;
|
||||
|
||||
private String assignType;
|
||||
private Long riderUserId;
|
||||
private Integer status;
|
||||
@@ -67,6 +83,18 @@ public class CanteenDeliveryOrderEntity extends Model<CanteenDeliveryOrderEntity
|
||||
private String pickupPhotoUrl;
|
||||
private String deliveryPhotoUrl;
|
||||
|
||||
@Schema(description = "骑手佣金快照(分),派单时从商户 mch_take_out_amt 写入")
|
||||
private Integer riderCommissionAmt;
|
||||
|
||||
@Schema(description = "骑手派单时间(佣金统计按此日期)")
|
||||
private LocalDateTime riderAssignedTime;
|
||||
|
||||
@Schema(description = "取餐时间")
|
||||
private LocalDateTime pickupTime;
|
||||
|
||||
@Schema(description = "送达时间")
|
||||
private LocalDateTime deliverTime;
|
||||
|
||||
@TableField(fill = FieldFill.INSERT)
|
||||
private String createBy;
|
||||
|
||||
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
package com.bsd.pjcloud.canteen.vo.app;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
@Schema(description = "自动接单配置")
|
||||
public class CanteenDeliveryAutoAcceptVO {
|
||||
|
||||
@Schema(description = "是否开启自动接单")
|
||||
private Boolean autoAccept;
|
||||
|
||||
@Schema(description = "商户ID(商家端)")
|
||||
private String merchantId;
|
||||
|
||||
@Schema(description = "骑手用户ID(骑手端)")
|
||||
private Long riderUserId;
|
||||
}
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
package com.bsd.pjcloud.canteen.vo.app;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
@Schema(description = "商家外送按月统计")
|
||||
public class CanteenDeliveryMerchantStatsMonthVO {
|
||||
|
||||
@Schema(description = "查询月份 yyyy-MM")
|
||||
private String month;
|
||||
|
||||
@Schema(description = "该月已接单订单数")
|
||||
private Long orderCount;
|
||||
|
||||
@Schema(description = "该月已接单金额合计(分)")
|
||||
private Long totalAmount;
|
||||
}
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
package com.bsd.pjcloud.canteen.vo.app;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
@Schema(description = "商家外送订单统计汇总")
|
||||
public class CanteenDeliveryMerchantStatsSummaryVO {
|
||||
|
||||
@Schema(description = "今日已接单订单数")
|
||||
private Long todayOrderCount;
|
||||
|
||||
@Schema(description = "今日已接单金额合计(分)")
|
||||
private Long todayOrderAmount;
|
||||
|
||||
@Schema(description = "本月已接单金额合计(分)")
|
||||
private Long monthOrderAmount;
|
||||
}
|
||||
+27
@@ -24,6 +24,21 @@ public class CanteenDeliveryOrderAppVO {
|
||||
private String fullAddress;
|
||||
private Integer status;
|
||||
|
||||
@Schema(description = "订单金额(分)")
|
||||
private Integer orderAmount;
|
||||
|
||||
@Schema(description = "商家是否已接单")
|
||||
private Integer merchantAccepted;
|
||||
|
||||
@Schema(description = "商家接单时间")
|
||||
private LocalDateTime merchantAcceptTime;
|
||||
|
||||
@Schema(description = "骑手是否已接单")
|
||||
private Integer riderAccepted;
|
||||
|
||||
@Schema(description = "骑手接单时间")
|
||||
private LocalDateTime riderAcceptTime;
|
||||
|
||||
@Schema(description = "指派骑手用户主键(未指派时为 null)")
|
||||
private Long riderUserId;
|
||||
|
||||
@@ -44,6 +59,18 @@ public class CanteenDeliveryOrderAppVO {
|
||||
private String deliveryPhotoUrl;
|
||||
private LocalDateTime createTime;
|
||||
|
||||
@Schema(description = "骑手佣金(分),派单时快照")
|
||||
private Integer riderCommissionAmt;
|
||||
|
||||
@Schema(description = "骑手派单时间")
|
||||
private LocalDateTime riderAssignedTime;
|
||||
|
||||
@Schema(description = "取餐时间")
|
||||
private LocalDateTime pickupTime;
|
||||
|
||||
@Schema(description = "送达时间")
|
||||
private LocalDateTime deliverTime;
|
||||
|
||||
@Schema(description = "购物车行项目(由 car_list_json 反序列化)")
|
||||
private List<CanteenDeliveryCartItemDTO> carList;
|
||||
}
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
package com.bsd.pjcloud.canteen.vo.app;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import java.time.LocalDate;
|
||||
|
||||
@Data
|
||||
@Schema(description = "骑手自定义日期佣金查询结果")
|
||||
public class CanteenDeliveryRiderCommissionQueryVO {
|
||||
|
||||
@Schema(description = "查询开始日期")
|
||||
private LocalDate startDate;
|
||||
|
||||
@Schema(description = "查询结束日期")
|
||||
private LocalDate endDate;
|
||||
|
||||
@Schema(description = "佣金合计(分)")
|
||||
private Long totalAmt;
|
||||
|
||||
@Schema(description = "有效派单数(非取消)")
|
||||
private Long orderCount;
|
||||
}
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
package com.bsd.pjcloud.canteen.vo.app;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
@Schema(description = "骑手佣金汇总(今日/本月,单位:分)")
|
||||
public class CanteenDeliveryRiderCommissionSummaryVO {
|
||||
|
||||
@Schema(description = "今日佣金合计(分)")
|
||||
private Long todayAmt;
|
||||
|
||||
@Schema(description = "本月佣金合计(分)")
|
||||
private Long monthAmt;
|
||||
|
||||
@Schema(description = "今日有效派单数(非取消)")
|
||||
private Long todayOrderCount;
|
||||
|
||||
@Schema(description = "本月有效派单数(非取消)")
|
||||
private Long monthOrderCount;
|
||||
}
|
||||
+87
-4
@@ -6,7 +6,12 @@ import com.bsd.pjcloud.canteen.push.CanteenDeliveryMerchantNotifyPublisher;
|
||||
import com.bsd.pjcloud.canteen.push.CanteenDeliveryRiderPushPublisher;
|
||||
import com.bsd.pjcloud.canteen.service.CanteenDeliveryOrderService;
|
||||
import com.bsd.pjcloud.canteen.entity.CanteenDeliveryOrderEntity;
|
||||
import com.bsd.pjcloud.canteen.vo.app.CanteenDeliveryAutoAcceptVO;
|
||||
import com.bsd.pjcloud.canteen.vo.app.CanteenDeliveryMerchantStatsMonthVO;
|
||||
import com.bsd.pjcloud.canteen.vo.app.CanteenDeliveryMerchantStatsSummaryVO;
|
||||
import com.bsd.pjcloud.canteen.vo.app.CanteenDeliveryOrderAppVO;
|
||||
import com.bsd.pjcloud.canteen.vo.app.CanteenDeliveryRiderCommissionQueryVO;
|
||||
import com.bsd.pjcloud.canteen.vo.app.CanteenDeliveryRiderCommissionSummaryVO;
|
||||
import com.bsd.pjcloud.common.core.util.R;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.bsd.pjcloud.common.log.annotation.SysLog;
|
||||
@@ -22,6 +27,9 @@ import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.springdoc.core.annotations.ParameterObject;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.time.format.DateTimeParseException;
|
||||
|
||||
/**
|
||||
* 食堂外送:订单同步 + 骑手 App
|
||||
*/
|
||||
@@ -103,6 +111,30 @@ public class CanteenDeliveryOrderController {
|
||||
return R.ok(canteenDeliveryOrderService.pageForRider(uid, tab, page));
|
||||
}
|
||||
|
||||
@GetMapping("/app/commission/summary")
|
||||
@Operation(summary = "骑手端-佣金汇总", description = "今日/本月佣金合计(分),按派单时间统计,已取消单不计入")
|
||||
public R<CanteenDeliveryRiderCommissionSummaryVO> appCommissionSummary() {
|
||||
Long uid = SecurityUtils.getUser().getId();
|
||||
return R.ok(canteenDeliveryOrderService.commissionSummaryForRider(uid));
|
||||
}
|
||||
|
||||
@GetMapping("/app/commission/query")
|
||||
@Operation(summary = "骑手端-自定义日期佣金", description = "startDate/endDate 格式 yyyy-MM-dd,含首尾自然日")
|
||||
public R<CanteenDeliveryRiderCommissionQueryVO> appCommissionQuery(
|
||||
@RequestParam String startDate,
|
||||
@RequestParam String endDate) {
|
||||
try {
|
||||
LocalDate start = LocalDate.parse(startDate.trim());
|
||||
LocalDate end = LocalDate.parse(endDate.trim());
|
||||
Long uid = SecurityUtils.getUser().getId();
|
||||
return R.ok(canteenDeliveryOrderService.commissionQueryForRider(uid, start, end));
|
||||
} catch (DateTimeParseException ex) {
|
||||
return R.failed("日期格式应为 yyyy-MM-dd");
|
||||
} catch (IllegalArgumentException ex) {
|
||||
return R.failed(ex.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@GetMapping("/app/{id}")
|
||||
@Operation(summary = "骑手端-配送单详情")
|
||||
public R<CanteenDeliveryOrderAppVO> appDetail(@PathVariable Long id) {
|
||||
@@ -116,14 +148,43 @@ public class CanteenDeliveryOrderController {
|
||||
|
||||
@GetMapping("/app/mch/list")
|
||||
@Operation(summary = "商家端 App-外送单列表",
|
||||
description = "当前登录用户部门及其下级部门关联的商户(钱包 get-by-dept-ids)下的外送单。"
|
||||
+ "tab:pending 进行中 | all全部 | completed 已完成 | cancelled 已取消。分页同骑手端。"
|
||||
+ "预约单 SCHEDULED 仅在 merchant_notify_done=1(已向商家触发通知)后返回;立即送不受限。")
|
||||
public R<Page<CanteenDeliveryOrderAppVO>> mchAppList(@RequestParam(defaultValue = "pending") String tab,
|
||||
description = "tab: wait_accept待接单 | accepted已接单 | cancelled | completed | all | pending(兼容)")
|
||||
public R<Page<CanteenDeliveryOrderAppVO>> mchAppList(@RequestParam(defaultValue = "wait_accept") String tab,
|
||||
@ParameterObject Page<CanteenDeliveryOrderEntity> page) {
|
||||
return canteenDeliveryOrderService.pageForMerchantApp(tab, page);
|
||||
}
|
||||
|
||||
@GetMapping("/app/mch/stats/summary")
|
||||
@Operation(summary = "商家端-订单统计汇总")
|
||||
public R<CanteenDeliveryMerchantStatsSummaryVO> mchStatsSummary() {
|
||||
return canteenDeliveryOrderService.merchantStatsSummary();
|
||||
}
|
||||
|
||||
@GetMapping("/app/mch/stats/month")
|
||||
@Operation(summary = "商家端-按月统计", description = "month 格式 yyyy-MM")
|
||||
public R<CanteenDeliveryMerchantStatsMonthVO> mchStatsMonth(@RequestParam String month) {
|
||||
return canteenDeliveryOrderService.merchantStatsByMonth(month);
|
||||
}
|
||||
|
||||
@GetMapping("/app/mch/auto-accept")
|
||||
@Operation(summary = "商家端-获取自动接单配置")
|
||||
public R<CanteenDeliveryAutoAcceptVO> mchGetAutoAccept() {
|
||||
return canteenDeliveryOrderService.getMerchantAutoAccept();
|
||||
}
|
||||
|
||||
@PutMapping("/app/mch/auto-accept")
|
||||
@Operation(summary = "商家端-保存自动接单配置")
|
||||
public R<CanteenDeliveryAutoAcceptVO> mchSaveAutoAccept(@RequestParam Boolean autoAccept) {
|
||||
return canteenDeliveryOrderService.saveMerchantAutoAccept(autoAccept);
|
||||
}
|
||||
|
||||
@SysLog("商家接单")
|
||||
@PostMapping("/app/mch/accept/{id}")
|
||||
@Operation(summary = "商家端-手动接单")
|
||||
public R<Void> mchAccept(@PathVariable Long id) {
|
||||
return canteenDeliveryOrderService.merchantAcceptOrder(id);
|
||||
}
|
||||
|
||||
@GetMapping("/app/mch/{id}")
|
||||
@Operation(summary = "商家端 App-外送单详情",
|
||||
description = "预约单未到商家通知完成前返回失败(与列表可见性一致)。")
|
||||
@@ -131,6 +192,28 @@ public class CanteenDeliveryOrderController {
|
||||
return canteenDeliveryOrderService.detailForMerchantApp(id);
|
||||
}
|
||||
|
||||
@GetMapping("/app/rider/auto-accept")
|
||||
@Operation(summary = "骑手端-获取自动接单配置")
|
||||
public R<CanteenDeliveryAutoAcceptVO> riderGetAutoAccept() {
|
||||
Long uid = SecurityUtils.getUser().getId();
|
||||
return canteenDeliveryOrderService.getRiderAutoAccept(uid);
|
||||
}
|
||||
|
||||
@PutMapping("/app/rider/auto-accept")
|
||||
@Operation(summary = "骑手端-保存自动接单配置")
|
||||
public R<CanteenDeliveryAutoAcceptVO> riderSaveAutoAccept(@RequestParam Boolean autoAccept) {
|
||||
Long uid = SecurityUtils.getUser().getId();
|
||||
return canteenDeliveryOrderService.saveRiderAutoAccept(uid, autoAccept);
|
||||
}
|
||||
|
||||
@SysLog("骑手接单")
|
||||
@PostMapping("/app/accept/{id}")
|
||||
@Operation(summary = "骑手端-手动接单")
|
||||
public R<Void> riderAccept(@PathVariable Long id) {
|
||||
Long uid = SecurityUtils.getUser().getId();
|
||||
return canteenDeliveryOrderService.riderAcceptOrder(uid, id);
|
||||
}
|
||||
|
||||
@SysLog("取餐拍照")
|
||||
@PostMapping("/app/pickup")
|
||||
@Operation(summary = "骑手端-到店取餐拍照",
|
||||
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
package com.bsd.pjcloud.canteen.mapper;
|
||||
|
||||
import com.bsd.pjcloud.canteen.entity.CanteenDeliveryAcceptSettingEntity;
|
||||
import com.bsd.pjcloud.common.data.datascope.PjcloudBaseMapper;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
@Mapper
|
||||
public interface CanteenDeliveryAcceptSettingMapper extends PjcloudBaseMapper<CanteenDeliveryAcceptSettingEntity> {
|
||||
}
|
||||
+38
@@ -5,9 +5,16 @@ import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import com.bsd.pjcloud.canteen.dto.delivery.CanteenDeliveryOrderSyncDTO;
|
||||
import com.bsd.pjcloud.canteen.dto.delivery.CanteenDeliveryPhotoDTO;
|
||||
import com.bsd.pjcloud.canteen.entity.CanteenDeliveryOrderEntity;
|
||||
import com.bsd.pjcloud.canteen.vo.app.CanteenDeliveryAutoAcceptVO;
|
||||
import com.bsd.pjcloud.canteen.vo.app.CanteenDeliveryMerchantStatsMonthVO;
|
||||
import com.bsd.pjcloud.canteen.vo.app.CanteenDeliveryMerchantStatsSummaryVO;
|
||||
import com.bsd.pjcloud.canteen.vo.app.CanteenDeliveryOrderAppVO;
|
||||
import com.bsd.pjcloud.canteen.vo.app.CanteenDeliveryRiderCommissionQueryVO;
|
||||
import com.bsd.pjcloud.canteen.vo.app.CanteenDeliveryRiderCommissionSummaryVO;
|
||||
import com.bsd.pjcloud.common.core.util.R;
|
||||
|
||||
import java.time.LocalDate;
|
||||
|
||||
public interface CanteenDeliveryOrderService extends IService<CanteenDeliveryOrderEntity> {
|
||||
|
||||
/**
|
||||
@@ -53,4 +60,35 @@ public interface CanteenDeliveryOrderService extends IService<CanteenDeliveryOrd
|
||||
* 单条:骑手派单+推送(事务内行锁;无可用骑手时保持待调度状态下次重试)。
|
||||
*/
|
||||
void dispatchScheduledRiderIfDue(Long deliveryOrderId);
|
||||
|
||||
/** 骑手端:今日/本月佣金汇总(分) */
|
||||
CanteenDeliveryRiderCommissionSummaryVO commissionSummaryForRider(Long riderUserId);
|
||||
|
||||
/** 骑手端:自定义日期佣金(分) */
|
||||
CanteenDeliveryRiderCommissionQueryVO commissionQueryForRider(Long riderUserId, LocalDate startDate, LocalDate endDate);
|
||||
|
||||
/** 商家端:今日/本月订单统计 */
|
||||
R<CanteenDeliveryMerchantStatsSummaryVO> merchantStatsSummary();
|
||||
|
||||
/** 商家端:按月统计 yyyy-MM */
|
||||
R<CanteenDeliveryMerchantStatsMonthVO> merchantStatsByMonth(String month);
|
||||
|
||||
/** 商家接单 */
|
||||
R<Void> merchantAcceptOrder(Long deliveryOrderId);
|
||||
|
||||
/** 骑手接单 */
|
||||
R<Void> riderAcceptOrder(Long riderUserId, Long deliveryOrderId);
|
||||
|
||||
/** 商家自动接单配置 */
|
||||
R<CanteenDeliveryAutoAcceptVO> getMerchantAutoAccept();
|
||||
|
||||
R<CanteenDeliveryAutoAcceptVO> saveMerchantAutoAccept(Boolean autoAccept);
|
||||
|
||||
/** 骑手自动接单配置 */
|
||||
R<CanteenDeliveryAutoAcceptVO> getRiderAutoAccept(Long riderUserId);
|
||||
|
||||
R<CanteenDeliveryAutoAcceptVO> saveRiderAutoAccept(Long riderUserId, Boolean autoAccept);
|
||||
|
||||
/** 内部:尝试商家自动接单(同步/通知后) */
|
||||
void tryMerchantAutoAccept(Long deliveryOrderId);
|
||||
}
|
||||
+495
-19
@@ -18,10 +18,12 @@ import com.bsd.pjcloud.canteen.constants.CanteenDeliveryScheduleConstants;
|
||||
import com.bsd.pjcloud.canteen.dto.delivery.CanteenDeliveryCartItemDTO;
|
||||
import com.bsd.pjcloud.canteen.dto.delivery.CanteenDeliveryOrderSyncDTO;
|
||||
import com.bsd.pjcloud.canteen.dto.delivery.CanteenDeliveryPhotoDTO;
|
||||
import com.bsd.pjcloud.canteen.entity.CanteenDeliveryAcceptSettingEntity;
|
||||
import com.bsd.pjcloud.canteen.entity.CanteenDeliveryAssignSeqEntity;
|
||||
import com.bsd.pjcloud.canteen.entity.CanteenDeliveryOrderEntity;
|
||||
import com.bsd.pjcloud.canteen.entity.CanteenRiderBuildingBindEntity;
|
||||
import com.bsd.pjcloud.canteen.entity.CanteenRiderPoolEntity;
|
||||
import com.bsd.pjcloud.canteen.mapper.CanteenDeliveryAcceptSettingMapper;
|
||||
import com.bsd.pjcloud.canteen.mapper.CanteenDeliveryAssignSeqMapper;
|
||||
import com.bsd.pjcloud.canteen.mapper.CanteenDeliveryOrderMapper;
|
||||
import com.bsd.pjcloud.canteen.mapper.CanteenRiderBuildingBindMapper;
|
||||
@@ -31,11 +33,17 @@ import com.bsd.pjcloud.canteen.push.CanteenDeliveryRiderPushPublisher;
|
||||
import com.bsd.pjcloud.canteen.service.CanteenDeliveryOrderService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import com.bsd.pjcloud.canteen.vo.app.CanteenDeliveryAutoAcceptVO;
|
||||
import com.bsd.pjcloud.canteen.vo.app.CanteenDeliveryMerchantStatsMonthVO;
|
||||
import com.bsd.pjcloud.canteen.vo.app.CanteenDeliveryMerchantStatsSummaryVO;
|
||||
import com.bsd.pjcloud.canteen.vo.app.CanteenDeliveryOrderAppVO;
|
||||
import com.bsd.pjcloud.canteen.vo.app.CanteenDeliveryRiderCommissionQueryVO;
|
||||
import com.bsd.pjcloud.canteen.vo.app.CanteenDeliveryRiderCommissionSummaryVO;
|
||||
import com.bsd.pjcloud.common.core.util.BeanUtils;
|
||||
import com.bsd.pjcloud.common.core.util.R;
|
||||
import com.bsd.pjcloud.common.security.util.SecurityUtils;
|
||||
import com.bsd.pjcloud.wallet.api.feign.RemoteMchService;
|
||||
import com.bsd.pjcloud.wallet.api.feign.RemoteWalletService;
|
||||
import com.bsd.pjcloud.wallet.api.vo.MchManageVo;
|
||||
import com.bsd.pjcloud.hard.api.dto.order.remote.HardUpdateTakeOutStatusDto;
|
||||
import com.bsd.pjcloud.hard.api.feign.RemoteHardOrderService;
|
||||
@@ -49,7 +57,10 @@ import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.transaction.support.TransactionSynchronization;
|
||||
import org.springframework.transaction.support.TransactionSynchronizationManager;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.YearMonth;
|
||||
import java.time.format.DateTimeParseException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@@ -66,6 +77,7 @@ public class CanteenDeliveryOrderServiceImpl extends ServiceImpl<CanteenDelivery
|
||||
private final CanteenRiderBuildingBindMapper riderBuildingBindMapper;
|
||||
private final CanteenRiderPoolMapper riderPoolMapper;
|
||||
private final CanteenDeliveryAssignSeqMapper assignSeqMapper;
|
||||
private final CanteenDeliveryAcceptSettingMapper acceptSettingMapper;
|
||||
private final RemoteUserService remoteUserService;
|
||||
private final RemoteDeptService remoteDeptService;
|
||||
private final ObjectMapper objectMapper;
|
||||
@@ -74,6 +86,7 @@ public class CanteenDeliveryOrderServiceImpl extends ServiceImpl<CanteenDelivery
|
||||
private final RemoteParamService remoteParamService;
|
||||
private final RemoteHardOrderService remoteHardOrderService;
|
||||
private final RemoteMchService remoteMchService;
|
||||
private final RemoteWalletService remoteWalletService;
|
||||
|
||||
private CanteenDeliveryOrderService deliveryOrderServiceSelf;
|
||||
|
||||
@@ -131,6 +144,11 @@ public class CanteenDeliveryOrderServiceImpl extends ServiceImpl<CanteenDelivery
|
||||
} catch (JsonProcessingException e) {
|
||||
return R.failed("购物车序列化失败");
|
||||
}
|
||||
entity.setOrderAmount(calcOrderAmountFromCart(dto.getCarList()));
|
||||
entity.setMerchantAccepted(0);
|
||||
entity.setRiderAccepted(0);
|
||||
entity.setAssignType(CanteenDeliveryAssignType.NONE);
|
||||
entity.setRiderUserId(null);
|
||||
|
||||
String expectType = entity.getExpectDeliveryType();
|
||||
if (!CanteenDeliveryScheduleConstants.EXPECT_TYPE_SCHEDULED.equals(expectType)
|
||||
@@ -138,10 +156,10 @@ public class CanteenDeliveryOrderServiceImpl extends ServiceImpl<CanteenDelivery
|
||||
entity.setMerchantNotifyDone(1);
|
||||
entity.setScheduledMerchantNotifyTime(null);
|
||||
entity.setScheduledRiderNotifyTime(null);
|
||||
assignRiderOnCreate(entity);
|
||||
entity.setStatus(CanteenDeliveryOrderStatus.MERCHANT_PENDING);
|
||||
save(entity);
|
||||
scheduleMerchantImmediatePushAfterCommit(entity);
|
||||
scheduleRiderPushAfterAssign(entity);
|
||||
scheduleTryMerchantAutoAcceptAfterCommit(entity.getId());
|
||||
return R.ok(entity.getId());
|
||||
}
|
||||
|
||||
@@ -154,19 +172,24 @@ public class CanteenDeliveryOrderServiceImpl extends ServiceImpl<CanteenDelivery
|
||||
entity.setScheduledRiderNotifyTime(slotStart.minusMinutes(riderBefore));
|
||||
entity.setScheduledMerchantNotifyTime(slotStart.minusMinutes(merchantBefore));
|
||||
entity.setMerchantNotifyDone(0);
|
||||
entity.setStatus(CanteenDeliveryOrderStatus.SCHEDULED_PENDING);
|
||||
|
||||
if (entity.getScheduledRiderNotifyTime().isAfter(now)) {
|
||||
entity.setStatus(CanteenDeliveryOrderStatus.SCHEDULED_PENDING);
|
||||
entity.setAssignType(CanteenDeliveryAssignType.NONE);
|
||||
entity.setRiderUserId(null);
|
||||
save(entity);
|
||||
return R.ok(entity.getId());
|
||||
}
|
||||
|
||||
assignRiderOnCreate(entity);
|
||||
if (entity.getScheduledMerchantNotifyTime() != null && !entity.getScheduledMerchantNotifyTime().isAfter(now)) {
|
||||
entity.setMerchantNotifyDone(1);
|
||||
entity.setStatus(CanteenDeliveryOrderStatus.MERCHANT_PENDING);
|
||||
}
|
||||
save(entity);
|
||||
scheduleNotifyMerchantIfDueAfterCommit(entity.getId());
|
||||
scheduleRiderPushAfterAssign(entity);
|
||||
if (Objects.equals(entity.getMerchantNotifyDone(), 1)) {
|
||||
scheduleMerchantPushAfterNotify(entity);
|
||||
scheduleTryMerchantAutoAcceptAfterCommit(entity.getId());
|
||||
} else {
|
||||
scheduleNotifyMerchantIfDueAfterCommit(entity.getId());
|
||||
}
|
||||
return R.ok(entity.getId());
|
||||
}
|
||||
|
||||
@@ -212,8 +235,11 @@ public class CanteenDeliveryOrderServiceImpl extends ServiceImpl<CanteenDelivery
|
||||
* 事务提交后再推送,避免回滚后骑手仍收到通知。
|
||||
*/
|
||||
private void scheduleRiderPushAfterAssign(CanteenDeliveryOrderEntity entity) {
|
||||
if (entity.getRiderUserId() == null
|
||||
|| !Objects.equals(entity.getStatus(), CanteenDeliveryOrderStatus.WAIT_PICKUP)) {
|
||||
if (entity.getRiderUserId() == null) {
|
||||
return;
|
||||
}
|
||||
int st = entity.getStatus() != null ? entity.getStatus() : -1;
|
||||
if (st != CanteenDeliveryOrderStatus.WAIT_PICKUP && st != CanteenDeliveryOrderStatus.RIDER_PENDING_ACCEPT) {
|
||||
return;
|
||||
}
|
||||
final Long riderId = entity.getRiderUserId();
|
||||
@@ -248,7 +274,8 @@ public class CanteenDeliveryOrderServiceImpl extends ServiceImpl<CanteenDelivery
|
||||
if (bind != null && verifyRiderInUnit(bind.getRiderUserId(), deptId)) {
|
||||
entity.setRiderUserId(bind.getRiderUserId());
|
||||
entity.setAssignType(CanteenDeliveryAssignType.BIND);
|
||||
entity.setStatus(CanteenDeliveryOrderStatus.WAIT_PICKUP);
|
||||
applyRiderCommissionSnapshot(entity);
|
||||
applyRiderAcceptState(entity);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -283,7 +310,47 @@ public class CanteenDeliveryOrderServiceImpl extends ServiceImpl<CanteenDelivery
|
||||
}
|
||||
entity.setRiderUserId(chosen.getRiderUserId());
|
||||
entity.setAssignType(CanteenDeliveryAssignType.ROUND_ROBIN);
|
||||
entity.setStatus(CanteenDeliveryOrderStatus.WAIT_PICKUP);
|
||||
applyRiderCommissionSnapshot(entity);
|
||||
applyRiderAcceptState(entity);
|
||||
}
|
||||
|
||||
private void applyRiderAcceptState(CanteenDeliveryOrderEntity entity) {
|
||||
if (entity.getRiderUserId() == null) {
|
||||
entity.setStatus(CanteenDeliveryOrderStatus.PENDING_ASSIGN);
|
||||
return;
|
||||
}
|
||||
if (isRiderAutoAccept(entity.getRiderUserId())) {
|
||||
entity.setRiderAccepted(1);
|
||||
entity.setRiderAcceptTime(LocalDateTime.now());
|
||||
entity.setStatus(CanteenDeliveryOrderStatus.WAIT_PICKUP);
|
||||
} else {
|
||||
entity.setRiderAccepted(0);
|
||||
entity.setStatus(CanteenDeliveryOrderStatus.RIDER_PENDING_ACCEPT);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 派单成功时快照商户配送费,后续商户改价不影响本单佣金。
|
||||
*/
|
||||
private void applyRiderCommissionSnapshot(CanteenDeliveryOrderEntity entity) {
|
||||
entity.setRiderAssignedTime(LocalDateTime.now());
|
||||
entity.setRiderCommissionAmt(resolveMchTakeOutAmt(entity.getMerchantId()));
|
||||
}
|
||||
|
||||
private int resolveMchTakeOutAmt(String merchantId) {
|
||||
if (StrUtil.isBlank(merchantId)) {
|
||||
return 0;
|
||||
}
|
||||
try {
|
||||
Long mid = Long.parseLong(merchantId.trim());
|
||||
R<Integer> r = remoteWalletService.innerMchTakeOutAmt(mid);
|
||||
if (r != null && r.isOk() && r.getData() != null) {
|
||||
return Math.max(0, r.getData());
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
log.warn("resolveMchTakeOutAmt merchantId={}", merchantId, ex);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
private List<CanteenRiderPoolEntity> filterPoolByBuyerGender(List<CanteenRiderPoolEntity> pool, Integer buyerGender) {
|
||||
@@ -381,8 +448,11 @@ public class CanteenDeliveryOrderServiceImpl extends ServiceImpl<CanteenDelivery
|
||||
var q = Wrappers.<CanteenDeliveryOrderEntity>lambdaQuery()
|
||||
.eq(CanteenDeliveryOrderEntity::getRiderUserId, riderUserId);
|
||||
switch (t) {
|
||||
case "wait_accept" ->
|
||||
q.eq(CanteenDeliveryOrderEntity::getStatus, CanteenDeliveryOrderStatus.RIDER_PENDING_ACCEPT);
|
||||
case "pending" ->
|
||||
q.in(CanteenDeliveryOrderEntity::getStatus, CanteenDeliveryOrderStatus.WAIT_PICKUP, CanteenDeliveryOrderStatus.DELIVERING);
|
||||
q.in(CanteenDeliveryOrderEntity::getStatus, CanteenDeliveryOrderStatus.WAIT_PICKUP, CanteenDeliveryOrderStatus.DELIVERING)
|
||||
.eq(CanteenDeliveryOrderEntity::getRiderAccepted, 1);
|
||||
case "completed" -> q.eq(CanteenDeliveryOrderEntity::getStatus, CanteenDeliveryOrderStatus.COMPLETED);
|
||||
case "cancelled" -> q.eq(CanteenDeliveryOrderEntity::getStatus, CanteenDeliveryOrderStatus.CANCELLED);
|
||||
default -> {
|
||||
@@ -486,10 +556,19 @@ public class CanteenDeliveryOrderServiceImpl extends ServiceImpl<CanteenDelivery
|
||||
.in(CanteenDeliveryOrderEntity::getMerchantId, merchantIds);
|
||||
applyMerchantScheduledVisibilityFilter(q);
|
||||
switch (t) {
|
||||
case "wait_accept" -> q.eq(CanteenDeliveryOrderEntity::getStatus, CanteenDeliveryOrderStatus.MERCHANT_PENDING);
|
||||
case "accepted" -> q.eq(CanteenDeliveryOrderEntity::getMerchantAccepted, 1)
|
||||
.in(CanteenDeliveryOrderEntity::getStatus,
|
||||
CanteenDeliveryOrderStatus.PENDING_ASSIGN,
|
||||
CanteenDeliveryOrderStatus.WAIT_PICKUP,
|
||||
CanteenDeliveryOrderStatus.RIDER_PENDING_ACCEPT,
|
||||
CanteenDeliveryOrderStatus.DELIVERING,
|
||||
CanteenDeliveryOrderStatus.SCHEDULED_PENDING);
|
||||
case "pending" -> q.in(CanteenDeliveryOrderEntity::getStatus,
|
||||
CanteenDeliveryOrderStatus.PENDING_ASSIGN,
|
||||
CanteenDeliveryOrderStatus.SCHEDULED_PENDING,
|
||||
CanteenDeliveryOrderStatus.WAIT_PICKUP,
|
||||
CanteenDeliveryOrderStatus.RIDER_PENDING_ACCEPT,
|
||||
CanteenDeliveryOrderStatus.DELIVERING);
|
||||
case "completed" -> q.eq(CanteenDeliveryOrderEntity::getStatus, CanteenDeliveryOrderStatus.COMPLETED);
|
||||
case "cancelled" -> q.eq(CanteenDeliveryOrderEntity::getStatus, CanteenDeliveryOrderStatus.CANCELLED);
|
||||
@@ -575,11 +654,15 @@ public class CanteenDeliveryOrderServiceImpl extends ServiceImpl<CanteenDelivery
|
||||
if (e == null || !Objects.equals(e.getRiderUserId(), riderUserId)) {
|
||||
return R.failed("订单不存在或无权操作");
|
||||
}
|
||||
if (!Objects.equals(e.getRiderAccepted(), 1)) {
|
||||
return R.failed("请先接单");
|
||||
}
|
||||
if (e.getStatus() != CanteenDeliveryOrderStatus.WAIT_PICKUP) {
|
||||
return R.failed("当前状态不可上传取餐照");
|
||||
}
|
||||
e.setPickupPhotoUrl(dto.getPhotoUrl());
|
||||
e.setStatus(CanteenDeliveryOrderStatus.DELIVERING);
|
||||
e.setPickupTime(LocalDateTime.now());
|
||||
updateById(e);
|
||||
syncHardTakeOutStatusOrThrow(e.getSourceOrderId(), HardUpdateTakeOutStatusDto.TakeOutStatus.TAKE_OUT_ING);
|
||||
return R.ok();
|
||||
@@ -597,6 +680,7 @@ public class CanteenDeliveryOrderServiceImpl extends ServiceImpl<CanteenDelivery
|
||||
}
|
||||
e.setDeliveryPhotoUrl(dto.getPhotoUrl());
|
||||
e.setStatus(CanteenDeliveryOrderStatus.COMPLETED);
|
||||
e.setDeliverTime(LocalDateTime.now());
|
||||
updateById(e);
|
||||
syncHardTakeOutStatusOrThrow(e.getSourceOrderId(), HardUpdateTakeOutStatusDto.TakeOutStatus.DONE);
|
||||
return R.ok();
|
||||
@@ -623,7 +707,9 @@ public class CanteenDeliveryOrderServiceImpl extends ServiceImpl<CanteenDelivery
|
||||
}
|
||||
|
||||
List<CanteenDeliveryOrderEntity> riderDue = list(Wrappers.<CanteenDeliveryOrderEntity>lambdaQuery()
|
||||
.eq(CanteenDeliveryOrderEntity::getStatus, CanteenDeliveryOrderStatus.SCHEDULED_PENDING)
|
||||
.eq(CanteenDeliveryOrderEntity::getMerchantAccepted, 1)
|
||||
.isNull(CanteenDeliveryOrderEntity::getRiderUserId)
|
||||
.eq(CanteenDeliveryOrderEntity::getStatus, CanteenDeliveryOrderStatus.PENDING_ASSIGN)
|
||||
.isNotNull(CanteenDeliveryOrderEntity::getScheduledRiderNotifyTime)
|
||||
.le(CanteenDeliveryOrderEntity::getScheduledRiderNotifyTime, now)
|
||||
.select(CanteenDeliveryOrderEntity::getId)
|
||||
@@ -661,8 +747,12 @@ public class CanteenDeliveryOrderServiceImpl extends ServiceImpl<CanteenDelivery
|
||||
return;
|
||||
}
|
||||
e.setMerchantNotifyDone(1);
|
||||
if (!isMerchantAccepted(e)) {
|
||||
e.setStatus(CanteenDeliveryOrderStatus.MERCHANT_PENDING);
|
||||
}
|
||||
updateById(e);
|
||||
scheduleMerchantPushAfterNotify(e);
|
||||
scheduleTryMerchantAutoAcceptAfterCommit(e.getId());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -693,18 +783,22 @@ public class CanteenDeliveryOrderServiceImpl extends ServiceImpl<CanteenDelivery
|
||||
CanteenDeliveryOrderEntity e = getOne(Wrappers.<CanteenDeliveryOrderEntity>lambdaQuery()
|
||||
.eq(CanteenDeliveryOrderEntity::getId, deliveryOrderId)
|
||||
.last("FOR UPDATE"));
|
||||
if (e == null || !Objects.equals(e.getStatus(), CanteenDeliveryOrderStatus.SCHEDULED_PENDING)) {
|
||||
if (e == null) {
|
||||
return;
|
||||
}
|
||||
if (e.getScheduledRiderNotifyTime() == null || e.getScheduledRiderNotifyTime().isAfter(LocalDateTime.now())) {
|
||||
return;
|
||||
}
|
||||
assignRiderOnCreate(e);
|
||||
if (e.getRiderUserId() == null) {
|
||||
e.setStatus(CanteenDeliveryOrderStatus.SCHEDULED_PENDING);
|
||||
updateById(e);
|
||||
if (!isMerchantAccepted(e)) {
|
||||
return;
|
||||
}
|
||||
if (e.getRiderUserId() != null) {
|
||||
return;
|
||||
}
|
||||
if (e.getStatus() != CanteenDeliveryOrderStatus.PENDING_ASSIGN) {
|
||||
return;
|
||||
}
|
||||
assignRiderOnCreate(e);
|
||||
updateById(e);
|
||||
scheduleRiderPushAfterAssign(e);
|
||||
}
|
||||
@@ -728,6 +822,388 @@ public class CanteenDeliveryOrderServiceImpl extends ServiceImpl<CanteenDelivery
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public CanteenDeliveryRiderCommissionSummaryVO commissionSummaryForRider(Long riderUserId) {
|
||||
LocalDate today = LocalDate.now();
|
||||
LocalDateTime dayStart = today.atStartOfDay();
|
||||
LocalDateTime dayEnd = today.plusDays(1).atStartOfDay();
|
||||
LocalDateTime monthStart = today.withDayOfMonth(1).atStartOfDay();
|
||||
LocalDateTime monthEnd = today.withDayOfMonth(1).plusMonths(1).atStartOfDay();
|
||||
|
||||
CanteenDeliveryRiderCommissionSummaryVO vo = new CanteenDeliveryRiderCommissionSummaryVO();
|
||||
vo.setTodayAmt(sumRiderCommission(riderUserId, dayStart, dayEnd));
|
||||
vo.setMonthAmt(sumRiderCommission(riderUserId, monthStart, monthEnd));
|
||||
vo.setTodayOrderCount(countRiderCommissionOrders(riderUserId, dayStart, dayEnd));
|
||||
vo.setMonthOrderCount(countRiderCommissionOrders(riderUserId, monthStart, monthEnd));
|
||||
return vo;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CanteenDeliveryRiderCommissionQueryVO commissionQueryForRider(Long riderUserId, LocalDate startDate, LocalDate endDate) {
|
||||
if (startDate == null || endDate == null) {
|
||||
throw new IllegalArgumentException("开始日期与结束日期不能为空");
|
||||
}
|
||||
if (endDate.isBefore(startDate)) {
|
||||
throw new IllegalArgumentException("结束日期不能早于开始日期");
|
||||
}
|
||||
LocalDateTime start = startDate.atStartOfDay();
|
||||
LocalDateTime end = endDate.plusDays(1).atStartOfDay();
|
||||
|
||||
CanteenDeliveryRiderCommissionQueryVO vo = new CanteenDeliveryRiderCommissionQueryVO();
|
||||
vo.setStartDate(startDate);
|
||||
vo.setEndDate(endDate);
|
||||
vo.setTotalAmt(sumRiderCommission(riderUserId, start, end));
|
||||
vo.setOrderCount(countRiderCommissionOrders(riderUserId, start, end));
|
||||
return vo;
|
||||
}
|
||||
|
||||
private long sumRiderCommission(Long riderUserId, LocalDateTime startInclusive, LocalDateTime endExclusive) {
|
||||
if (riderUserId == null) {
|
||||
return 0L;
|
||||
}
|
||||
List<CanteenDeliveryOrderEntity> rows = list(buildCommissionQuery(riderUserId, startInclusive, endExclusive)
|
||||
.select(CanteenDeliveryOrderEntity::getRiderCommissionAmt));
|
||||
return rows.stream()
|
||||
.mapToLong(e -> e.getRiderCommissionAmt() != null ? e.getRiderCommissionAmt() : 0L)
|
||||
.sum();
|
||||
}
|
||||
|
||||
private long countRiderCommissionOrders(Long riderUserId, LocalDateTime startInclusive, LocalDateTime endExclusive) {
|
||||
if (riderUserId == null) {
|
||||
return 0L;
|
||||
}
|
||||
return count(buildCommissionQuery(riderUserId, startInclusive, endExclusive));
|
||||
}
|
||||
|
||||
private LambdaQueryWrapper<CanteenDeliveryOrderEntity> buildCommissionQuery(Long riderUserId,
|
||||
LocalDateTime startInclusive,
|
||||
LocalDateTime endExclusive) {
|
||||
return Wrappers.<CanteenDeliveryOrderEntity>lambdaQuery()
|
||||
.eq(CanteenDeliveryOrderEntity::getRiderUserId, riderUserId)
|
||||
.isNotNull(CanteenDeliveryOrderEntity::getRiderAssignedTime)
|
||||
.ge(CanteenDeliveryOrderEntity::getRiderAssignedTime, startInclusive)
|
||||
.lt(CanteenDeliveryOrderEntity::getRiderAssignedTime, endExclusive)
|
||||
.ne(CanteenDeliveryOrderEntity::getStatus, CanteenDeliveryOrderStatus.CANCELLED)
|
||||
.isNotNull(CanteenDeliveryOrderEntity::getRiderCommissionAmt);
|
||||
}
|
||||
|
||||
@Override
|
||||
public R<CanteenDeliveryMerchantStatsSummaryVO> merchantStatsSummary() {
|
||||
R<List<String>> mchIdsR = resolveMerchantIdStringsForLoginUser();
|
||||
if (!mchIdsR.isOk()) {
|
||||
return R.failed(mchIdsR.getMsg());
|
||||
}
|
||||
List<String> merchantIds = mchIdsR.getData();
|
||||
LocalDate today = LocalDate.now();
|
||||
LocalDateTime dayStart = today.atStartOfDay();
|
||||
LocalDateTime dayEnd = today.plusDays(1).atStartOfDay();
|
||||
LocalDateTime monthStart = today.withDayOfMonth(1).atStartOfDay();
|
||||
LocalDateTime monthEnd = today.withDayOfMonth(1).plusMonths(1).atStartOfDay();
|
||||
|
||||
CanteenDeliveryMerchantStatsSummaryVO vo = new CanteenDeliveryMerchantStatsSummaryVO();
|
||||
vo.setTodayOrderCount(countMerchantAcceptedOrders(merchantIds, dayStart, dayEnd));
|
||||
vo.setTodayOrderAmount(sumMerchantAcceptedAmount(merchantIds, dayStart, dayEnd));
|
||||
vo.setMonthOrderAmount(sumMerchantAcceptedAmount(merchantIds, monthStart, monthEnd));
|
||||
return R.ok(vo);
|
||||
}
|
||||
|
||||
@Override
|
||||
public R<CanteenDeliveryMerchantStatsMonthVO> merchantStatsByMonth(String month) {
|
||||
R<List<String>> mchIdsR = resolveMerchantIdStringsForLoginUser();
|
||||
if (!mchIdsR.isOk()) {
|
||||
return R.failed(mchIdsR.getMsg());
|
||||
}
|
||||
YearMonth ym;
|
||||
try {
|
||||
ym = YearMonth.parse(month.trim());
|
||||
} catch (DateTimeParseException ex) {
|
||||
return R.failed("月份格式应为 yyyy-MM");
|
||||
}
|
||||
LocalDateTime start = ym.atDay(1).atStartOfDay();
|
||||
LocalDateTime end = ym.plusMonths(1).atDay(1).atStartOfDay();
|
||||
CanteenDeliveryMerchantStatsMonthVO vo = new CanteenDeliveryMerchantStatsMonthVO();
|
||||
vo.setMonth(ym.toString());
|
||||
vo.setOrderCount(countMerchantAcceptedOrders(mchIdsR.getData(), start, end));
|
||||
vo.setTotalAmount(sumMerchantAcceptedAmount(mchIdsR.getData(), start, end));
|
||||
return R.ok(vo);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public R<Void> merchantAcceptOrder(Long deliveryOrderId) {
|
||||
R<List<String>> mchIdsR = resolveMerchantIdStringsForLoginUser();
|
||||
if (!mchIdsR.isOk()) {
|
||||
return R.failed(mchIdsR.getMsg());
|
||||
}
|
||||
return merchantAcceptInternal(deliveryOrderId, mchIdsR.getData());
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public R<Void> riderAcceptOrder(Long riderUserId, Long deliveryOrderId) {
|
||||
CanteenDeliveryOrderEntity e = getById(deliveryOrderId);
|
||||
if (e == null || !Objects.equals(e.getRiderUserId(), riderUserId)) {
|
||||
return R.failed("订单不存在或无权操作");
|
||||
}
|
||||
if (!Objects.equals(e.getStatus(), CanteenDeliveryOrderStatus.RIDER_PENDING_ACCEPT)) {
|
||||
return R.failed("当前状态不可接单");
|
||||
}
|
||||
e.setRiderAccepted(1);
|
||||
e.setRiderAcceptTime(LocalDateTime.now());
|
||||
e.setStatus(CanteenDeliveryOrderStatus.WAIT_PICKUP);
|
||||
updateById(e);
|
||||
return R.ok();
|
||||
}
|
||||
|
||||
@Override
|
||||
public R<CanteenDeliveryAutoAcceptVO> getMerchantAutoAccept() {
|
||||
R<List<String>> mchIdsR = resolveMerchantIdStringsForLoginUser();
|
||||
if (!mchIdsR.isOk()) {
|
||||
return R.failed(mchIdsR.getMsg());
|
||||
}
|
||||
if (CollUtil.isEmpty(mchIdsR.getData())) {
|
||||
return R.failed("商户不存在");
|
||||
}
|
||||
String merchantId = mchIdsR.getData().get(0);
|
||||
CanteenDeliveryAutoAcceptVO vo = new CanteenDeliveryAutoAcceptVO();
|
||||
vo.setMerchantId(merchantId);
|
||||
vo.setAutoAccept(isMerchantAutoAccept(merchantId));
|
||||
return R.ok(vo);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public R<CanteenDeliveryAutoAcceptVO> saveMerchantAutoAccept(Boolean autoAccept) {
|
||||
R<List<String>> mchIdsR = resolveMerchantIdStringsForLoginUser();
|
||||
if (!mchIdsR.isOk()) {
|
||||
return R.failed(mchIdsR.getMsg());
|
||||
}
|
||||
if (CollUtil.isEmpty(mchIdsR.getData())) {
|
||||
return R.failed("商户不存在");
|
||||
}
|
||||
String merchantId = mchIdsR.getData().get(0);
|
||||
saveMerchantAutoAcceptSetting(merchantId, Boolean.TRUE.equals(autoAccept));
|
||||
if (Boolean.TRUE.equals(autoAccept)) {
|
||||
autoAcceptPendingMerchantOrders(merchantId);
|
||||
}
|
||||
CanteenDeliveryAutoAcceptVO vo = new CanteenDeliveryAutoAcceptVO();
|
||||
vo.setMerchantId(merchantId);
|
||||
vo.setAutoAccept(Boolean.TRUE.equals(autoAccept));
|
||||
return R.ok(vo);
|
||||
}
|
||||
|
||||
@Override
|
||||
public R<CanteenDeliveryAutoAcceptVO> getRiderAutoAccept(Long riderUserId) {
|
||||
CanteenDeliveryAutoAcceptVO vo = new CanteenDeliveryAutoAcceptVO();
|
||||
vo.setRiderUserId(riderUserId);
|
||||
vo.setAutoAccept(isRiderAutoAccept(riderUserId));
|
||||
return R.ok(vo);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public R<CanteenDeliveryAutoAcceptVO> saveRiderAutoAccept(Long riderUserId, Boolean autoAccept) {
|
||||
saveRiderAutoAcceptSetting(riderUserId, Boolean.TRUE.equals(autoAccept));
|
||||
if (Boolean.TRUE.equals(autoAccept)) {
|
||||
autoAcceptPendingRiderOrders(riderUserId);
|
||||
}
|
||||
CanteenDeliveryAutoAcceptVO vo = new CanteenDeliveryAutoAcceptVO();
|
||||
vo.setRiderUserId(riderUserId);
|
||||
vo.setAutoAccept(Boolean.TRUE.equals(autoAccept));
|
||||
return R.ok(vo);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void tryMerchantAutoAccept(Long deliveryOrderId) {
|
||||
CanteenDeliveryOrderEntity e = getById(deliveryOrderId);
|
||||
if (e == null || isMerchantAccepted(e)) {
|
||||
return;
|
||||
}
|
||||
if (!Objects.equals(e.getStatus(), CanteenDeliveryOrderStatus.MERCHANT_PENDING)) {
|
||||
return;
|
||||
}
|
||||
if (!isMerchantAutoAccept(e.getMerchantId())) {
|
||||
return;
|
||||
}
|
||||
merchantAcceptInternal(e.getId(), List.of(e.getMerchantId()));
|
||||
}
|
||||
|
||||
private R<Void> merchantAcceptInternal(Long deliveryOrderId, List<String> merchantIds) {
|
||||
CanteenDeliveryOrderEntity e = getOne(Wrappers.<CanteenDeliveryOrderEntity>lambdaQuery()
|
||||
.eq(CanteenDeliveryOrderEntity::getId, deliveryOrderId)
|
||||
.last("FOR UPDATE"));
|
||||
if (e == null || StrUtil.isBlank(e.getMerchantId()) || !merchantIds.contains(e.getMerchantId())) {
|
||||
return R.failed("订单不存在或无权操作");
|
||||
}
|
||||
if (!merchantScheduledOrderVisibleToMerchant(e)) {
|
||||
return R.failed("订单不存在或无权操作");
|
||||
}
|
||||
if (isMerchantAccepted(e)) {
|
||||
return R.failed("订单已接单");
|
||||
}
|
||||
if (!Objects.equals(e.getStatus(), CanteenDeliveryOrderStatus.MERCHANT_PENDING)) {
|
||||
return R.failed("当前状态不可接单");
|
||||
}
|
||||
e.setMerchantAccepted(1);
|
||||
e.setMerchantAcceptTime(LocalDateTime.now());
|
||||
assignRiderOnCreate(e);
|
||||
updateById(e);
|
||||
scheduleRiderPushAfterAssign(e);
|
||||
return R.ok();
|
||||
}
|
||||
|
||||
private void scheduleTryMerchantAutoAcceptAfterCommit(Long deliveryOrderId) {
|
||||
if (deliveryOrderId == null || deliveryOrderServiceSelf == null) {
|
||||
return;
|
||||
}
|
||||
if (TransactionSynchronizationManager.isSynchronizationActive()) {
|
||||
TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() {
|
||||
@Override
|
||||
public void afterCommit() {
|
||||
deliveryOrderServiceSelf.tryMerchantAutoAccept(deliveryOrderId);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
deliveryOrderServiceSelf.tryMerchantAutoAccept(deliveryOrderId);
|
||||
}
|
||||
}
|
||||
|
||||
private void autoAcceptPendingMerchantOrders(String merchantId) {
|
||||
List<CanteenDeliveryOrderEntity> pending = list(Wrappers.<CanteenDeliveryOrderEntity>lambdaQuery()
|
||||
.eq(CanteenDeliveryOrderEntity::getMerchantId, merchantId)
|
||||
.eq(CanteenDeliveryOrderEntity::getStatus, CanteenDeliveryOrderStatus.MERCHANT_PENDING)
|
||||
.eq(CanteenDeliveryOrderEntity::getMerchantAccepted, 0)
|
||||
.last("LIMIT 200"));
|
||||
for (CanteenDeliveryOrderEntity row : pending) {
|
||||
try {
|
||||
merchantAcceptInternal(row.getId(), List.of(merchantId));
|
||||
} catch (Exception ex) {
|
||||
log.warn("autoAcceptPendingMerchantOrders id={}", row.getId(), ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void autoAcceptPendingRiderOrders(Long riderUserId) {
|
||||
List<CanteenDeliveryOrderEntity> pending = list(Wrappers.<CanteenDeliveryOrderEntity>lambdaQuery()
|
||||
.eq(CanteenDeliveryOrderEntity::getRiderUserId, riderUserId)
|
||||
.eq(CanteenDeliveryOrderEntity::getStatus, CanteenDeliveryOrderStatus.RIDER_PENDING_ACCEPT)
|
||||
.eq(CanteenDeliveryOrderEntity::getRiderAccepted, 0)
|
||||
.last("LIMIT 200"));
|
||||
for (CanteenDeliveryOrderEntity row : pending) {
|
||||
try {
|
||||
riderAcceptOrder(riderUserId, row.getId());
|
||||
} catch (Exception ex) {
|
||||
log.warn("autoAcceptPendingRiderOrders id={}", row.getId(), ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private long countMerchantAcceptedOrders(List<String> merchantIds, LocalDateTime start, LocalDateTime end) {
|
||||
if (CollUtil.isEmpty(merchantIds)) {
|
||||
return 0L;
|
||||
}
|
||||
return count(buildMerchantStatsQuery(merchantIds, start, end));
|
||||
}
|
||||
|
||||
private long sumMerchantAcceptedAmount(List<String> merchantIds, LocalDateTime start, LocalDateTime end) {
|
||||
if (CollUtil.isEmpty(merchantIds)) {
|
||||
return 0L;
|
||||
}
|
||||
List<CanteenDeliveryOrderEntity> rows = list(buildMerchantStatsQuery(merchantIds, start, end)
|
||||
.select(CanteenDeliveryOrderEntity::getOrderAmount));
|
||||
return rows.stream().mapToLong(e -> e.getOrderAmount() != null ? e.getOrderAmount() : 0L).sum();
|
||||
}
|
||||
|
||||
private LambdaQueryWrapper<CanteenDeliveryOrderEntity> buildMerchantStatsQuery(List<String> merchantIds,
|
||||
LocalDateTime start,
|
||||
LocalDateTime end) {
|
||||
return Wrappers.<CanteenDeliveryOrderEntity>lambdaQuery()
|
||||
.in(CanteenDeliveryOrderEntity::getMerchantId, merchantIds)
|
||||
.eq(CanteenDeliveryOrderEntity::getMerchantAccepted, 1)
|
||||
.ne(CanteenDeliveryOrderEntity::getStatus, CanteenDeliveryOrderStatus.CANCELLED)
|
||||
.isNotNull(CanteenDeliveryOrderEntity::getMerchantAcceptTime)
|
||||
.ge(CanteenDeliveryOrderEntity::getMerchantAcceptTime, start)
|
||||
.lt(CanteenDeliveryOrderEntity::getMerchantAcceptTime, end);
|
||||
}
|
||||
|
||||
private int calcOrderAmountFromCart(List<CanteenDeliveryCartItemDTO> carList) {
|
||||
if (CollUtil.isEmpty(carList)) {
|
||||
return 0;
|
||||
}
|
||||
int sum = 0;
|
||||
for (CanteenDeliveryCartItemDTO c : carList) {
|
||||
if (c == null) {
|
||||
continue;
|
||||
}
|
||||
if (c.getTotalPrice() != null && StrUtil.isNotBlank(String.valueOf(c.getTotalPrice()))) {
|
||||
try {
|
||||
sum += Integer.parseInt(String.valueOf(c.getTotalPrice()).trim());
|
||||
continue;
|
||||
} catch (NumberFormatException ignored) {
|
||||
}
|
||||
}
|
||||
int price = c.getProductPrice() != null ? c.getProductPrice() : 0;
|
||||
int cnt = c.getProductCount() != null ? c.getProductCount() : 0;
|
||||
sum += price * cnt;
|
||||
}
|
||||
return Math.max(0, sum);
|
||||
}
|
||||
|
||||
private boolean isMerchantAccepted(CanteenDeliveryOrderEntity e) {
|
||||
return e != null && Objects.equals(e.getMerchantAccepted(), 1);
|
||||
}
|
||||
|
||||
private boolean isMerchantAutoAccept(String merchantId) {
|
||||
if (StrUtil.isBlank(merchantId)) {
|
||||
return false;
|
||||
}
|
||||
CanteenDeliveryAcceptSettingEntity row = acceptSettingMapper.selectOne(
|
||||
Wrappers.<CanteenDeliveryAcceptSettingEntity>lambdaQuery()
|
||||
.eq(CanteenDeliveryAcceptSettingEntity::getMerchantId, merchantId));
|
||||
return row != null && Objects.equals(row.getAutoAccept(), 1);
|
||||
}
|
||||
|
||||
private boolean isRiderAutoAccept(Long riderUserId) {
|
||||
if (riderUserId == null) {
|
||||
return false;
|
||||
}
|
||||
CanteenDeliveryAcceptSettingEntity row = acceptSettingMapper.selectOne(
|
||||
Wrappers.<CanteenDeliveryAcceptSettingEntity>lambdaQuery()
|
||||
.eq(CanteenDeliveryAcceptSettingEntity::getRiderUserId, riderUserId));
|
||||
return row != null && Objects.equals(row.getAutoAccept(), 1);
|
||||
}
|
||||
|
||||
private void saveMerchantAutoAcceptSetting(String merchantId, boolean autoAccept) {
|
||||
CanteenDeliveryAcceptSettingEntity row = acceptSettingMapper.selectOne(
|
||||
Wrappers.<CanteenDeliveryAcceptSettingEntity>lambdaQuery()
|
||||
.eq(CanteenDeliveryAcceptSettingEntity::getMerchantId, merchantId));
|
||||
if (row == null) {
|
||||
row = new CanteenDeliveryAcceptSettingEntity();
|
||||
row.setMerchantId(merchantId);
|
||||
row.setAutoAccept(autoAccept ? 1 : 0);
|
||||
acceptSettingMapper.insert(row);
|
||||
return;
|
||||
}
|
||||
row.setAutoAccept(autoAccept ? 1 : 0);
|
||||
acceptSettingMapper.updateById(row);
|
||||
}
|
||||
|
||||
private void saveRiderAutoAcceptSetting(Long riderUserId, boolean autoAccept) {
|
||||
CanteenDeliveryAcceptSettingEntity row = acceptSettingMapper.selectOne(
|
||||
Wrappers.<CanteenDeliveryAcceptSettingEntity>lambdaQuery()
|
||||
.eq(CanteenDeliveryAcceptSettingEntity::getRiderUserId, riderUserId));
|
||||
if (row == null) {
|
||||
row = new CanteenDeliveryAcceptSettingEntity();
|
||||
row.setRiderUserId(riderUserId);
|
||||
row.setAutoAccept(autoAccept ? 1 : 0);
|
||||
acceptSettingMapper.insert(row);
|
||||
return;
|
||||
}
|
||||
row.setAutoAccept(autoAccept ? 1 : 0);
|
||||
acceptSettingMapper.updateById(row);
|
||||
}
|
||||
|
||||
/**
|
||||
* 来源订单号即硬件外卖订单主键(与同步时 dto.id 一致)。非数字则跳过(非硬件单)。
|
||||
* 同步失败抛异常,触发事务回滚,避免本地状态与硬件订单不一致。
|
||||
|
||||
+7
@@ -69,6 +69,13 @@ public interface RemoteWalletService {
|
||||
@GetMapping("/wallet-manage/inner/is-use-door")
|
||||
R<String> innserIsUseDoor(@RequestParam Long userId);
|
||||
|
||||
/**
|
||||
* 商户配送费(分),供食堂外送派单时快照骑手佣金
|
||||
*/
|
||||
@NoToken
|
||||
@GetMapping("/wallet-manage/inner/mch-take-out-amt")
|
||||
R<Integer> innerMchTakeOutAmt(@RequestParam("merchantId") Long merchantId);
|
||||
|
||||
@NoToken
|
||||
@PostMapping("/wallet-active/remote/open-card-list")
|
||||
R<Page<WalletActiveEntity>> remoteOpenCardList(@RequestBody WalletRemoteOpenCardListDto body);
|
||||
|
||||
+14
@@ -148,6 +148,20 @@ public class WalletManageController {
|
||||
return R.ok(true);
|
||||
}
|
||||
|
||||
@Inner
|
||||
@GetMapping("/inner/mch-take-out-amt")
|
||||
@Operation(summary = "内部-商户配送费(分)", description = "派单时快照骑手佣金;返回 mch_take_out_setting.mch_take_out_amt")
|
||||
public R<Integer> innerMchTakeOutAmt(@RequestParam Long merchantId) {
|
||||
if (merchantId == null) {
|
||||
return R.ok(0);
|
||||
}
|
||||
MchTakeOutSettingEntity setting = walletManageService.getOrCreateTakeOut(merchantId);
|
||||
if (setting == null || setting.getMchTakeOutAmt() == null) {
|
||||
return R.ok(0);
|
||||
}
|
||||
return R.ok(Math.max(0, setting.getMchTakeOutAmt()));
|
||||
}
|
||||
|
||||
@GetMapping("/dept-change")
|
||||
public R<Boolean> deptChange(@RequestParam Long deptId, @RequestParam Boolean isDel) {
|
||||
walletManageService.deptChange(deptId, isDel);
|
||||
|
||||
Reference in new issue
Block a user