4.12新需求修改

This commit is contained in:
dev 2025-04-17 16:56:45 +08:00
parent 8ec2796770
commit b4eee35c1f
15 changed files with 507 additions and 24 deletions

View File

@ -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);
}
/**
* 导出物流询价列表
*/

View File

@ -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();
}
/**
* 修改货件计划
*/

View File

@ -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;
}

View File

@ -110,4 +110,10 @@ public class BizLogisticsQuote extends TenantEntity {
private Long inquiryId;
/**
* 后端物流类型
*/
private String backLogisticsType;
}

View File

@ -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;
}

View File

@ -129,4 +129,9 @@ public class BizLogisticsQuoteVo implements Serializable {
private String backLogisticsType;
}

View File

@ -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;
/**
* 渠道IDsystem=dict_codecustom=自定义渠道ID
*/
@ExcelProperty(value = "渠道ID")
private Long channelId;
/**
* 报价目标日期
*/
@JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8")
private Date quoteDate;
private FbaShipmentApiResponse.Address shipToAddress;
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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<>();

View File

@ -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();

View File

@ -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);
}
}

View File

@ -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 {};
}

View File

@ -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);
}
}

View File

@ -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();
}
}
}
}