订单管理

This commit is contained in:
dev 2025-03-25 18:05:19 +08:00
parent 58126e7773
commit 46e107e86b
13 changed files with 201 additions and 54 deletions

View File

@ -48,7 +48,7 @@ public class BizInquiryRequestController extends BaseController {
/**
* 根据目的地仓库和渠道创建物流询价单
* 根据目的地仓库和渠道查询物流询价单
*/
@SaCheckPermission("amz:inquiryRequest:list")
@GetMapping("/query/{destination}/{channelId}/{date}")

View File

@ -7,6 +7,8 @@ import jakarta.servlet.http.HttpServletResponse;
import jakarta.validation.constraints.*;
import cn.dev33.satoken.annotation.SaCheckPermission;
import org.asinkj.amz.domain.bo.BizLogisticsQuoteMostBo;
import org.asinkj.amz.domain.vo.InquiryQuoteStatusDTO;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.springframework.validation.annotation.Validated;
import org.asinkj.common.idempotent.annotation.RepeatSubmit;
@ -107,6 +109,14 @@ public class BizLogisticsQuoteController extends BaseController {
return R.ok();
}
@GetMapping("/today-quote-status")
@RepeatSubmit()
public ResponseEntity<List<InquiryQuoteStatusDTO>> getTodayQuoteStatus() {
List<InquiryQuoteStatusDTO> statusList = bizLogisticsQuoteService.getTodayQuoteStatus();
return ResponseEntity.ok(statusList);
}
/**
* 修改物流报价
*/

View File

@ -101,5 +101,7 @@ public class BizLogisticsQuote extends TenantEntity {
*/
private String unit;
private Long inquiryId;
}

View File

@ -30,7 +30,7 @@ public class BizLogisticsQuoteMostBo extends BaseEntity {
/**
* 主键ID
*/
// @NotNull(message = "主键ID不能为空", groups = { AddGroup.class, EditGroup.class })
@NotNull(message = "主键ID不能为空", groups = { AddGroup.class, EditGroup.class })
private Long id;
/**

View File

@ -33,22 +33,22 @@ public class BizLogisticsOrderDetailVo implements Serializable {
/**
* 主键应用层生成的全局唯一ID
*/
@ExcelProperty(value = "主键", converter = ExcelDictConvert.class)
@ExcelDictFormat(readConverterExp = "应=用层生成的全局唯一ID")
// @ExcelProperty(value = "主键", converter = ExcelDictConvert.class)
// @ExcelDictFormat(readConverterExp = "应=用层生成的全局唯一ID")
private Long id;
/**
* 关联主表IDbiz_logistics_order.id
*/
@ExcelProperty(value = "关联主表ID", converter = ExcelDictConvert.class)
@ExcelDictFormat(readConverterExp = "b=iz_logistics_order.id")
@ExcelProperty(value = "订单号")
// @ExcelDictFormat(readConverterExp = "b=iz_logistics_order.id")
private String orderId;
/**
* FBA货件编号冗余存储避免联表查询
*/
@ExcelProperty(value = "FBA货件编号", converter = ExcelDictConvert.class)
@ExcelDictFormat(readConverterExp = "冗=余存储,避免联表查询")
@ExcelProperty(value = "FBA货件编号")
// @ExcelDictFormat(readConverterExp = "冗=余存储,避免联表查询")
private String fbaShipmentId;
@ -56,134 +56,134 @@ public class BizLogisticsOrderDetailVo implements Serializable {
/**
* FBA箱号亚马逊系统中箱子的唯一标识
*/
@ExcelProperty(value = "FBA箱号", converter = ExcelDictConvert.class)
@ExcelDictFormat(readConverterExp = "亚=马逊系统中箱子的唯一标识")
@ExcelProperty(value = "FBA箱号")
// @ExcelDictFormat(readConverterExp = "亚=马逊系统中箱子的唯一标识")
private String fbaBoxNumber;
/**
* 物流商ID冗余存储
*/
@ExcelProperty(value = "物流商ID", converter = ExcelDictConvert.class)
@ExcelDictFormat(readConverterExp = "冗=余存储")
@ExcelProperty(value = "物流商ID")
// @ExcelDictFormat(readConverterExp = "冗=余存储")
private Long logisticsProviderId;
/**
* 物流商名称冗余存储
*/
@ExcelProperty(value = "物流商名称", converter = ExcelDictConvert.class)
@ExcelDictFormat(readConverterExp = "冗=余存储")
@ExcelProperty(value = "物流商名称")
// @ExcelDictFormat(readConverterExp = "冗=余存储")
private String logisticsProviderName;
/**
* 物流渠道与主表一致
*/
@ExcelProperty(value = "物流渠道", converter = ExcelDictConvert.class)
@ExcelDictFormat(readConverterExp = "与=主表一致")
@ExcelProperty(value = "物流渠道")
// @ExcelDictFormat(readConverterExp = "与=主表一致")
private String logisticsChannel;
/**
* 目的地仓库冗余存储
*/
@ExcelProperty(value = "目的地仓库", converter = ExcelDictConvert.class)
@ExcelDictFormat(readConverterExp = "冗=余存储")
@ExcelProperty(value = "目的地仓库")
// @ExcelDictFormat(readConverterExp = "冗=余存储")
private String destination;
/**
* 计划数量该箱子预计装载的商品数量
*/
@ExcelProperty(value = "计划数量", converter = ExcelDictConvert.class)
@ExcelDictFormat(readConverterExp = "该=箱子预计装载的商品数量")
@ExcelProperty(value = "计划数量")
// @ExcelDictFormat(readConverterExp = "该=箱子预计装载的商品数量")
private Long plannedQuantity;
/**
* 实际货件数量该箱子实际装载的商品数量
*/
@ExcelProperty(value = "实际货件数量", converter = ExcelDictConvert.class)
@ExcelDictFormat(readConverterExp = "该=箱子实际装载的商品数量")
@ExcelProperty(value = "实际货件数量")
// @ExcelDictFormat(readConverterExp = "该=箱子实际装载的商品数量")
private Long shipmentQuantity;
/**
* 物流追踪号物流商提供的唯一包裹标识
*/
@ExcelProperty(value = "物流追踪号", converter = ExcelDictConvert.class)
@ExcelDictFormat(readConverterExp = "物=流商提供的唯一包裹标识")
@ExcelProperty(value = "物流追踪号")
// @ExcelDictFormat(readConverterExp = "物=流商提供的唯一包裹标识")
private String trackingNumber;
/**
* 供应商称重单位KG由供应商提供
*/
@ExcelProperty(value = "供应商称重", converter = ExcelDictConvert.class)
@ExcelDictFormat(readConverterExp = "单=位KG由供应商提供")
@ExcelProperty(value = "供应商称重")
// @ExcelDictFormat(readConverterExp = "单=位KG由供应商提供")
private Long supplierWeight;
/**
* 物流商计重单位KG物流商实际测量值
*/
@ExcelProperty(value = "物流商计重", converter = ExcelDictConvert.class)
@ExcelDictFormat(readConverterExp = "单=位KG物流商实际测量值")
@ExcelProperty(value = "物流商计重")
// @ExcelDictFormat(readConverterExp = "单=位KG物流商实际测量值")
private Long logisticsWeight;
/**
* 称重差异应用层计算物流商计重 - 供应商称重
*/
@ExcelProperty(value = "称重差异", converter = ExcelDictConvert.class)
@ExcelDictFormat(readConverterExp = "应=用层计算:物流商计重,-=,供=应商称重")
@ExcelProperty(value = "称重差异")
// @ExcelDictFormat(readConverterExp = "应=用层计算:物流商计重,-=,供=应商称重")
private Long weightDiff;
/**
* 物流单价单位/KG由合同或报价确定
*/
@ExcelProperty(value = "物流单价", converter = ExcelDictConvert.class)
@ExcelDictFormat(readConverterExp = "单=位:元/KG由合同或报价确定")
@ExcelProperty(value = "物流单价")
// @ExcelDictFormat(readConverterExp = "单=位:元/KG由合同或报价确定")
private Long pricePerKg;
/**
* 物流计价重量应用层根据业务规则计算
*/
@ExcelProperty(value = "物流计价重量", converter = ExcelDictConvert.class)
@ExcelDictFormat(readConverterExp = "应=用层根据业务规则计算")
@ExcelProperty(value = "物流计价重量")
// @ExcelDictFormat(readConverterExp = "应=用层根据业务规则计算")
private Long logisticsCalculationPrice;
/**
* 其他物流费用如报关费保险费等
*/
@ExcelProperty(value = "其他物流费用", converter = ExcelDictConvert.class)
@ExcelDictFormat(readConverterExp = "如=报关费、保险费等")
@ExcelProperty(value = "其他物流费用")
// @ExcelDictFormat(readConverterExp = "如=报关费、保险费等")
private Long otherFee;
/**
* 费用合计应用层计算物流计价 + 其他费用
*/
@ExcelProperty(value = "费用合计", converter = ExcelDictConvert.class)
@ExcelDictFormat(readConverterExp = "应=用层计算:物流计价,+=,其=他费用")
@ExcelProperty(value = "费用合计")
// @ExcelDictFormat(readConverterExp = "应=用层计算:物流计价,+=,其=他费用")
private Long totalFee;
/**
* 物流状态pending:待发运/in_transit:运输中/delivered:已签收
*/
@ExcelProperty(value = "物流状态", converter = ExcelDictConvert.class)
@ExcelDictFormat(readConverterExp = "p=ending:待发运/in_transit:运输中/delivered:已签收")
@ExcelDictFormat(readConverterExp = "pending=待发运,in_transit=运输中,delivered=已签收")
private String logisticsStatus;
/**
* 预计签收日期物流商提供的预估日期
*/
@ExcelProperty(value = "预计签收日期", converter = ExcelDictConvert.class)
@ExcelDictFormat(readConverterExp = "物=流商提供的预估日期")
@ExcelProperty(value = "预计签收日期")
// @ExcelDictFormat(readConverterExp = "物=流商提供的预估日期")
private Date estimatedDeliveryDate;
/**
* 实际签收日期物流商回传的实际日期
*/
@ExcelProperty(value = "实际签收日期", converter = ExcelDictConvert.class)
@ExcelDictFormat(readConverterExp = "物=流商回传的实际日期")
@ExcelProperty(value = "实际签收日期")
// @ExcelDictFormat(readConverterExp = "物=流商回传的实际日期")
private Date actualDeliveryDate;
/**
* 运输时效单位实际签收日期 - 发货日期
*/
@ExcelProperty(value = "运输时效", converter = ExcelDictConvert.class)
@ExcelDictFormat(readConverterExp = "单=位:天,实际签收日期,-=,发=货日期")
@ExcelProperty(value = "运输时效")
// @ExcelDictFormat(readConverterExp = "单=位:天,实际签收日期,-=,发=货日期")
private Long timeliness;

View File

@ -0,0 +1,11 @@
package org.asinkj.amz.domain.vo;
import lombok.Data;
@Data
public class InquiryQuoteStatusDTO {
private Long inquiryId;
private String inquiryNo;
private Long providerId;
private String quoteStatus; // "已报价" "未报价"
}

View File

@ -1,9 +1,13 @@
package org.asinkj.amz.mapper;
import org.apache.ibatis.annotations.Param;
import org.asinkj.amz.domain.BizInquiryRequest;
import org.asinkj.amz.domain.vo.BizInquiryRequestVo;
import org.asinkj.common.mybatis.core.mapper.BaseMapperPlus;
import java.time.LocalDate;
import java.util.List;
/**
* 物流询价Mapper接口
*
@ -12,4 +16,6 @@ import org.asinkj.common.mybatis.core.mapper.BaseMapperPlus;
*/
public interface BizInquiryRequestMapper extends BaseMapperPlus<BizInquiryRequest, BizInquiryRequestVo> {
// 自定义查询可选
List<BizInquiryRequest> selectOpenAndEffectiveInquiries(@Param("currentDate") LocalDate currentDate);
}

View File

@ -1,9 +1,13 @@
package org.asinkj.amz.mapper;
import org.apache.ibatis.annotations.Param;
import org.asinkj.amz.domain.BizLogisticsQuote;
import org.asinkj.amz.domain.vo.BizLogisticsQuoteVo;
import org.asinkj.common.mybatis.core.mapper.BaseMapperPlus;
import java.time.LocalDate;
import java.util.List;
/**
* 物流报价Mapper接口
*
@ -12,4 +16,8 @@ import org.asinkj.common.mybatis.core.mapper.BaseMapperPlus;
*/
public interface BizLogisticsQuoteMapper extends BaseMapperPlus<BizLogisticsQuote, BizLogisticsQuoteVo> {
List<BizLogisticsQuote> selectQuotesByProvidersAndDate(
@Param("providerIds") List<Long> providerIds,
@Param("quoteDate") LocalDate quoteDate
);
}

View File

@ -4,6 +4,7 @@ import jakarta.validation.constraints.NotNull;
import org.asinkj.amz.domain.bo.BizLogisticsQuoteMostBo;
import org.asinkj.amz.domain.vo.BizLogisticsQuoteVo;
import org.asinkj.amz.domain.bo.BizLogisticsQuoteBo;
import org.asinkj.amz.domain.vo.InquiryQuoteStatusDTO;
import org.asinkj.common.mybatis.core.page.TableDataInfo;
import org.asinkj.common.mybatis.core.page.PageQuery;
@ -74,4 +75,6 @@ public interface IBizLogisticsQuoteService {
TableDataInfo<BizLogisticsQuoteVo> listWithDesAndChannel(@NotNull(message = "目的地不能为空") String destination, @NotNull(message = "渠道不能为空") String channel, @NotNull(message = "日期不能为空") String date);
void insertMostQuoteByBo(BizLogisticsQuoteMostBo bo);
List<InquiryQuoteStatusDTO> getTodayQuoteStatus();
}

View File

@ -4,7 +4,9 @@ import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.NumberUtil;
import lombok.extern.slf4j.Slf4j;
import org.asinkj.amz.domain.BizLogisticsQuote;
import org.asinkj.amz.domain.vo.BizLogisticsChannelVo;
import org.asinkj.amz.mapper.BizLogisticsQuoteMapper;
import org.asinkj.amz.service.IBizLogisticsChannelService;
import org.asinkj.common.core.domain.R;
import org.asinkj.common.core.utils.MapstructUtils;
@ -26,7 +28,9 @@ 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;
@ -53,6 +57,9 @@ public class BizInquiryRequestServiceImpl implements IBizInquiryRequestService {
@Resource
private BizInquiryRequestMapper billingRequestMapper;
@Resource
private BizLogisticsQuoteMapper logisticsQuoteMapper;
/**
* 查询物流询价
*
@ -161,6 +168,10 @@ public class BizInquiryRequestServiceImpl implements IBizInquiryRequestService {
@Override
public R<Void> createWithDesAndChannel(String destination, String channelId,String date) {
BizInquiryRequest bizInquiryRequest = new BizInquiryRequest();
bizInquiryRequest.setDestination(destination);
bizInquiryRequest.setChannelId(NumberUtil.parseLong(channelId));
@ -182,13 +193,14 @@ public class BizInquiryRequestServiceImpl implements IBizInquiryRequestService {
bizInquiryRequest.setEffectiveStartTime(new Date());
bizInquiryRequest.setEffectiveEndTime(new Date());
}else if("sea".equals(bizLogisticsChannelVo.getShippingMethod())){
//获取下周一的日期
Calendar calendar = Calendar.getInstance();
calendar.add(Calendar.DAY_OF_WEEK, 8 - calendar.get(Calendar.DAY_OF_WEEK));
bizInquiryRequest.setEffectiveStartTime(calendar.getTime());
//获取下下周一的日期
calendar.add(Calendar.DAY_OF_WEEK, 7);
bizInquiryRequest.setEffectiveEndTime(calendar.getTime());
//获取本周的周日上个周六的日期
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());

View File

@ -5,9 +5,12 @@ import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.NumberUtil;
import lombok.extern.slf4j.Slf4j;
import org.asinkj.amz.domain.BizInquiryRequest;
import org.asinkj.amz.domain.bo.BizLogisticsQuoteMostBo;
import org.asinkj.amz.domain.vo.InquiryQuoteStatusDTO;
import org.asinkj.amz.mapper.BizInquiryRequestMapper;
import org.asinkj.amz.service.IBizLogisticsChannelService;
import org.asinkj.common.core.exception.ServiceException;
import org.asinkj.common.core.utils.MapstructUtils;
import org.asinkj.common.core.utils.StringUtils;
import org.asinkj.common.mybatis.core.page.TableDataInfo;
@ -17,6 +20,8 @@ import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.RequiredArgsConstructor;
import org.asinkj.common.satoken.utils.LoginHelper;
import org.asinkj.system.api.RemoteUserService;
import org.springframework.data.util.Pair;
import org.springframework.stereotype.Service;
import org.asinkj.amz.domain.bo.BizLogisticsQuoteBo;
import org.asinkj.amz.domain.vo.BizLogisticsQuoteVo;
@ -25,7 +30,10 @@ import org.asinkj.amz.mapper.BizLogisticsQuoteMapper;
import org.asinkj.amz.service.IBizLogisticsQuoteService;
import javax.annotation.Resource;
import java.time.LocalDate;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;
/**
* 物流报价Service业务层处理
@ -47,6 +55,9 @@ public class BizLogisticsQuoteServiceImpl implements IBizLogisticsQuoteService {
@Resource
private BizInquiryRequestMapper bizInquiryRequestMapper;
@Resource
private RemoteUserService remoteUserService ;
/**
* 查询物流报价
*
@ -181,6 +192,14 @@ public class BizLogisticsQuoteServiceImpl implements IBizLogisticsQuoteService {
@Override
public void insertMostQuoteByBo(BizLogisticsQuoteMostBo bo) {
//检查是否重复报价
LambdaQueryWrapper<BizLogisticsQuote> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(BizLogisticsQuote::getInquiryId, bo.getId());
queryWrapper.eq(BizLogisticsQuote::getUserId, LoginHelper.getUserId());
if (baseMapper.selectCount(queryWrapper) > 0) {
throw new ServiceException("该询价单已报价,请勿重复报价");
}
Date quoteStartDate = bo.getQuoteStartDate();
Date quoteEndDate = bo.getQuoteEndDate();
//计算中间的每一天的日期
@ -201,6 +220,7 @@ public class BizLogisticsQuoteServiceImpl implements IBizLogisticsQuoteService {
bizLogisticsQuote.setChannelId(bo.getChannelId());
bizLogisticsQuote.setIsDdp(bo.getIsDdp());
bizLogisticsQuote.setUnit(bo.getUnit());
bizLogisticsQuote.setInquiryId(bo.getId());
bizLogisticsQuotes.add(bizLogisticsQuote);
}
boolean b = baseMapper.insertBatch(bizLogisticsQuotes);
@ -208,4 +228,62 @@ public class BizLogisticsQuoteServiceImpl implements IBizLogisticsQuoteService {
}
@Override
public List<InquiryQuoteStatusDTO> getTodayQuoteStatus() {
LocalDate today = LocalDate.now();
List<BizInquiryRequest> inquiries = bizInquiryRequestMapper.selectOpenAndEffectiveInquiries(today);
// 2. 收集所有物流商ID
Map<Long, List<Long>> inquiryProvidersMap = new HashMap<>();
Set<Long> allProviderIds = new HashSet<>();
for (BizInquiryRequest inquiry : inquiries) {
List<Long> providerIds = parseTargetProviders(inquiry.getTargetProviders());
inquiryProvidersMap.put(inquiry.getId(), providerIds);
allProviderIds.addAll(providerIds);
}
// 3. 查询当日报价记录即使 allProviderIds 为空也会执行
List<BizLogisticsQuote> quotes = baseMapper.selectQuotesByProvidersAndDate(
new ArrayList<>(allProviderIds), today
);
// 4. 构建报价状态映射表
Map<Pair<Long, Long>, BizLogisticsQuote> quoteMap = quotes.stream()
.collect(Collectors.toMap(
quote -> Pair.of(quote.getInquiryId(), quote.getChannelId()),
Function.identity()
));
// 5. 组合结果
List<InquiryQuoteStatusDTO> result = new ArrayList<>();
for (BizInquiryRequest inquiry : inquiries) {
List<Long> providerIds = inquiryProvidersMap.get(inquiry.getId());
for (Long providerId : providerIds) {
InquiryQuoteStatusDTO dto = new InquiryQuoteStatusDTO();
dto.setInquiryId(inquiry.getId());
dto.setInquiryNo(inquiry.getInquiryNo());
dto.setProviderId(providerId);
dto.setQuoteStatus(
quoteMap.containsKey(Pair.of(inquiry.getId(), providerId)) ? "已报价" : "未报价"
);
result.add(dto);
}
}
return result;
}
// 解析 target_providers 字符串为物流商ID列表
private List<Long> parseTargetProviders(String targetProviders) {
if (StringUtils.isBlank(targetProviders)) {
// 空值返回所有物流商ID
return remoteUserService.selectUserIdsByRoleIds(List.of(3L));
}
return Arrays.stream(targetProviders.split(","))
.map(Long::parseLong)
.collect(Collectors.toList());
}
}

View File

@ -3,5 +3,11 @@
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="org.asinkj.amz.mapper.BizInquiryRequestMapper">
<select id="selectOpenAndEffectiveInquiries" resultType="org.asinkj.amz.domain.BizInquiryRequest">
SELECT *
FROM biz_inquiry_request
WHERE inquiry_status = 'OPEN'
AND del_flag = '0'
AND #{currentDate} = deadline::date
</select>
</mapper>

View File

@ -3,5 +3,16 @@
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="org.asinkj.amz.mapper.BizLogisticsQuoteMapper">
<select id="selectQuotesByProvidersAndDate" resultType="org.asinkj.amz.domain.BizLogisticsQuote">
SELECT *
FROM biz_logistics_quote
WHERE del_flag = '0'
AND quote_date = #{quoteDate}
<if test="providerIds != null and !providerIds.isEmpty()">
AND channel_id IN
<foreach item="providerId" collection="providerIds" open="(" separator="," close=")">
#{providerId}
</foreach>
</if>
</select>
</mapper>