This commit is contained in:
2026-08-14 02:43:38 +08:00
parent 8e06aa3f68
commit 2373d62ceb
15 changed files with 579 additions and 25 deletions
@@ -14,6 +14,7 @@ import org.springblade.core.mp.support.Query;
import org.springblade.core.secure.annotation.PreAuth;
import org.springblade.core.tool.api.R;
import org.springblade.transport.pojo.dto.MasterOrderDispatchRequest;
import org.springblade.transport.excel.MasterOrderWaybillExcel;
import org.springblade.transport.pojo.vo.MasterOrderVO;
import org.springblade.transport.service.IMasterOrderService;
import org.springframework.web.bind.annotation.GetMapping;
@@ -44,5 +45,5 @@ public class MasterOrderController extends BladeController {
@PostMapping("/remove") @ApiOperationSupport(order = 6) @Operation(summary = "删除") public R status(@RequestParam Long id) { return R.status(masterOrderService.removeMasterOrder(id)); }
@PostMapping("/close-dispatch") @ApiOperationSupport(order = 7) @Operation(summary = "关闭调度") public R closeDispatch(@RequestParam Long id) { return R.status(masterOrderService.closeDispatch(id)); }
@PostMapping("/dispatch") @ApiOperationSupport(order = 8) @Operation(summary = "确认调度") public R<MasterOrderVO> dispatch(@RequestBody MasterOrderDispatchRequest data) { return R.data(masterOrderService.dispatch(data)); }
@GetMapping("/export") @ApiOperationSupport(order = 9) @Operation(summary = "按运单导出") public void export(MasterOrderVO query, HttpServletResponse response) { ExcelUtil.export(response, "总单运单明细", "运单明细", masterOrderService.exportWaybills(query), MasterOrderVO.class); }
@GetMapping("/export") @ApiOperationSupport(order = 9) @Operation(summary = "按运单导出") public void export(MasterOrderVO query, HttpServletResponse response) { ExcelUtil.export(response, "总单运单明细", "运单明细", masterOrderService.exportWaybills(query), MasterOrderWaybillExcel.class); }
}
@@ -24,11 +24,15 @@ package org.springblade.transport.controller;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
import cn.idev.excel.write.handler.SheetWriteHandler;
import cn.idev.excel.write.metadata.holder.WriteSheetHolder;
import cn.idev.excel.write.metadata.holder.WriteWorkbookHolder;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.servlet.http.HttpServletResponse;
import lombok.AllArgsConstructor;
import org.apache.poi.ss.usermodel.CellStyle;
import org.springblade.common.excel.ImportFailureExcelUtil;
import org.springblade.core.boot.ctrl.BladeController;
import org.springblade.core.excel.util.ExcelUtil;
@@ -45,14 +49,17 @@ import org.springblade.transport.pojo.entity.CustomerArchive;
import org.springblade.transport.pojo.entity.ProjectApply;
import org.springblade.transport.pojo.entity.TransportPlan;
import org.springblade.transport.pojo.entity.Waybill;
import org.springblade.transport.pojo.dto.WaybillImportBatchRequest;
import org.springblade.transport.pojo.vo.BusinessRemoveResultVO;
import org.springblade.transport.pojo.vo.LoadingManageVO;
import org.springblade.transport.pojo.vo.WaybillImportBatchVO;
import org.springblade.transport.pojo.vo.WaybillVO;
import org.springblade.transport.service.IContractManageService;
import org.springblade.transport.service.ICustomerArchiveService;
import org.springblade.transport.service.IProjectApplyService;
import org.springblade.transport.service.ITransportPlanService;
import org.springblade.transport.service.IWaybillService;
import org.springblade.transport.service.IWaybillImportBatchService;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
@@ -83,6 +90,7 @@ public class WaybillController extends BladeController {
private final IContractManageService contractManageService;
private final ICustomerArchiveService customerArchiveService;
private final ITransportPlanService transportPlanService;
private final IWaybillImportBatchService waybillImportBatchService;
@GetMapping("/detail")
@ApiOperationSupport(order = 1)
@@ -122,22 +130,58 @@ public class WaybillController extends BladeController {
return R.data(options);
}
@PostMapping("/submit")
@GetMapping("/import-batch/list")
@ApiOperationSupport(order = 4)
@Operation(summary = "运单批量导入批次分页")
public R<IPage<WaybillImportBatchVO>> importBatchList(WaybillImportBatchRequest request, Query query) {
return R.data(waybillImportBatchService.page(Condition.getPage(query), request));
}
@GetMapping("/import-batch/details")
@ApiOperationSupport(order = 5)
@Operation(summary = "运单批量导入明细分页")
public R<IPage<WaybillVO>> importBatchDetails(@RequestParam Long batchId, WaybillVO waybill, Query query) {
waybill.setImportBatchId(batchId);
return R.data(waybillService.selectWaybillPage(Condition.getPage(query), waybill));
}
@PostMapping("/import-batch/draft")
@ApiOperationSupport(order = 6)
@Operation(summary = "保存运单批量导入草稿")
public R saveImportBatchDraft(@RequestBody WaybillImportBatchRequest request) {
return R.data(waybillImportBatchService.saveDraft(request));
}
@PostMapping("/import-batch/confirm")
@ApiOperationSupport(order = 7)
@Operation(summary = "确认运单批量导入")
public R confirmImportBatch(@RequestBody WaybillImportBatchRequest request) {
return R.data(waybillImportBatchService.confirm(request));
}
@PostMapping("/import-batch/remove")
@ApiOperationSupport(order = 8)
@Operation(summary = "删除运单批量导入批次")
public R<BusinessRemoveResultVO> removeImportBatches(@RequestParam String ids) {
return R.data(waybillImportBatchService.removeBatches(ids));
}
@PostMapping("/submit")
@ApiOperationSupport(order = 9)
@Operation(summary = "新增或修改", description = "传入waybill")
public R submit(@RequestBody Waybill waybill) {
return R.status(waybillService.submit(waybill));
}
@PostMapping("/remove")
@ApiOperationSupport(order = 5)
@ApiOperationSupport(order = 10)
@Operation(summary = "逻辑删除", description = "传入ids")
public R<BusinessRemoveResultVO> remove(@Parameter(description = "主键集合", required = true) @RequestParam String ids) {
return R.data(waybillService.removeWaybill(ids));
}
@GetMapping("/export-waybill-manage")
@ApiOperationSupport(order = 6)
@ApiOperationSupport(order = 11)
@Operation(summary = "导出运单管理")
public void exportWaybill(WaybillVO waybill, @RequestParam(required = false) String ids, HttpServletResponse response) {
List<WaybillExcel> list = waybillService.exportWaybill(waybill, ids);
@@ -145,7 +189,7 @@ public class WaybillController extends BladeController {
}
@PostMapping("/import-waybill-manage")
@ApiOperationSupport(order = 7)
@ApiOperationSupport(order = 12)
@Operation(summary = "导入运单管理", description = "传入excel")
public R importWaybill(MultipartFile file, HttpServletResponse response) {
List<WaybillExcel> failureList = waybillService.importWaybill(ExcelUtil.read(file, WaybillExcel.class));
@@ -157,63 +201,70 @@ public class WaybillController extends BladeController {
}
@GetMapping("/export-template")
@ApiOperationSupport(order = 8)
@ApiOperationSupport(order = 13)
@Operation(summary = "导出模板")
public void exportTemplate(HttpServletResponse response) {
ExcelUtil.export(response, "运单管理模板", "运单管理导入模板", new ArrayList<WaybillExcel>(), WaybillExcel.class);
}
@GetMapping("/import-batch/export-template")
@ApiOperationSupport(order = 9)
@ApiOperationSupport(order = 14)
@Operation(summary = "导出运单批量导入模板")
public void exportImportBatchTemplate(HttpServletResponse response) {
ExcelUtil.export(response, "运单批量导入模板", "运单批量导入模板", new ArrayList<WaybillImportBatchExcel>(), WaybillImportBatchExcel.class);
ExcelUtil.export(
response,
"运单批量导入模板",
"运单批量导入模板",
new ArrayList<WaybillImportBatchExcel>(),
new TextColumnStyleHandler(13, 14),
WaybillImportBatchExcel.class
);
}
@PostMapping("/copy")
@ApiOperationSupport(order = 10)
@ApiOperationSupport(order = 15)
@Operation(summary = "复制", description = "传入id")
public R<WaybillVO> copy(@Parameter(description = "主键", required = true) @RequestParam Long id) {
return R.data(waybillService.copy(id));
}
@PostMapping("/change-route")
@ApiOperationSupport(order = 11)
@ApiOperationSupport(order = 16)
@Operation(summary = "变更运输路线", description = "传入运单路线与变更记录")
public R changeRoute(@RequestBody Waybill waybill) {
return R.status(waybillService.changeRoute(waybill));
}
@PostMapping("/cancel")
@ApiOperationSupport(order = 12)
@ApiOperationSupport(order = 17)
@Operation(summary = "取消", description = "传入id")
public R cancel(@Parameter(description = "主键", required = true) @RequestParam Long id) {
return R.status(waybillService.cancel(id));
}
@PostMapping("/reassign")
@ApiOperationSupport(order = 13)
@ApiOperationSupport(order = 18)
@Operation(summary = "重新派单", description = "传入id")
public R reassign(@Parameter(description = "主键", required = true) @RequestParam Long id) {
return R.status(waybillService.reassign(id));
}
@PostMapping("/complete")
@ApiOperationSupport(order = 14)
@ApiOperationSupport(order = 19)
@Operation(summary = "完成", description = "传入id")
public R complete(@Parameter(description = "主键", required = true) @RequestParam Long id) {
return R.status(waybillService.complete(id));
}
@PostMapping("/batch-complete")
@ApiOperationSupport(order = 15)
@ApiOperationSupport(order = 20)
@Operation(summary = "批量完成", description = "传入ids")
public R<BusinessRemoveResultVO> batchComplete(@Parameter(description = "主键集合", required = true) @RequestParam String ids) {
return R.data(waybillService.batchComplete(ids));
}
@PostMapping("/road-loading")
@ApiOperationSupport(order = 16)
@ApiOperationSupport(order = 21)
@Operation(summary = "公路配载", description = "传入ids")
public R<LoadingManageVO> roadLoading(@Parameter(description = "主键集合", required = true) @RequestParam String ids) {
return R.data(waybillService.roadLoading(ids));
@@ -229,4 +280,23 @@ public class WaybillController extends BladeController {
return option;
}
private static final class TextColumnStyleHandler implements SheetWriteHandler {
private final int[] columnIndexes;
private TextColumnStyleHandler(int... columnIndexes) {
this.columnIndexes = columnIndexes;
}
@Override
public void afterSheetCreate(WriteWorkbookHolder writeWorkbookHolder, WriteSheetHolder writeSheetHolder) {
CellStyle textStyle = writeWorkbookHolder.getWorkbook().createCellStyle();
short textFormat = writeWorkbookHolder.getWorkbook().createDataFormat().getFormat("@");
textStyle.setDataFormat(textFormat);
for (int columnIndex : columnIndexes) {
writeSheetHolder.getSheet().setDefaultColumnStyle(columnIndex, textStyle);
}
}
}
}
@@ -41,15 +41,15 @@ public class LoadingManageExcel implements Serializable {
private String driverPhone;
@ExcelProperty("承运类型")
private String carrierType;
@ExcelProperty("承运商")
private String carrierName;
@ExcelProperty("发货地")
private String departureAddress;
@ExcelProperty("途经地")
private String transitAddress;
@ExcelProperty("到货地")
private String arrivalAddress;
@ExcelProperty("运输类型")
@ExcelProperty("承运商")
private String carrierName;
@ExcelProperty("运输方式")
private String transportType;
@ExcelProperty("数据来源")
private String dataSource;
@@ -0,0 +1,74 @@
/**
* BladeX Commercial License Agreement
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
*/
package org.springblade.transport.excel;
import cn.idev.excel.annotation.ExcelProperty;
import cn.idev.excel.annotation.write.style.ColumnWidth;
import cn.idev.excel.annotation.write.style.ContentRowHeight;
import cn.idev.excel.annotation.write.style.HeadRowHeight;
import lombok.Data;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.util.Date;
/** 总单运单明细导出模型。 */
@Data
@ColumnWidth(20)
@HeadRowHeight(20)
@ContentRowHeight(18)
public class MasterOrderWaybillExcel {
@ExcelProperty("总单号")
private String masterNo;
@ExcelProperty("运单号")
private String waybillNo;
@ExcelProperty("项目名称")
private String projectName;
@ExcelProperty("客户合同")
private String contractName;
@ExcelProperty("客户名称")
private String customerName;
@ExcelProperty("运输类型")
private String transportType;
@ExcelProperty("货物名称")
private String cargoName;
@ExcelProperty("货物类型")
private String cargoType;
@ExcelProperty("数量")
private BigDecimal quantity;
@ExcelProperty("数量单位")
private String quantityUnit;
@ExcelProperty("发货地址")
private String departureAddress;
@ExcelProperty("发货联系人")
private String departureContact;
@ExcelProperty("发货联系人电话")
private String departurePhone;
@ExcelProperty("收货地址")
private String arrivalAddress;
@ExcelProperty("收货联系人")
private String arrivalContact;
@ExcelProperty("收货联系人电话")
private String arrivalPhone;
@ExcelProperty("承运类型")
private String carrierType;
@ExcelProperty("承运商")
private String carrierName;
@ExcelProperty("司机")
private String driverName;
@ExcelProperty("车牌号/航班号/船号/班列号")
private String vehicleNo;
@ExcelProperty("开始日期")
private LocalDate startDate;
@ExcelProperty("结束日期")
private LocalDate endDate;
@ExcelProperty("业务状态")
private String businessStatus;
@ExcelProperty("备注")
private String remark;
@ExcelProperty("创建时间")
private Date createTime;
}
@@ -0,0 +1,14 @@
/**
* BladeX Commercial License Agreement
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
*/
package org.springblade.transport.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
import org.springblade.transport.pojo.entity.WaybillImportBatch;
/** 运单批次 Mapper。 */
@Mapper
public interface WaybillImportBatchMapper extends BaseMapper<WaybillImportBatch> {
}
@@ -6,6 +6,7 @@ import org.springblade.core.mp.base.BaseService;
import org.springblade.transport.pojo.dto.MasterOrderDispatchRequest;
import org.springblade.transport.pojo.entity.MasterOrder;
import org.springblade.transport.pojo.vo.MasterOrderVO;
import org.springblade.transport.excel.MasterOrderWaybillExcel;
import java.util.List;
@@ -22,5 +23,5 @@ public interface IMasterOrderService extends BaseService<MasterOrder> {
boolean removeMasterOrder(Long id);
boolean closeDispatch(Long id);
MasterOrderVO dispatch(MasterOrderDispatchRequest request);
List<MasterOrderVO> exportWaybills(MasterOrderVO query);
List<MasterOrderWaybillExcel> exportWaybills(MasterOrderVO query);
}
@@ -0,0 +1,20 @@
/**
* BladeX Commercial License Agreement
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
*/
package org.springblade.transport.service;
import com.baomidou.mybatisplus.core.metadata.IPage;
import org.springblade.core.mp.base.BaseService;
import org.springblade.transport.pojo.dto.WaybillImportBatchRequest;
import org.springblade.transport.pojo.entity.WaybillImportBatch;
import org.springblade.transport.pojo.vo.BusinessRemoveResultVO;
import org.springblade.transport.pojo.vo.WaybillImportBatchVO;
/** 运单批次服务。 */
public interface IWaybillImportBatchService extends BaseService<WaybillImportBatch> {
WaybillImportBatch saveDraft(WaybillImportBatchRequest request);
WaybillImportBatch confirm(WaybillImportBatchRequest request);
IPage<WaybillImportBatchVO> page(IPage<WaybillImportBatch> page, WaybillImportBatchRequest request);
BusinessRemoveResultVO removeBatches(String ids);
}
@@ -749,12 +749,19 @@ public class CustomerArchiveServiceImpl extends BaseServiceImpl<CustomerArchiveM
}
private void grantNewCustomerToIncludedUsers(CustomerArchive customer) {
List<Long> userIds = new ArrayList<>(baseMapper.selectIncludeNewCustomerUserIds(customer.getTenantId()));
String tenantId = Func.isNotEmpty(customer.getTenantId()) ? customer.getTenantId() : AuthUtil.getTenantId();
List<Long> userIds = new ArrayList<>(baseMapper.selectIncludeNewCustomerUserIds(tenantId));
Long currentUserId = AuthUtil.getUserId();
if (Func.isNotEmpty(currentUserId) && !userIds.contains(currentUserId)) {
userIds.add(currentUserId);
}
userIds.forEach(userId -> {
Long scopeCount = userCustomerScopeMapper.selectCount(Wrappers.<UserCustomerScope>lambdaQuery()
.eq(UserCustomerScope::getUserId, userId)
.eq(UserCustomerScope::getCustomerId, customer.getId()));
if (scopeCount != null && scopeCount > 0) {
return;
}
UserCustomerScope scope = new UserCustomerScope();
scope.setUserId(userId);
scope.setCustomerId(customer.getId());
@@ -261,7 +261,9 @@ public class LoadingManageServiceImpl extends BaseServiceImpl<LoadingManageMappe
@Transactional(rollbackFor = Exception.class)
public boolean complete(Long id) {
LoadingManage loadingManage = loadEditable(id, true);
if (!Objects.equals(loadingManage.getBusinessStatus(), STATUS_RUNNING)) {
if (!Objects.equals(loadingManage.getBusinessStatus(), STATUS_RUNNING)
&& !(Objects.equals(loadingManage.getBusinessStatus(), STATUS_PENDING)
&& allAssociatedWaybillsRunning(loadingManage))) {
throw new ServiceException("仅进行中状态允许完成");
}
loadingManage.setBusinessStatus(STATUS_COMPLETED);
@@ -290,6 +292,18 @@ public class LoadingManageServiceImpl extends BaseServiceImpl<LoadingManageMappe
return result;
}
private boolean allAssociatedWaybillsRunning(LoadingManage loadingManage) {
List<Long> waybillIdList = waybillIds(loadingManage.getWaybillIdsJson());
if (Func.isEmpty(waybillIdList)) {
return false;
}
List<Waybill> waybillList = waybillMapper.selectList(Wrappers.<Waybill>lambdaQuery()
.eq(Waybill::getIsDeleted, 0)
.in(Waybill::getId, waybillIdList));
return waybillList.size() == waybillIdList.size()
&& waybillList.stream().allMatch(waybill -> Objects.equals(waybill.getBusinessStatus(), STATUS_RUNNING));
}
private LambdaQueryWrapper<LoadingManage> buildQuery(LoadingManageVO loadingManage) {
TransportBusinessSupport.validateAllDept(loadingManage.getAllDept(), "配载管理");
LambdaQueryWrapper<LoadingManage> queryWrapper = Wrappers.<LoadingManage>lambdaQuery().eq(LoadingManage::getIsDeleted, 0);
@@ -13,6 +13,7 @@ import org.springblade.core.tool.utils.BeanUtil;
import org.springblade.core.tool.utils.Func;
import org.springblade.system.cache.UserCache;
import org.springblade.transport.mapper.MasterOrderMapper;
import org.springblade.transport.excel.MasterOrderWaybillExcel;
import org.springblade.transport.pojo.dto.MasterOrderDispatchRequest;
import org.springblade.transport.pojo.entity.MasterOrder;
import org.springblade.transport.pojo.entity.ContractManage;
@@ -152,14 +153,36 @@ public class MasterOrderServiceImpl extends BaseServiceImpl<MasterOrderMapper, M
}
@Override
public List<MasterOrderVO> exportWaybills(MasterOrderVO query) {
List<MasterOrderVO> result = new ArrayList<>();
public List<MasterOrderWaybillExcel> exportWaybills(MasterOrderVO query) {
List<MasterOrderWaybillExcel> result = new ArrayList<>();
for (MasterOrder masterOrder : list(buildQuery(query))) {
for (Waybill waybill : waybillService.list(new LambdaQueryWrapper<Waybill>().eq(Waybill::getMasterNo, masterOrder.getMasterNo()))) {
MasterOrderVO row = toVO(masterOrder);
MasterOrderWaybillExcel row = new MasterOrderWaybillExcel();
row.setMasterNo(masterOrder.getMasterNo());
row.setWaybillNo(waybill.getWaybillNo());
row.setProjectName(waybill.getProjectName());
row.setContractName(waybill.getContractName());
row.setCustomerName(waybill.getCustomerName());
row.setTransportType(waybill.getTransportType());
row.setCargoName(waybill.getCargoName());
row.setCargoType(waybill.getCargoType());
row.setMasterNo(waybill.getWaybillNo());
row.setQuantity(waybill.getQuantity());
row.setQuantityUnit(waybill.getQuantityUnit());
row.setDepartureAddress(waybill.getDepartureAddress());
row.setDepartureContact(waybill.getDepartureContact());
row.setDeparturePhone(waybill.getDeparturePhone());
row.setArrivalAddress(waybill.getArrivalAddress());
row.setArrivalContact(waybill.getArrivalContact());
row.setArrivalPhone(waybill.getArrivalPhone());
row.setCarrierType(waybill.getCarrierType());
row.setCarrierName(waybill.getCarrierName());
row.setDriverName(waybill.getDriverName());
row.setVehicleNo(waybill.getVehicleNo());
row.setStartDate(waybill.getStartDate());
row.setEndDate(waybill.getEndDate());
row.setBusinessStatus(waybill.getBusinessStatus());
row.setRemark(waybill.getRemark());
row.setCreateTime(waybill.getCreateTime());
result.add(row);
}
}
@@ -0,0 +1,228 @@
/**
* BladeX Commercial License Agreement
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
*/
package org.springblade.transport.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.RequiredArgsConstructor;
import org.springblade.core.log.exception.ServiceException;
import org.springblade.core.mp.base.BaseServiceImpl;
import org.springblade.core.tool.utils.BeanUtil;
import org.springblade.core.tool.utils.Func;
import org.springblade.system.cache.UserCache;
import org.springblade.transport.mapper.WaybillImportBatchMapper;
import org.springblade.transport.pojo.dto.WaybillImportBatchRequest;
import org.springblade.transport.pojo.entity.CustomerArchive;
import org.springblade.transport.pojo.entity.ProjectApply;
import org.springblade.transport.pojo.entity.TransportPlan;
import org.springblade.transport.pojo.entity.Waybill;
import org.springblade.transport.pojo.entity.WaybillImportBatch;
import org.springblade.transport.pojo.vo.BusinessRemoveResultVO;
import org.springblade.transport.pojo.vo.WaybillImportBatchVO;
import org.springblade.transport.service.ICustomerArchiveService;
import org.springblade.transport.service.IProjectApplyService;
import org.springblade.transport.service.ITransportPlanService;
import org.springblade.transport.service.IWaybillImportBatchService;
import org.springblade.transport.service.IWaybillService;
import org.springblade.transport.support.TransportBusinessSupport;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;
/** 运单批次服务实现。 */
@Service
@RequiredArgsConstructor
public class WaybillImportBatchServiceImpl extends BaseServiceImpl<WaybillImportBatchMapper, WaybillImportBatch> implements IWaybillImportBatchService {
private static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
private final IWaybillService waybillService;
private final ICustomerArchiveService customerArchiveService;
private final IProjectApplyService projectApplyService;
private final ITransportPlanService transportPlanService;
@Override
@Transactional(rollbackFor = Exception.class)
public WaybillImportBatch saveDraft(WaybillImportBatchRequest request) {
WaybillImportBatch batch = buildBatch(request, "draft");
batch.setWaybillCount(0);
if (Func.isNotEmpty(request.getId())) {
WaybillImportBatch oldBatch = getById(request.getId());
if (oldBatch == null || Objects.equals(oldBatch.getIsDeleted(), 1)) throw new ServiceException("运单批次不存在");
batch.setId(oldBatch.getId());
batch.setBatchNo(oldBatch.getBatchNo());
}
saveOrUpdate(batch);
return batch;
}
@Override
@Transactional(rollbackFor = Exception.class)
public WaybillImportBatch confirm(WaybillImportBatchRequest request) {
if (Func.isEmpty(request.getRows())) throw new ServiceException("请上传至少一条运单明细");
String importStatus = "processing".equals(request.getStatus()) ? "processing" : "completed";
WaybillImportBatch batch = buildBatch(request, importStatus);
if (Func.isNotEmpty(request.getId())) {
WaybillImportBatch oldBatch = getById(request.getId());
if (oldBatch == null || Objects.equals(oldBatch.getIsDeleted(), 1)) throw new ServiceException("运单批次不存在");
if (!"draft".equals(oldBatch.getImportStatus())) throw new ServiceException("仅草稿状态的批次允许确认导入");
batch.setId(oldBatch.getId());
batch.setBatchNo(oldBatch.getBatchNo());
}
batch.setWaybillCount(0);
saveOrUpdate(batch);
for (int index = 0; index < request.getRows().size(); index++) {
try {
Waybill waybill = buildWaybill(request.getRows().get(index), batch);
waybillService.submit(waybill);
} catch (Exception exception) {
throw new ServiceException("" + (index + 1) + "行导入失败:" + exception.getMessage());
}
}
batch.setWaybillCount(request.getRows().size());
batch.setImportStatus(importStatus);
updateById(batch);
return batch;
}
@Override
public IPage<WaybillImportBatchVO> page(IPage<WaybillImportBatch> page, WaybillImportBatchRequest request) {
LambdaQueryWrapper<WaybillImportBatch> queryWrapper = Wrappers.<WaybillImportBatch>lambdaQuery()
.eq(WaybillImportBatch::getIsDeleted, 0)
.like(Func.isNotEmpty(request.getBatchNo()), WaybillImportBatch::getBatchNo, request.getBatchNo())
.apply(Func.isNotEmpty(request.getCarrierId()), "FIND_IN_SET({0}, carrier_ids)", request.getCarrierId())
.eq(Func.isNotEmpty(request.getCarrierName()), WaybillImportBatch::getCarrierName, request.getCarrierName())
.orderByDesc(WaybillImportBatch::getCreateTime);
IPage<WaybillImportBatch> entityPage = page(page, queryWrapper);
List<WaybillImportBatchVO> records = entityPage.getRecords().stream().map(this::toVO).toList();
Page<WaybillImportBatchVO> resultPage = new Page<>(entityPage.getCurrent(), entityPage.getSize(), entityPage.getTotal());
resultPage.setRecords(records);
return resultPage;
}
@Override
@Transactional(rollbackFor = Exception.class)
public BusinessRemoveResultVO removeBatches(String ids) {
List<Long> idList = Func.toLongList(ids);
if (Func.isEmpty(idList)) throw new ServiceException("请选择需要删除的运单批次");
BusinessRemoveResultVO result = new BusinessRemoveResultVO();
for (WaybillImportBatch batch : listByIds(idList)) {
if (Objects.equals(batch.getIsDeleted(), 1)) continue;
List<Waybill> waybills = waybillService.list(Wrappers.<Waybill>lambdaQuery()
.eq(Waybill::getImportBatchId, batch.getId()).eq(Waybill::getIsDeleted, 0));
if (Func.isNotEmpty(waybills)) {
waybillService.deleteLogic(waybills.stream().map(Waybill::getId).toList());
}
deleteLogic(List.of(batch.getId()));
result.setSuccessCount(result.getSuccessCount() + 1);
}
return result;
}
private WaybillImportBatch buildBatch(WaybillImportBatchRequest request, String importStatus) {
if (Func.isEmpty(request.getProjectId())) throw new ServiceException("请选择项目");
if (Func.isEmpty(request.getContractId())) throw new ServiceException("请选择客户合同");
if (Func.isEmpty(request.getCarrierType())) throw new ServiceException("请选择承运类型");
if (Func.isEmpty(request.getImportType())) throw new ServiceException("请选择导入类型");
WaybillImportBatch batch = new WaybillImportBatch();
BeanUtil.copyProperties(request, batch);
batch.setBatchNo(Func.isEmpty(request.getBatchNo()) ? nextCode() : request.getBatchNo());
batch.setCarrierIds(joinIds(request.getCarrierIds()));
batch.setCarrierName(resolveCarrierNames(request.getCarrierIds(), request.getCarrierName()));
batch.setImportStatus(importStatus);
batch.setImportType("settlement".equals(request.getImportType()) ? "settlement" : "waybill");
ProjectApply project = projectApplyService.getById(request.getProjectId());
if (project == null || !List.of("approved", "change_approved").contains(project.getApprovalStatus())) {
throw new ServiceException("仅允许选择审核通过或变更审核通过的项目");
}
batch.setProjectName(project.getProjectName());
if (Func.isEmpty(batch.getCustomerName())) batch.setCustomerName(project.getCustomerNames());
TransportPlan plan = Func.isEmpty(request.getPlanId()) ? null : transportPlanService.getById(request.getPlanId());
if (plan != null) batch.setPlanName(plan.getPlanName());
return batch;
}
private Waybill buildWaybill(Map<String, Object> row, WaybillImportBatch batch) {
Waybill waybill = BeanUtil.copyProperties(row, Waybill.class);
if (waybill == null) throw new ServiceException("运单数据不正确");
waybill.setProjectId(batch.getProjectId());
waybill.setProjectName(batch.getProjectName());
waybill.setCustomerName(batch.getCustomerName());
waybill.setContractId(batch.getContractId());
waybill.setContractName(batch.getContractName());
waybill.setCarrierType(batch.getCarrierType());
waybill.setCarrierId(firstCarrierId(batch.getCarrierIds()));
waybill.setCarrierName(batch.getCarrierName());
waybill.setPlanId(batch.getPlanId());
waybill.setPlanName(batch.getPlanName());
waybill.setImportBatchId(batch.getId());
waybill.setBatchNo(batch.getBatchNo());
waybill.setDataSource("批量导入");
waybill.setBusinessStatus("processing".equals(batch.getImportStatus()) ? "pending" : batch.getImportStatus());
waybill.setQuantity(defaultQuantity(waybill.getQuantity()));
waybill.setQuantityUnit(Func.isEmpty(waybill.getQuantityUnit()) ? "" : waybill.getQuantityUnit());
waybill.setPriceUnit(Func.isEmpty(waybill.getPriceUnit()) ? "" : waybill.getPriceUnit());
waybill.setStartDate(parseDate(row.get("startDate"), "开始时间"));
waybill.setEndDate(parseDate(row.get("endDate"), "结束时间"));
return waybill;
}
private LocalDate parseDate(Object value, String fieldName) {
if (value == null || String.valueOf(value).isBlank()) throw new ServiceException(fieldName + "不能为空");
String text = String.valueOf(value).trim();
try {
return text.length() == 10 ? LocalDate.parse(text) : LocalDate.parse(text, DATE_TIME_FORMATTER);
} catch (DateTimeParseException exception) {
throw new ServiceException(fieldName + "格式必须为 YYYY-MM-DD HH:mm:ss");
}
}
private BigDecimal defaultQuantity(BigDecimal quantity) {
return quantity == null ? BigDecimal.ONE : quantity;
}
private Long firstCarrierId(String carrierIds) {
if (Func.isEmpty(carrierIds)) return null;
return Func.toLongList(carrierIds).stream().findFirst().orElse(null);
}
private String resolveCarrierNames(List<Long> carrierIds, String carrierName) {
if (Func.isNotEmpty(carrierName)) return carrierName;
if (Func.isEmpty(carrierIds)) return null;
List<CustomerArchive> carriers = customerArchiveService.listByIds(carrierIds);
return carriers.stream().map(CustomerArchive::getFullName).filter(Func::isNotEmpty).collect(Collectors.joining(","));
}
private String joinIds(List<Long> carrierIds) {
return Func.isEmpty(carrierIds) ? null : carrierIds.stream().map(String::valueOf).collect(Collectors.joining(","));
}
private WaybillImportBatchVO toVO(WaybillImportBatch batch) {
WaybillImportBatchVO vo = BeanUtil.copyProperties(batch, WaybillImportBatchVO.class);
if (vo == null) throw new ServiceException("运单批次数据转换失败");
vo.setImportTypeName("settlement".equals(batch.getImportType()) ? "结算单" : "运单");
vo.setStatusName(switch (batch.getImportStatus()) { case "draft" -> "草稿"; case "processing" -> "进行中"; default -> "完成"; });
vo.setCreateUserName(UserCache.getUserRealName(batch.getCreateUser()));
vo.setUpdateUserName(UserCache.getUserRealName(batch.getUpdateUser()));
return vo;
}
private synchronized String nextCode() {
String prefix = "YDB" + LocalDate.now().format(DateTimeFormatter.BASIC_ISO_DATE);
long count = count(Wrappers.<WaybillImportBatch>lambdaQuery().likeRight(WaybillImportBatch::getBatchNo, prefix));
return prefix + String.format("%04d", count + 1);
}
}
@@ -427,6 +427,9 @@ public class WaybillServiceImpl extends BaseServiceImpl<WaybillMapper, Waybill>
if (Func.isNotEmpty(waybill.getBatchNo())) {
queryWrapper.like(Waybill::getBatchNo, waybill.getBatchNo());
}
if (Func.isNotEmpty(waybill.getImportBatchId())) {
queryWrapper.eq(Waybill::getImportBatchId, waybill.getImportBatchId());
}
if (Func.isNotEmpty(waybill.getRelationNo())) {
queryWrapper.like(Waybill::getRelationNo, waybill.getRelationNo());
}