4.12新需求修改
This commit is contained in:
parent
8ec2796770
commit
b4eee35c1f
@ -6,6 +6,7 @@ import lombok.RequiredArgsConstructor;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import jakarta.validation.constraints.*;
|
||||
import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||
import org.asinkj.amz.domain.vo.InquiryRequestItemVo;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.asinkj.common.idempotent.annotation.RepeatSubmit;
|
||||
@ -72,6 +73,13 @@ public class BizInquiryRequestController extends BaseController {
|
||||
return bizInquiryRequestService.createWithDesAndChannel(destination, channelId,date);
|
||||
}
|
||||
|
||||
@SaCheckPermission("amz:shipmentPlan:edit")
|
||||
@PostMapping("/create/batch")
|
||||
@RepeatSubmit
|
||||
public R<String> batchCreateWithItems(@RequestBody List<InquiryRequestItemVo> items) {
|
||||
return bizInquiryRequestService.batchCreateWithItems(items);
|
||||
}
|
||||
|
||||
/**
|
||||
* 导出物流询价列表
|
||||
*/
|
||||
|
@ -89,6 +89,16 @@ public class BizShipmentPlanController extends BaseController {
|
||||
return toAjax(bizShipmentPlanService.insertByBo(bo));
|
||||
}
|
||||
|
||||
@SaCheckPermission("amz:shipmentPlan:add")
|
||||
@Log(title = "货件计划", businessType = BusinessType.INSERT)
|
||||
@RepeatSubmit()
|
||||
@PostMapping("/update/list/{status}")
|
||||
public R<Void> updateList( @RequestBody List<String> list, @PathVariable String status) {
|
||||
|
||||
bizShipmentPlanService.updateList(list, status);
|
||||
return R.ok();
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改货件计划
|
||||
*/
|
||||
|
@ -1,5 +1,6 @@
|
||||
package org.asinkj.amz.domain;
|
||||
|
||||
import org.asinkj.asinking.entity.FbaShipmentApiResponse;
|
||||
import org.asinkj.common.tenant.core.TenantEntity;
|
||||
import com.baomidou.mybatisplus.annotation.*;
|
||||
import lombok.Data;
|
||||
@ -7,6 +8,7 @@ import lombok.EqualsAndHashCode;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Date;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import org.springframework.format.annotation.DateTimeFormat;
|
||||
|
||||
@ -104,4 +106,7 @@ public class BizInquiryRequest extends TenantEntity {
|
||||
private Date quoteDate;
|
||||
|
||||
|
||||
private FbaShipmentApiResponse.Address shipToAddress;
|
||||
|
||||
|
||||
}
|
||||
|
@ -110,4 +110,10 @@ public class BizLogisticsQuote extends TenantEntity {
|
||||
private Long inquiryId;
|
||||
|
||||
|
||||
/**
|
||||
* 后端物流类型
|
||||
*/
|
||||
private String backLogisticsType;
|
||||
|
||||
|
||||
}
|
||||
|
@ -2,10 +2,12 @@ package org.asinkj.amz.domain.vo;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Date;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import org.asinkj.amz.domain.BizInquiryRequest;
|
||||
import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
|
||||
import com.alibaba.excel.annotation.ExcelProperty;
|
||||
import org.asinkj.asinking.entity.FbaShipmentApiResponse;
|
||||
import org.asinkj.common.excel.annotation.ExcelDictFormat;
|
||||
import org.asinkj.common.excel.convert.ExcelDictConvert;
|
||||
import io.github.linpeilie.annotations.AutoMapper;
|
||||
@ -16,7 +18,6 @@ import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 物流询价视图对象 biz_inquiry_request
|
||||
*
|
||||
@ -120,5 +121,7 @@ public class BizInquiryRequestVo implements Serializable {
|
||||
*/
|
||||
private Date quoteDate;
|
||||
|
||||
private FbaShipmentApiResponse.Address shipToAddress;
|
||||
|
||||
|
||||
}
|
||||
|
@ -129,4 +129,9 @@ public class BizLogisticsQuoteVo implements Serializable {
|
||||
|
||||
|
||||
|
||||
|
||||
private String backLogisticsType;
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,58 @@
|
||||
package org.asinkj.amz.domain.vo;
|
||||
|
||||
import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
|
||||
import com.alibaba.excel.annotation.ExcelProperty;
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import io.github.linpeilie.annotations.AutoMapper;
|
||||
import lombok.Data;
|
||||
import org.asinkj.amz.domain.BizInquiryRequest;
|
||||
import org.asinkj.asinking.entity.FbaShipmentApiResponse;
|
||||
import org.asinkj.common.excel.annotation.ExcelDictFormat;
|
||||
import org.asinkj.common.excel.convert.ExcelDictConvert;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Date;
|
||||
|
||||
|
||||
/**
|
||||
* 物流询价视图对象 biz_inquiry_request
|
||||
*
|
||||
* @author shuo hu
|
||||
* @date 2025-03-21
|
||||
*/
|
||||
@Data
|
||||
@ExcelIgnoreUnannotated
|
||||
@AutoMapper(target = BizInquiryRequest.class)
|
||||
public class InquiryRequestItemVo implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private String shipmentId;
|
||||
/**
|
||||
* 目的地(存储四级行政编码,如CN310115)
|
||||
*/
|
||||
@ExcelProperty(value = "目的地", converter = ExcelDictConvert.class)
|
||||
@ExcelDictFormat(readConverterExp = "存=储四级行政编码,如CN310115")
|
||||
private String destination;
|
||||
|
||||
|
||||
/**
|
||||
* 渠道ID(system=dict_code,custom=自定义渠道ID)
|
||||
*/
|
||||
@ExcelProperty(value = "渠道ID")
|
||||
private Long channelId;
|
||||
|
||||
/**
|
||||
* 报价目标日期
|
||||
*/
|
||||
@JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8")
|
||||
private Date quoteDate;
|
||||
|
||||
|
||||
private FbaShipmentApiResponse.Address shipToAddress;
|
||||
|
||||
|
||||
}
|
@ -4,6 +4,7 @@ import jakarta.validation.constraints.NotNull;
|
||||
import org.asinkj.amz.domain.BizInquiryRequest;
|
||||
import org.asinkj.amz.domain.vo.BizInquiryRequestVo;
|
||||
import org.asinkj.amz.domain.bo.BizInquiryRequestBo;
|
||||
import org.asinkj.amz.domain.vo.InquiryRequestItemVo;
|
||||
import org.asinkj.common.core.domain.R;
|
||||
import org.asinkj.common.mybatis.core.page.TableDataInfo;
|
||||
import org.asinkj.common.mybatis.core.page.PageQuery;
|
||||
@ -71,5 +72,8 @@ public interface IBizInquiryRequestService {
|
||||
|
||||
R<String> createWithDesAndChannel(@NotNull(message = "目的地不能为空") String destination, @NotNull(message = "渠道不能为空") String channelId, @NotNull(message = "日期不能为空") String date);
|
||||
|
||||
|
||||
R<String> batchCreateWithItems(List<InquiryRequestItemVo> items);
|
||||
|
||||
TableDataInfo<BizInquiryRequestVo> queryWithDesAndChannel(@NotNull(message = "目的地不能为空") String destination, @NotNull(message = "渠道不能为空") String channelId, @NotNull(message = "日期不能为空") String date);
|
||||
}
|
||||
|
@ -77,4 +77,8 @@ public interface IBizShipmentPlanService {
|
||||
void takeTodayAmzPlanData();
|
||||
|
||||
TableDataInfo<BizShipmentPlanOrderVo> queryPageListOrder(BizShipmentPlanBo bo, PageQuery pageQuery);
|
||||
|
||||
void updateStatusbyFbaShipmentIds(List<String> fbaShipmentids);
|
||||
|
||||
void updateList(Collection<String> list, String status);
|
||||
}
|
||||
|
@ -1,13 +1,16 @@
|
||||
package org.asinkj.amz.service.impl;
|
||||
|
||||
import cn.hutool.core.collection.CollectionUtil;
|
||||
import cn.hutool.core.date.DateTime;
|
||||
import cn.hutool.core.date.DateUtil;
|
||||
import cn.hutool.core.util.NumberUtil;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.asinkj.amz.domain.BizLogisticsQuote;
|
||||
import org.asinkj.amz.domain.vo.BizLogisticsChannelVo;
|
||||
import org.asinkj.amz.domain.vo.InquiryRequestItemVo;
|
||||
import org.asinkj.amz.mapper.BizLogisticsQuoteMapper;
|
||||
import org.asinkj.amz.service.IBizLogisticsChannelService;
|
||||
import org.asinkj.amz.service.IBizShipmentPlanService;
|
||||
import org.asinkj.common.core.domain.R;
|
||||
import org.asinkj.common.core.utils.MapstructUtils;
|
||||
import org.asinkj.common.core.utils.StringUtils;
|
||||
@ -17,10 +20,13 @@ import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.asinkj.common.redis.annotation.DistributedLock;
|
||||
import org.asinkj.common.redis.utils.RedisUtils;
|
||||
import org.asinkj.common.satoken.utils.LoginHelper;
|
||||
import org.asinkj.resource.api.RemoteMessageService;
|
||||
import org.asinkj.utils.SerialNoGenerator;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.redisson.api.RLock;
|
||||
import org.springframework.dao.DuplicateKeyException;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.asinkj.amz.domain.bo.BizInquiryRequestBo;
|
||||
import org.asinkj.amz.domain.vo.BizInquiryRequestVo;
|
||||
@ -29,12 +35,12 @@ import org.asinkj.amz.mapper.BizInquiryRequestMapper;
|
||||
import org.asinkj.amz.service.IBizInquiryRequestService;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.time.DayOfWeek;
|
||||
import java.time.LocalDate;
|
||||
import java.time.temporal.TemporalAdjusters;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* 物流询价Service业务层处理
|
||||
@ -64,6 +70,10 @@ public class BizInquiryRequestServiceImpl implements IBizInquiryRequestService {
|
||||
@Resource
|
||||
private RemoteMessageService remoteMessageService;
|
||||
|
||||
@Resource
|
||||
private IBizShipmentPlanService bizShipmentPlanService;
|
||||
|
||||
|
||||
/**
|
||||
* 查询物流询价
|
||||
*
|
||||
@ -71,7 +81,7 @@ public class BizInquiryRequestServiceImpl implements IBizInquiryRequestService {
|
||||
* @return 物流询价
|
||||
*/
|
||||
@Override
|
||||
public BizInquiryRequestVo queryById(Long id){
|
||||
public BizInquiryRequestVo queryById(Long id) {
|
||||
return baseMapper.selectVoById(id);
|
||||
}
|
||||
|
||||
@ -151,7 +161,7 @@ public class BizInquiryRequestServiceImpl implements IBizInquiryRequestService {
|
||||
/**
|
||||
* 保存前的数据校验
|
||||
*/
|
||||
private void validEntityBeforeSave(BizInquiryRequest entity){
|
||||
private void validEntityBeforeSave(BizInquiryRequest entity) {
|
||||
//TODO 做一些数据校验,如唯一约束
|
||||
}
|
||||
|
||||
@ -164,16 +174,14 @@ public class BizInquiryRequestServiceImpl implements IBizInquiryRequestService {
|
||||
*/
|
||||
@Override
|
||||
public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
|
||||
if(isValid){
|
||||
if (isValid) {
|
||||
//TODO 做一些业务上的校验,判断是否需要校验
|
||||
}
|
||||
return baseMapper.deleteByIds(ids) > 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public R<String> createWithDesAndChannel(String destination, String channelId,String date) {
|
||||
|
||||
|
||||
public R<String> createWithDesAndChannel(String destination, String channelId, String date) {
|
||||
|
||||
|
||||
BizInquiryRequest bizInquiryRequest = new BizInquiryRequest();
|
||||
@ -192,13 +200,13 @@ public class BizInquiryRequestServiceImpl implements IBizInquiryRequestService {
|
||||
//查询出渠道信息
|
||||
|
||||
BizLogisticsChannelVo bizLogisticsChannelVo = bizLogisticsChannelService.queryById(bizInquiryRequest.getChannelId());
|
||||
if (bizLogisticsChannelVo == null){
|
||||
if (bizLogisticsChannelVo == null) {
|
||||
log.info("渠道信息为空");
|
||||
}
|
||||
if ("air".equals(bizLogisticsChannelVo.getShippingMethod())){
|
||||
if ("air".equals(bizLogisticsChannelVo.getShippingMethod())) {
|
||||
bizInquiryRequest.setEffectiveStartTime(new Date());
|
||||
bizInquiryRequest.setEffectiveEndTime(new Date());
|
||||
}else if("sea".equals(bizLogisticsChannelVo.getShippingMethod())){
|
||||
} else if ("sea".equals(bizLogisticsChannelVo.getShippingMethod())) {
|
||||
//获取本周的周日上个周六的日期
|
||||
LocalDate sunday = LocalDate.now().with(TemporalAdjusters.previousOrSame(DayOfWeek.SUNDAY));
|
||||
LocalDate saturday = sunday.plusDays(6);
|
||||
@ -213,18 +221,212 @@ public class BizInquiryRequestServiceImpl implements IBizInquiryRequestService {
|
||||
bizInquiryRequest.setTransportChannel(bizLogisticsChannelVo.getShippingMethod());
|
||||
//获取当天上午11点的时间 ?
|
||||
bizInquiryRequest.setDeadline(LocalDate.now()
|
||||
.atTime(11, 0));
|
||||
.atTime(11, 0));
|
||||
bizInquiryRequest.setRequesterId(LoginHelper.getUserId());
|
||||
DateTime dateTime = DateUtil.parseDate(date);
|
||||
bizInquiryRequest.setQuoteDate(dateTime);
|
||||
|
||||
billingRequestMapper.insert(bizInquiryRequest);
|
||||
|
||||
remoteMessageService.publishMessage(LoginHelper.getUserId(), "您好,您的询价单创建成功。具体询价单号为:"+bizInquiryRequest.getInquiryNo());
|
||||
remoteMessageService.publishMessage(LoginHelper.getUserId(), "您好,您的询价单创建成功。具体询价单号为:" + bizInquiryRequest.getInquiryNo());
|
||||
|
||||
return R.ok(bizInquiryRequest.getInquiryNo());
|
||||
}
|
||||
|
||||
|
||||
// @Override
|
||||
// public R<String> batchCreateWithItems(List<InquiryRequestItemVo> items) {
|
||||
//
|
||||
// if (CollectionUtil.isEmpty(items)) {
|
||||
// return R.fail("询价单不能为空");
|
||||
// }
|
||||
//
|
||||
// List<InquiryRequestItemVo> requests = fiterItemsList(items);
|
||||
// if (CollectionUtil.isEmpty(requests)) {
|
||||
// return R.warn("已经有相同的询价了");
|
||||
// }
|
||||
// List<BizInquiryRequest> bizInquiryRequests = new ArrayList<>();
|
||||
// for (InquiryRequestItemVo request : requests) {
|
||||
//
|
||||
//
|
||||
// BizInquiryRequest bizInquiryRequest = new BizInquiryRequest();
|
||||
// bizInquiryRequest.setDestination(request.getDestination());
|
||||
// bizInquiryRequest.setChannelId(request.getChannelId());
|
||||
//
|
||||
// bizInquiryRequest.setRequesterName(LoginHelper.getLoginUser().getNickname());
|
||||
// if (bizInquiryRequest.getChannelId() == null) {
|
||||
// return R.fail("渠道不能为空");
|
||||
// }
|
||||
// if (bizInquiryRequest.getDestination() == null) {
|
||||
// return R.fail("目的地不能为空");
|
||||
// }
|
||||
// //询价单号(规则:INQ+年月+6位序列)
|
||||
// bizInquiryRequest.setInquiryNo(SerialNoGenerator.generateInquiryNo());
|
||||
// //查询出渠道信息
|
||||
//
|
||||
// BizLogisticsChannelVo bizLogisticsChannelVo = bizLogisticsChannelService.queryById(bizInquiryRequest.getChannelId());
|
||||
// if (bizLogisticsChannelVo == null) {
|
||||
// log.info("渠道信息为空");
|
||||
// }
|
||||
// if ("air".equals(bizLogisticsChannelVo.getShippingMethod())) {
|
||||
// bizInquiryRequest.setEffectiveStartTime(new Date());
|
||||
// bizInquiryRequest.setEffectiveEndTime(new Date());
|
||||
// } else if ("sea".equals(bizLogisticsChannelVo.getShippingMethod())) {
|
||||
// //获取本周的周日上个周六的日期
|
||||
// LocalDate sunday = LocalDate.now().with(TemporalAdjusters.previousOrSame(DayOfWeek.SUNDAY));
|
||||
//
|
||||
// LocalDate saturday = sunday.plusDays(6);
|
||||
//
|
||||
// bizInquiryRequest.setEffectiveStartTime(DateUtil.date(sunday));
|
||||
//
|
||||
// bizInquiryRequest.setEffectiveEndTime(DateUtil.date(saturday));
|
||||
// }
|
||||
//
|
||||
// bizInquiryRequest.setChannelName(bizLogisticsChannelVo.getChannelName());
|
||||
// bizInquiryRequest.setTransportChannel(bizLogisticsChannelVo.getShippingMethod());
|
||||
// //获取当天上午11点的时间 ?
|
||||
// bizInquiryRequest.setDeadline(LocalDate.now()
|
||||
// .atTime(11, 0));
|
||||
//
|
||||
// bizInquiryRequest.setRequesterId(LoginHelper.getUserId());
|
||||
// bizInquiryRequest.setQuoteDate(request.getQuoteDate());
|
||||
// bizInquiryRequest.setShipToAddress(request.getShipToAddress());
|
||||
// bizInquiryRequests.add(bizInquiryRequest);
|
||||
// }
|
||||
// billingRequestMapper.insertBatch(bizInquiryRequests);
|
||||
//
|
||||
//// remoteMessageService.publishMessage(LoginHelper.getUserId(), "您好,您的询价单创建成功。具体询价单号为:" + bizInquiryRequest.getInquiryNo());
|
||||
//
|
||||
// return R.ok();
|
||||
// }
|
||||
|
||||
|
||||
/**
|
||||
* 创建单个询价单(带分布式锁)
|
||||
*/
|
||||
@DistributedLock(
|
||||
prefix = "inquiry:create",
|
||||
params = {"request.channelId", "request.destination"}, // 从request对象提取字段
|
||||
waitTime = 0,
|
||||
leaseTime = 30
|
||||
)
|
||||
private BizInquiryRequest createSingleInquiry(InquiryRequestItemVo request) {
|
||||
// 参数校验
|
||||
if (request.getChannelId() == null) {
|
||||
throw new RuntimeException("渠道不能为空");
|
||||
}
|
||||
if (request.getDestination() == null) {
|
||||
throw new RuntimeException("目的地不能为空");
|
||||
}
|
||||
|
||||
// 构建询价单对象
|
||||
BizInquiryRequest bizInquiryRequest = new BizInquiryRequest();
|
||||
bizInquiryRequest.setDestination(request.getDestination());
|
||||
bizInquiryRequest.setChannelId(request.getChannelId());
|
||||
bizInquiryRequest.setRequesterName(LoginHelper.getLoginUser().getNickname());
|
||||
bizInquiryRequest.setInquiryNo(SerialNoGenerator.generateInquiryNo());
|
||||
|
||||
// 查询渠道信息
|
||||
BizLogisticsChannelVo channelVo = bizLogisticsChannelService.queryById(request.getChannelId());
|
||||
if (channelVo == null) {
|
||||
throw new RuntimeException("渠道不存在");
|
||||
}
|
||||
|
||||
// 设置运输时效
|
||||
if ("air".equals(channelVo.getShippingMethod())) {
|
||||
bizInquiryRequest.setEffectiveStartTime(new Date());
|
||||
bizInquiryRequest.setEffectiveEndTime(new Date());
|
||||
} else if ("sea".equals(channelVo.getShippingMethod())) {
|
||||
LocalDate sunday = LocalDate.now().with(TemporalAdjusters.previousOrSame(DayOfWeek.SUNDAY));
|
||||
LocalDate saturday = sunday.plusDays(6);
|
||||
bizInquiryRequest.setEffectiveStartTime(DateUtil.date(sunday));
|
||||
bizInquiryRequest.setEffectiveEndTime(DateUtil.date(saturday));
|
||||
}
|
||||
|
||||
// 设置其他字段
|
||||
bizInquiryRequest.setChannelName(channelVo.getChannelName());
|
||||
bizInquiryRequest.setTransportChannel(channelVo.getShippingMethod());
|
||||
bizInquiryRequest.setDeadline(LocalDate.now().atTime(11, 0));
|
||||
bizInquiryRequest.setRequesterId(LoginHelper.getUserId());
|
||||
bizInquiryRequest.setQuoteDate(request.getQuoteDate());
|
||||
bizInquiryRequest.setShipToAddress(request.getShipToAddress());
|
||||
|
||||
return bizInquiryRequest;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public R<String> batchCreateWithItems(List<InquiryRequestItemVo> items) {
|
||||
// 1. 参数校验
|
||||
if (CollectionUtil.isEmpty(items)) {
|
||||
return R.fail("询价单不能为空");
|
||||
}
|
||||
Set<String> shipmentIds = items.stream().map(InquiryRequestItemVo::getShipmentId).collect(Collectors.toSet());
|
||||
bizShipmentPlanService.updateList(shipmentIds, "send");
|
||||
|
||||
// 2. 过滤重复请求(前置校验)
|
||||
List<InquiryRequestItemVo> requests = fiterItemsList(items);
|
||||
if (CollectionUtil.isEmpty(requests)) {
|
||||
return R.warn("已有相同询价单");
|
||||
}
|
||||
|
||||
// 3. 批量创建(每个询价单独立加锁)
|
||||
List<BizInquiryRequest> bizInquiryRequests = new ArrayList<>();
|
||||
for (InquiryRequestItemVo request : requests) {
|
||||
try {
|
||||
BizInquiryRequest item = createSingleInquiry(request);
|
||||
bizInquiryRequests.add(item);
|
||||
} catch (RuntimeException e) {
|
||||
// 捕获锁冲突或业务校验异常
|
||||
return R.fail(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
// 4. 批量插入(兜底:数据库唯一索引)
|
||||
try {
|
||||
billingRequestMapper.insertBatch(bizInquiryRequests);
|
||||
} catch (DuplicateKeyException e) {
|
||||
log.error("唯一索引拦截重复数据: {}", e.getMessage());
|
||||
return R.fail("存在重复的渠道-目的地组合");
|
||||
}
|
||||
|
||||
// 5. 发送通知(可选)
|
||||
// String inquiryNo = bizInquiryRequests.get(0).getInquiryNo();
|
||||
// remoteMessageService.publishMessage(LoginHelper.getUserId(), "询价单创建成功,单号:" + inquiryNo);
|
||||
|
||||
return R.ok();
|
||||
}
|
||||
|
||||
|
||||
|
||||
private List<InquiryRequestItemVo> fiterItemsList(List<InquiryRequestItemVo> items) {
|
||||
LambdaQueryWrapper<BizInquiryRequest> wrapper = new LambdaQueryWrapper<>();
|
||||
for (InquiryRequestItemVo item : items) {
|
||||
wrapper.or(w -> w
|
||||
.eq(BizInquiryRequest::getDestination, item.getDestination())
|
||||
.eq(BizInquiryRequest::getChannelId, item.getChannelId())
|
||||
.eq(BizInquiryRequest::getQuoteDate, item.getQuoteDate())
|
||||
);
|
||||
}
|
||||
|
||||
// 查询已存在的记录
|
||||
List<BizInquiryRequest> existingList = baseMapper.selectList(wrapper);
|
||||
|
||||
|
||||
// 将已存在的记录转为 Set 方便快速比对(假设三字段组合唯一)
|
||||
Set<String> existingKeys = existingList.stream()
|
||||
.map(e -> e.getDestination() + "_" + e.getChannelId() + "_" + e.getQuoteDate())
|
||||
.collect(Collectors.toSet());
|
||||
|
||||
// 过滤掉重复的待插入数据
|
||||
List<InquiryRequestItemVo> filteredItems = items.stream()
|
||||
.filter(item -> !existingKeys.contains(
|
||||
item.getDestination() + "_" + item.getChannelId() + "_" + item.getQuoteDate()
|
||||
))
|
||||
.collect(Collectors.toList());
|
||||
return filteredItems;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TableDataInfo<BizInquiryRequestVo> queryWithDesAndChannel(String destination, String channelId, String date) {
|
||||
LambdaQueryWrapper<BizInquiryRequest> queryWrapper = new LambdaQueryWrapper<>();
|
||||
|
@ -75,7 +75,7 @@ public class BizLogisticsOrderServiceImpl implements IBizLogisticsOrderService {
|
||||
* @return 物流订单
|
||||
*/
|
||||
@Override
|
||||
public BizLogisticsOrderVo queryById(Long id){
|
||||
public BizLogisticsOrderVo queryById(Long id) {
|
||||
return baseMapper.selectVoById(id);
|
||||
}
|
||||
|
||||
@ -118,7 +118,9 @@ public class BizLogisticsOrderServiceImpl implements IBizLogisticsOrderService {
|
||||
lqw.eq(bo.getShipmentQuantity() != null, BizLogisticsOrder::getShipmentQuantity, bo.getShipmentQuantity());
|
||||
lqw.eq(bo.getAmazonShelfDate() != null, BizLogisticsOrder::getAmazonShelfDate, bo.getAmazonShelfDate());
|
||||
lqw.eq(bo.getShelfTimeliness() != null, BizLogisticsOrder::getShelfTimeliness, bo.getShelfTimeliness());
|
||||
lqw.and(wrapper -> wrapper.eq(BizLogisticsOrder::getCreateBy, LoginHelper.getUserId()).or().eq(BizLogisticsOrder::getLogisticsProviderId, LoginHelper.getUserId()));
|
||||
if (!LoginHelper.isSuperAdmin() && !LoginHelper.isManagerAdmin()) {
|
||||
lqw.and(wrapper -> wrapper.eq(BizLogisticsOrder::getCreateBy, LoginHelper.getUserId()).or().eq(BizLogisticsOrder::getLogisticsProviderId, LoginHelper.getUserId()));
|
||||
}
|
||||
// Set<Long> roleIdSet = LoginHelper.getLoginUser().getRoles().stream().map(RoleDTO::getRoleId).collect(Collectors.toSet());
|
||||
// log.info("roleIdSet:{}", roleIdSet);
|
||||
// if (roleIdSet.contains(3L)){
|
||||
@ -165,7 +167,7 @@ public class BizLogisticsOrderServiceImpl implements IBizLogisticsOrderService {
|
||||
/**
|
||||
* 保存前的数据校验
|
||||
*/
|
||||
private void validEntityBeforeSave(BizLogisticsOrder entity){
|
||||
private void validEntityBeforeSave(BizLogisticsOrder entity) {
|
||||
//TODO 做一些数据校验,如唯一约束
|
||||
}
|
||||
|
||||
@ -178,10 +180,14 @@ public class BizLogisticsOrderServiceImpl implements IBizLogisticsOrderService {
|
||||
*/
|
||||
@Override
|
||||
public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
|
||||
if(isValid){
|
||||
if (isValid) {
|
||||
//TODO 做一些业务上的校验,判断是否需要校验
|
||||
}
|
||||
return baseMapper.deleteByIds(ids) > 0;
|
||||
boolean b = baseMapper.deleteByIds(ids) > 0;
|
||||
List<BizLogisticsOrder> bizLogisticsOrders = baseMapper.selectByIds(ids);
|
||||
List<String> fbaShipmentids = bizLogisticsOrders.stream().map(BizLogisticsOrder::getFbaShipmentId).collect(Collectors.toList());
|
||||
bizShipmentPlanService.updateStatusbyFbaShipmentIds(fbaShipmentids);
|
||||
return b;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -225,7 +231,7 @@ public class BizLogisticsOrderServiceImpl implements IBizLogisticsOrderService {
|
||||
bizLogisticsOrder.setOrderId(SerialNoGenerator.generateOrderNo());
|
||||
|
||||
bizLogisticsOrder.setLogisticsProviderId(quoteVo.getUserId());
|
||||
String nickName = remoteUserService.selectNicknameById(quoteVo.getUserId());
|
||||
String nickName = remoteUserService.selectNicknameById(quoteVo.getUserId());
|
||||
bizLogisticsOrder.setLogisticsProviderName(nickName);
|
||||
|
||||
bizLogisticsOrder.setQuoteOrderId(Long.valueOf(bo.getLogicQuoteId()));
|
||||
@ -240,7 +246,7 @@ public class BizLogisticsOrderServiceImpl implements IBizLogisticsOrderService {
|
||||
bizLogisticsOrder.setShipmentQuantity(sum);
|
||||
|
||||
|
||||
ArrayList<BizLogisticsOrderDetail> orderDetailList = new ArrayList<>();
|
||||
ArrayList<BizLogisticsOrderDetail> orderDetailList = new ArrayList<>();
|
||||
|
||||
for (BizShipmentTracking bizShipmentTracking : trackingList) {
|
||||
BizLogisticsOrderDetail detail = new BizLogisticsOrderDetail();
|
||||
|
@ -4,6 +4,7 @@ import cn.hutool.core.collection.CollectionUtil;
|
||||
import cn.hutool.core.date.DateTime;
|
||||
import cn.hutool.core.date.DateUtil;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.asinkj.amz.domain.*;
|
||||
import org.asinkj.amz.domain.bo.SysAmazonStoreBo;
|
||||
@ -361,8 +362,11 @@ public class BizShipmentPlanServiceImpl implements IBizShipmentPlanService {
|
||||
}
|
||||
bizShipmentPlanVo.setBoxQuantity(count);
|
||||
bizShipmentPlanVo.setOrder(bizLogisticsOrder);
|
||||
BizLogisticsQuote bizLogisticsQuote = quoteMap.get(bizLogisticsOrder.getQuoteOrderId());
|
||||
bizShipmentPlanVo.setQuote(bizLogisticsQuote);
|
||||
if (bizLogisticsOrder != null) {
|
||||
BizLogisticsQuote bizLogisticsQuote = quoteMap.get(bizLogisticsOrder.getQuoteOrderId());
|
||||
bizShipmentPlanVo.setQuote(bizLogisticsQuote);
|
||||
}
|
||||
|
||||
if (CollectionUtil.isNotEmpty(sids)) {
|
||||
String storeName = storeNameMap.get(bizShipmentPlanVo.getSid());
|
||||
bizShipmentPlanVo.setSellerName(storeName);
|
||||
@ -371,4 +375,21 @@ public class BizShipmentPlanServiceImpl implements IBizShipmentPlanService {
|
||||
}
|
||||
return TableDataInfo.build(bizShipmentPlanOrderVoPage);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateStatusbyFbaShipmentIds(List<String> fbaShipmentids) {
|
||||
LambdaUpdateWrapper<BizShipmentPlan> lambdaUpdateWrapper = new LambdaUpdateWrapper<>();
|
||||
lambdaUpdateWrapper.in(BizShipmentPlan::getShipmentId, fbaShipmentids)
|
||||
.set(BizShipmentPlan::getFbaStatus, "ask");
|
||||
baseMapper.update(null,lambdaUpdateWrapper);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateList(Collection<String> list, String status) {
|
||||
LambdaUpdateWrapper<BizShipmentPlan> lambdaUpdateWrapper = new LambdaUpdateWrapper<>();
|
||||
lambdaUpdateWrapper.in(BizShipmentPlan::getShipmentId, list)
|
||||
.set(BizShipmentPlan::getFbaStatus, "send");
|
||||
baseMapper.update(null,lambdaUpdateWrapper);
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,31 @@
|
||||
package org.asinkj.common.redis.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
@Target(ElementType.METHOD) // 标注在方法上
|
||||
@Retention(RetentionPolicy.RUNTIME) // 运行时生效
|
||||
public @interface DistributedLock {
|
||||
/**
|
||||
* 锁的Key前缀(默认使用方法名)
|
||||
*/
|
||||
String prefix() default "";
|
||||
|
||||
/**
|
||||
* 等待锁时间(秒),0表示不等待
|
||||
*/
|
||||
long waitTime() default 0;
|
||||
|
||||
/**
|
||||
* 锁持有时间(秒)
|
||||
*/
|
||||
long leaseTime() default 30;
|
||||
|
||||
/**
|
||||
* 业务唯一标识参数名(从方法参数中提取)
|
||||
* 例如:params = {"channelId", "destination"}
|
||||
*/
|
||||
String[] params() default {};
|
||||
}
|
@ -0,0 +1,100 @@
|
||||
package org.asinkj.common.redis.aspect;
|
||||
|
||||
import org.asinkj.common.redis.annotation.DistributedLock;
|
||||
import org.aspectj.lang.ProceedingJoinPoint;
|
||||
import org.aspectj.lang.annotation.Around;
|
||||
import org.aspectj.lang.annotation.Aspect;
|
||||
import org.aspectj.lang.reflect.MethodSignature;
|
||||
import org.asinkj.common.redis.utils.RedisUtils;
|
||||
import org.redisson.api.RLock;
|
||||
import org.springframework.expression.Expression;
|
||||
import org.springframework.expression.ExpressionParser;
|
||||
import org.springframework.expression.spel.standard.SpelExpressionParser;
|
||||
import org.springframework.expression.spel.support.StandardEvaluationContext;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
@Aspect
|
||||
@Component
|
||||
public class DistributedLockAspect {
|
||||
|
||||
private final ExpressionParser parser = new SpelExpressionParser();
|
||||
|
||||
/**
|
||||
* 环绕通知,拦截被 @DistributedLock 注解的方法
|
||||
*/
|
||||
@Around("@annotation(distributedLock)")
|
||||
public Object around(ProceedingJoinPoint joinPoint, DistributedLock distributedLock) throws Throwable {
|
||||
// 1. 生成分布式锁Key
|
||||
String lockKey = generateLockKey(joinPoint, distributedLock);
|
||||
|
||||
// 2. 获取 Redisson 锁对象
|
||||
RLock lock = RedisUtils.getClient().getLock(lockKey);
|
||||
|
||||
try {
|
||||
// 3. 尝试加锁
|
||||
boolean isLocked = lock.tryLock(distributedLock.waitTime(), distributedLock.leaseTime(), TimeUnit.SECONDS);
|
||||
if (!isLocked) {
|
||||
throw new RuntimeException("系统繁忙,请稍后重试");
|
||||
}
|
||||
|
||||
// 4. 执行目标方法(业务逻辑)
|
||||
return joinPoint.proceed();
|
||||
|
||||
} finally {
|
||||
// 5. 释放锁
|
||||
if (lock.isHeldByCurrentThread()) {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成锁的Key(格式:prefix:param1_value:param2_value)
|
||||
*/
|
||||
private String generateLockKey(ProceedingJoinPoint joinPoint, DistributedLock lock) {
|
||||
// 获取方法参数名和值
|
||||
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
|
||||
String[] paramNames = signature.getParameterNames();
|
||||
Object[] args = joinPoint.getArgs();
|
||||
|
||||
// 解析业务唯一标识参数值
|
||||
StringBuilder keyBuilder = new StringBuilder();
|
||||
if (lock.prefix().isEmpty()) {
|
||||
keyBuilder.append(joinPoint.getSignature().getName()); // 默认用方法名
|
||||
} else {
|
||||
keyBuilder.append(lock.prefix());
|
||||
}
|
||||
|
||||
for (String param : lock.params()) {
|
||||
Object value = getParamValue(param, paramNames, args);
|
||||
keyBuilder.append(":").append(value);
|
||||
}
|
||||
|
||||
return keyBuilder.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据参数名获取参数值(支持SpEL表达式)
|
||||
*/
|
||||
private Object getParamValue(String param, String[] paramNames, Object[] args) {
|
||||
// 检查是否是SpEL表达式(例如 #request.channelId)
|
||||
if (param.startsWith("#")) {
|
||||
StandardEvaluationContext context = new StandardEvaluationContext();
|
||||
for (int i = 0; i < paramNames.length; i++) {
|
||||
context.setVariable(paramNames[i], args[i]);
|
||||
}
|
||||
Expression exp = parser.parseExpression(param);
|
||||
return exp.getValue(context);
|
||||
}
|
||||
|
||||
// 普通参数名匹配
|
||||
for (int i = 0; i < paramNames.length; i++) {
|
||||
if (param.equals(paramNames[i])) {
|
||||
return args[i];
|
||||
}
|
||||
}
|
||||
throw new IllegalArgumentException("未找到参数: " + param);
|
||||
}
|
||||
}
|
@ -10,7 +10,9 @@ import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
@ -545,4 +547,22 @@ public class RedisUtils {
|
||||
RKeys rKeys = CLIENT.getKeys();
|
||||
return rKeys.countExists(key) > 0;
|
||||
}
|
||||
|
||||
public static <T> T executeWithLock(String lockKey, Supplier<T> supplier,
|
||||
long waitTime, long leaseTime) {
|
||||
RLock lock = RedisUtils.getClient().getLock(lockKey);
|
||||
try {
|
||||
if (lock.tryLock(waitTime, leaseTime, TimeUnit.SECONDS)) {
|
||||
return supplier.get(); // 执行核心业务逻辑
|
||||
}
|
||||
throw new RuntimeException("获取锁失败");
|
||||
} catch (InterruptedException e) {
|
||||
Thread.currentThread().interrupt();
|
||||
throw new RuntimeException("锁等待被中断");
|
||||
} finally {
|
||||
if (lock.isHeldByCurrentThread()) {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user