调整结算模块
This commit is contained in:
+1
@@ -41,6 +41,7 @@ public class TransportReconciliation extends TenantEntity {
|
||||
private Long contractId;
|
||||
private String contractNo;
|
||||
private String contractName;
|
||||
private String customerName;
|
||||
private String payerName;
|
||||
private String payeeName;
|
||||
private String currency;
|
||||
|
||||
+1
-1
@@ -33,7 +33,7 @@ public class VehicleReconciliationExcel implements Serializable {
|
||||
@ExcelProperty("里程(KM)") @NumberFormat("0.00") private BigDecimal mileage;
|
||||
@ExcelProperty("批次号") private String batchNo;
|
||||
@ExcelProperty("运输单价") @NumberFormat("0.00") private BigDecimal unitPrice;
|
||||
@ExcelProperty("运费") @NumberFormat("0.00") private BigDecimal freightAmount;
|
||||
@ExcelProperty("运输费") @NumberFormat("0.00") private BigDecimal freightAmount;
|
||||
@ExcelProperty("费用项目1") @NumberFormat("0.00") private BigDecimal feeItemOne;
|
||||
@ExcelProperty("结算费用合计") @NumberFormat("0.00") private BigDecimal settlementAmount;
|
||||
@ExcelIgnore private String errorMessage;
|
||||
|
||||
+7
@@ -31,6 +31,7 @@ import org.springblade.transport.pojo.dto.ReceivablePayableTransferRequest;
|
||||
import org.springblade.transport.pojo.dto.ReceivablePayableUpdateFeeRequest;
|
||||
import org.springblade.transport.pojo.entity.MasterOrder;
|
||||
import org.springblade.transport.pojo.entity.ReceivablePayableDetail;
|
||||
import org.springblade.transport.pojo.entity.Waybill;
|
||||
import org.springblade.transport.pojo.vo.ReceivablePayableChangeRecordVO;
|
||||
import org.springblade.transport.pojo.vo.ReceivablePayableCargoFeeVO;
|
||||
import org.springblade.transport.pojo.vo.ReceivablePayableDetailVO;
|
||||
@@ -81,6 +82,12 @@ public interface IReceivablePayableDetailService extends BaseService<ReceivableP
|
||||
/** 完成运单后按合同系统计费模式自动生成应收、应付明细。 */
|
||||
void generateForCompletedWaybills(List<Long> waybillIds);
|
||||
|
||||
/**
|
||||
* 批量导入完成运单后按合同系统计费模式生成应收、应付明细。
|
||||
* <p>与导入事务共用同一事务,运单尚未提交,因此直接传入实体而非主键。</p>
|
||||
*/
|
||||
void generateForImportedWaybills(List<Waybill> waybills);
|
||||
|
||||
/** 完成配载单后按其记录的承运商合同汇总生成一条应付明细。 */
|
||||
void generateForCompletedLoading(List<Long> waybillIds, Long carrierContractId, String loadingNo);
|
||||
|
||||
|
||||
+8
@@ -641,6 +641,14 @@ public class ReceivablePayableDetailServiceImpl
|
||||
this::resolveWaybillCarrierContract, AuthUtil.getUserId(), new Date());
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void generateForImportedWaybills(List<Waybill> waybills) {
|
||||
if (Func.isEmpty(waybills)) return;
|
||||
generateAutomaticWaybillDetails(waybills, true,
|
||||
this::resolveWaybillCarrierContract, AuthUtil.getUserId(), new Date());
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(propagation = org.springframework.transaction.annotation.Propagation.REQUIRES_NEW,
|
||||
rollbackFor = Exception.class)
|
||||
|
||||
+114
-11
@@ -52,6 +52,7 @@ import org.springblade.transport.pojo.vo.TransportReconciliationVO;
|
||||
import org.springblade.transport.service.ITransportReconciliationService;
|
||||
import org.springblade.transport.wrapper.TransportReconciliationWrapper;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.interceptor.TransactionAspectSupport;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
@@ -139,6 +140,9 @@ public class TransportReconciliationServiceImpl
|
||||
@Override
|
||||
public TransportReconciliationVO detail(Long id) {
|
||||
TransportReconciliationVO vo = TransportReconciliationWrapper.build().entityVO(existing(id));
|
||||
if (Func.isEmpty(vo.getCustomerName())) {
|
||||
vo.setCustomerName("receivable".equals(vo.getSettlementType()) ? vo.getPayerName() : vo.getPayeeName());
|
||||
}
|
||||
vo.setInternalDetails(internalRows(id));
|
||||
vo.setExternalDetails(externalRows(id));
|
||||
vo.setChangeRecords(changeRecordMapper.selectList(Wrappers.<TransportReconciliationChangeRecord>lambdaQuery()
|
||||
@@ -196,32 +200,115 @@ public class TransportReconciliationServiceImpl
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public List<VehicleReconciliationFailureExcel> importVehicles(Long id, List<VehicleReconciliationExcel> rows) {
|
||||
if (Func.isEmpty(rows)) throw new ServiceException("导入数据不能为空");
|
||||
TransportReconciliation bill = editable(id);
|
||||
if (!VEHICLE.equals(bill.getReconciliationMode())) throw new ServiceException("当前对账模式不是整车总额对账");
|
||||
resetExternal(id);
|
||||
List<VehicleReconciliationFailureExcel> failures = new ArrayList<>();
|
||||
List<TransportReconciliationExternal> validExternals = new ArrayList<>();
|
||||
for (int index = 0; index < rows.size(); index++) {
|
||||
VehicleReconciliationExcel row = rows.get(index);
|
||||
List<String> validationErrors = validateImportVehicle(row);
|
||||
if (Func.isNotEmpty(validationErrors)) {
|
||||
VehicleReconciliationFailureExcel failure = new VehicleReconciliationFailureExcel();
|
||||
BeanUtil.copyProperties(row, failure);
|
||||
failure.setErrorMessage(org.springblade.common.excel.ImportFailureExcelUtil.formatErrorMessage(validationErrors));
|
||||
failures.add(failure);
|
||||
continue;
|
||||
}
|
||||
try {
|
||||
validateExternal(row.getVehicleNo(), row.getCargoName(), row.getTransportQuantity(), row.getSettlementAmount());
|
||||
TransportReconciliationExternal external = new TransportReconciliationExternal();
|
||||
BeanUtil.copyProperties(row, external);
|
||||
external.setReconciliationId(id); external.setExternalLineNo(index + 2);
|
||||
external.setActualDepartureTime(parseTime(row.getActualDepartureTime(), "实际发货时间"));
|
||||
external.setActualCompletionTime(parseTimeNullable(row.getActualCompletionTime(), "实际完成时间"));
|
||||
external.setFeeItemsJson(JsonUtil.toJson(Map.of("费用项目1", money(row.getFeeItemOne()))));
|
||||
external.setMatchStatus(UNMATCHED); external.setSuspectedDuplicate(false);
|
||||
external.setRawDataJson(JsonUtil.toJson(row)); externalMapper.insert(external);
|
||||
validExternals.add(buildVehicleExternal(id, index, row));
|
||||
} catch (Exception exception) {
|
||||
VehicleReconciliationFailureExcel failure = new VehicleReconciliationFailureExcel();
|
||||
BeanUtil.copyProperties(row, failure); failure.setErrorMessage(exception.getMessage());
|
||||
BeanUtil.copyProperties(row, failure);
|
||||
failure.setErrorMessage(org.springblade.common.excel.ImportFailureExcelUtil.formatErrorMessage(List.of(
|
||||
exception instanceof ServiceException ? exception.getMessage() : "导入失败")));
|
||||
failures.add(failure);
|
||||
}
|
||||
}
|
||||
if (Func.isNotEmpty(failures)) {
|
||||
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
|
||||
return failures;
|
||||
}
|
||||
for (TransportReconciliationExternal external : validExternals) {
|
||||
if (externalMapper.insert(external) <= 0) throw new ServiceException("外部账单保存失败");
|
||||
}
|
||||
refreshStats(id);
|
||||
return failures;
|
||||
}
|
||||
|
||||
private TransportReconciliationExternal buildVehicleExternal(Long reconciliationId, int index,
|
||||
VehicleReconciliationExcel row) {
|
||||
TransportReconciliationExternal external = new TransportReconciliationExternal();
|
||||
BeanUtil.copyProperties(row, external);
|
||||
external.setReconciliationId(reconciliationId);
|
||||
external.setExternalLineNo(index + 2);
|
||||
external.setActualDepartureTime(parseTime(row.getActualDepartureTime(), "实际发货时间"));
|
||||
external.setActualCompletionTime(parseTimeNullable(row.getActualCompletionTime(), "实际完成时间"));
|
||||
external.setFeeItemsJson(JsonUtil.toJson(Map.of("费用项目1", money(row.getFeeItemOne()))));
|
||||
external.setMatchStatus(UNMATCHED);
|
||||
external.setSuspectedDuplicate(false);
|
||||
external.setRawDataJson(JsonUtil.toJson(row));
|
||||
return external;
|
||||
}
|
||||
|
||||
private List<String> validateImportVehicle(VehicleReconciliationExcel row) {
|
||||
List<String> validationErrors = new ArrayList<>();
|
||||
org.springblade.common.excel.ImportFailureExcelUtil.addValidationError(validationErrors,
|
||||
Func.isEmpty(row.getVehicleNo()), "车牌号不能为空");
|
||||
org.springblade.common.excel.ImportFailureExcelUtil.addValidationError(validationErrors,
|
||||
Func.isEmpty(row.getCargoName()), "货物名称不能为空");
|
||||
org.springblade.common.excel.ImportFailureExcelUtil.addValidationError(validationErrors,
|
||||
Func.isEmpty(row.getActualDepartureTime()), "实际发货时间不能为空");
|
||||
org.springblade.common.excel.ImportFailureExcelUtil.addValidationError(validationErrors,
|
||||
Func.isEmpty(row.getTransportQuantity()), "运输总量不能为空");
|
||||
org.springblade.common.excel.ImportFailureExcelUtil.addValidationError(validationErrors,
|
||||
Func.isEmpty(row.getSettlementAmount()), "结算费用合计不能为空");
|
||||
|
||||
addImportLengthError(validationErrors, row.getVehicleNo(), 30, "车牌号不能超过30字");
|
||||
addImportLengthError(validationErrors, row.getDepartureAddress(), 500, "发货地址不能超过500字");
|
||||
addImportLengthError(validationErrors, row.getArrivalAddress(), 500, "到货地址不能超过500字");
|
||||
addImportLengthError(validationErrors, row.getTransportType(), 100, "运输类型不能超过100字");
|
||||
addImportLengthError(validationErrors, row.getCargoName(), 500, "货物名称不能超过500字");
|
||||
addImportLengthError(validationErrors, row.getCargoType(), 500, "货物类型不能超过500字");
|
||||
addImportLengthError(validationErrors, row.getBatchNo(), 100, "批次号不能超过100字");
|
||||
|
||||
addImportDecimalErrors(validationErrors, row.getTransportQuantity(), "运输总量", 6);
|
||||
addImportDecimalErrors(validationErrors, row.getMileage(), "里程(KM)", 2);
|
||||
addImportDecimalErrors(validationErrors, row.getUnitPrice(), "运输单价", 2);
|
||||
addImportDecimalErrors(validationErrors, row.getFreightAmount(), "运输费", 2);
|
||||
addImportDecimalErrors(validationErrors, row.getFeeItemOne(), "费用项目1", 2);
|
||||
addImportDecimalErrors(validationErrors, row.getSettlementAmount(), "结算费用合计", 2);
|
||||
|
||||
LocalDateTime departureTime = parseImportTime(row.getActualDepartureTime(), "实际发货时间", validationErrors);
|
||||
LocalDateTime completionTime = parseImportTime(row.getActualCompletionTime(), "实际完成时间", validationErrors);
|
||||
org.springblade.common.excel.ImportFailureExcelUtil.addValidationError(validationErrors,
|
||||
departureTime != null && completionTime != null && completionTime.isBefore(departureTime),
|
||||
"实际完成时间不能早于实际发货时间");
|
||||
return validationErrors;
|
||||
}
|
||||
|
||||
private LocalDateTime parseImportTime(String value, String field, List<String> validationErrors) {
|
||||
if (Func.isEmpty(value)) return null;
|
||||
try {
|
||||
return parseTimeNullable(value, field);
|
||||
} catch (ServiceException exception) {
|
||||
org.springblade.common.excel.ImportFailureExcelUtil.addValidationError(validationErrors, true, exception.getMessage());
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private void addImportLengthError(List<String> validationErrors, String value, int maxLength, String message) {
|
||||
org.springblade.common.excel.ImportFailureExcelUtil.addLengthValidationError(validationErrors, value, maxLength, message);
|
||||
}
|
||||
|
||||
private void addImportDecimalErrors(List<String> validationErrors, BigDecimal value, String field, int scale) {
|
||||
org.springblade.common.excel.ImportFailureExcelUtil.addValidationError(validationErrors,
|
||||
value != null && value.compareTo(BigDecimal.ZERO) < 0, field + "不能小于0");
|
||||
org.springblade.common.excel.ImportFailureExcelUtil.addValidationError(validationErrors,
|
||||
value != null && value.stripTrailingZeros().scale() > scale, field + "最多保留" + scale + "位小数");
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public List<CargoReconciliationFailureExcel> importCargoes(Long id, List<CargoReconciliationExcel> rows) {
|
||||
@@ -563,6 +650,7 @@ public class TransportReconciliationServiceImpl
|
||||
bill.setFormalSettlementId(formal.getId()); bill.setFormalSettlementNo(formal.getFormalSettlementNo()); bill.setSettlementType(formal.getSettlementType());
|
||||
bill.setProjectId(formal.getProjectId()); bill.setProjectName(formal.getProjectName()); bill.setDeptId(formal.getDeptId()); bill.setDeptName(formal.getDeptName());
|
||||
bill.setContractId(formal.getContractId()); bill.setContractNo(formal.getContractNo()); bill.setContractName(formal.getContractName());
|
||||
bill.setCustomerName("receivable".equals(formal.getSettlementType()) ? formal.getPayerName() : formal.getPayeeName());
|
||||
bill.setPayerName(formal.getPayerName()); bill.setPayeeName(formal.getPayeeName()); bill.setCurrency(formal.getCurrency());
|
||||
bill.setSettlementAmount(money(formal.getSettlementAmount())); bill.setPaidAmount(money(formal.getPaidAmount()));
|
||||
List<String> preNos = formalSourceMapper.selectList(Wrappers.<FormalSettlementSource>lambdaQuery().eq(FormalSettlementSource::getFormalSettlementId, formal.getId()))
|
||||
@@ -637,5 +725,20 @@ public class TransportReconciliationServiceImpl
|
||||
private BigDecimal sumExternalQuantity(List<TransportReconciliationExternal> rows) { return rows.stream().map(TransportReconciliationExternal::getTransportQuantity).map(this::money).reduce(BigDecimal.ZERO, BigDecimal::add); }
|
||||
private BigDecimal sumInternalAmount(List<TransportReconciliationInternal> rows) { return rows.stream().map(TransportReconciliationInternal::getSettlementAmount).map(this::money).reduce(BigDecimal.ZERO, BigDecimal::add); }
|
||||
private BigDecimal sumExternalAmount(List<TransportReconciliationExternal> rows) { return rows.stream().map(TransportReconciliationExternal::getSettlementAmount).map(this::money).reduce(BigDecimal.ZERO, BigDecimal::add); }
|
||||
private String nextNo() { return "DZ" + LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmssSSS")); }
|
||||
private synchronized String nextNo() {
|
||||
String prefix = "DZD" + LocalDate.now().format(DateTimeFormatter.BASIC_ISO_DATE);
|
||||
int sequence = list(Wrappers.<TransportReconciliation>lambdaQuery()
|
||||
.select(TransportReconciliation::getReconciliationNo)
|
||||
.likeRight(TransportReconciliation::getReconciliationNo, prefix))
|
||||
.stream()
|
||||
.map(TransportReconciliation::getReconciliationNo)
|
||||
.filter(number -> number != null && number.length() == prefix.length() + 5)
|
||||
.map(number -> number.substring(prefix.length()))
|
||||
.filter(suffix -> suffix.chars().allMatch(Character::isDigit))
|
||||
.mapToInt(Integer::parseInt)
|
||||
.max()
|
||||
.orElse(0) + 1;
|
||||
if (sequence > 99999) throw new ServiceException("当日运输对账单号流水已用完");
|
||||
return prefix + String.format("%05d", sequence);
|
||||
}
|
||||
}
|
||||
|
||||
+51
-27
@@ -25,6 +25,7 @@ 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.IReceivablePayableDetailService;
|
||||
import org.springblade.transport.service.ITransportPlanService;
|
||||
import org.springblade.transport.service.IWaybillImportBatchService;
|
||||
import org.springblade.transport.service.IWaybillService;
|
||||
@@ -48,56 +49,75 @@ import java.util.stream.Collectors;
|
||||
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 static final String STATUS_DRAFT = "draft";
|
||||
private static final String STATUS_COMPLETED = "completed";
|
||||
private static final String IMPORT_TYPE_WAYBILL = "waybill";
|
||||
private static final String IMPORT_TYPE_SETTLEMENT = "settlement";
|
||||
private final IWaybillService waybillService;
|
||||
private final ICustomerArchiveService customerArchiveService;
|
||||
private final IProjectApplyService projectApplyService;
|
||||
private final ITransportPlanService transportPlanService;
|
||||
private final IReceivablePayableDetailService receivablePayableDetailService;
|
||||
|
||||
@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;
|
||||
return persist(request, STATUS_DRAFT);
|
||||
}
|
||||
|
||||
@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";
|
||||
return persist(request, STATUS_DRAFT.equals(request.getStatus()) ? STATUS_DRAFT : STATUS_COMPLETED);
|
||||
}
|
||||
|
||||
/** 草稿与确认导入共用落库流程,差异仅在于运单是否走校验以及是否生成应收应付明细。 */
|
||||
private WaybillImportBatch persist(WaybillImportBatchRequest request, String importStatus) {
|
||||
boolean draft = STATUS_DRAFT.equals(importStatus);
|
||||
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("仅草稿状态的批次允许确认导入");
|
||||
if (!STATUS_DRAFT.equals(oldBatch.getImportStatus())) throw new ServiceException("仅草稿状态的批次允许编辑");
|
||||
batch.setId(oldBatch.getId());
|
||||
batch.setBatchNo(oldBatch.getBatchNo());
|
||||
}
|
||||
batch.setWaybillCount(0);
|
||||
saveOrUpdate(batch);
|
||||
// 重新落库前清理批次已生成的运单,避免草稿反复保存产生重复运单。
|
||||
clearBatchWaybills(batch.getId());
|
||||
|
||||
for (int index = 0; index < request.getRows().size(); index++) {
|
||||
List<Map<String, Object>> rows = Func.isEmpty(request.getRows()) ? List.of() : request.getRows();
|
||||
List<Waybill> waybills = new ArrayList<>();
|
||||
for (int index = 0; index < rows.size(); index++) {
|
||||
try {
|
||||
Waybill waybill = buildWaybill(request.getRows().get(index), batch, request.getCarrierContractId());
|
||||
waybillService.submit(waybill);
|
||||
Waybill waybill = buildWaybill(rows.get(index), batch, request.getCarrierContractId(), draft);
|
||||
if (draft) waybillService.saveDraft(waybill); else waybillService.submit(waybill);
|
||||
waybills.add(waybill);
|
||||
} catch (Exception exception) {
|
||||
throw new ServiceException("第" + (index + 1) + "行导入失败:" + exception.getMessage());
|
||||
throw new ServiceException("第" + (index + 1) + "行" + (draft ? "保存" : "导入") + "失败:" + exception.getMessage());
|
||||
}
|
||||
}
|
||||
batch.setWaybillCount(request.getRows().size());
|
||||
batch.setImportStatus(importStatus);
|
||||
batch.setWaybillCount(waybills.size());
|
||||
updateById(batch);
|
||||
// 导入完成且导入类型为运单时,按合同费用生成模式(系统生成)同步生成应收应付明细。
|
||||
if (!draft && IMPORT_TYPE_WAYBILL.equals(batch.getImportType())) {
|
||||
receivablePayableDetailService.generateForImportedWaybills(waybills);
|
||||
}
|
||||
return batch;
|
||||
}
|
||||
|
||||
private void clearBatchWaybills(Long batchId) {
|
||||
if (Func.isEmpty(batchId)) return;
|
||||
List<Waybill> waybills = waybillService.list(Wrappers.<Waybill>lambdaQuery()
|
||||
.eq(Waybill::getImportBatchId, batchId).eq(Waybill::getIsDeleted, 0));
|
||||
if (Func.isNotEmpty(waybills)) {
|
||||
waybillService.deleteLogic(waybills.stream().map(Waybill::getId).toList());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public IPage<WaybillImportBatchVO> page(IPage<WaybillImportBatch> page, WaybillImportBatchRequest request) {
|
||||
LambdaQueryWrapper<WaybillImportBatch> queryWrapper = Wrappers.<WaybillImportBatch>lambdaQuery()
|
||||
@@ -143,7 +163,7 @@ public class WaybillImportBatchServiceImpl extends BaseServiceImpl<WaybillImport
|
||||
batch.setCarrierIds(joinIds(request.getCarrierIds()));
|
||||
batch.setCarrierName(resolveCarrierNames(request.getCarrierIds(), request.getCarrierName()));
|
||||
batch.setImportStatus(importStatus);
|
||||
batch.setImportType("settlement".equals(request.getImportType()) ? "settlement" : "waybill");
|
||||
batch.setImportType(IMPORT_TYPE_SETTLEMENT.equals(request.getImportType()) ? IMPORT_TYPE_SETTLEMENT : IMPORT_TYPE_WAYBILL);
|
||||
ProjectApply project = projectApplyService.getById(request.getProjectId());
|
||||
if (project == null || !List.of("approved", "change_approved").contains(project.getApprovalStatus())) {
|
||||
throw new ServiceException("仅允许选择审核通过或变更审核通过的项目");
|
||||
@@ -155,7 +175,7 @@ public class WaybillImportBatchServiceImpl extends BaseServiceImpl<WaybillImport
|
||||
return batch;
|
||||
}
|
||||
|
||||
private Waybill buildWaybill(Map<String, Object> row, WaybillImportBatch batch, Long carrierContractId) {
|
||||
private Waybill buildWaybill(Map<String, Object> row, WaybillImportBatch batch, Long carrierContractId, boolean draft) {
|
||||
if (row == null) throw new ServiceException("运单数据不正确");
|
||||
Waybill waybill = new Waybill();
|
||||
waybill.setOriginalNo(stringValue(row, "originalNo"));
|
||||
@@ -207,12 +227,13 @@ public class WaybillImportBatchServiceImpl extends BaseServiceImpl<WaybillImport
|
||||
waybill.setImportBatchId(batch.getId());
|
||||
waybill.setBatchNo(batch.getBatchNo());
|
||||
waybill.setDataSource("批量导入");
|
||||
waybill.setBusinessStatus("processing".equals(batch.getImportStatus()) ? "pending" : batch.getImportStatus());
|
||||
waybill.setBusinessStatus(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"), "结束时间"));
|
||||
// 草稿允许明细不完整,时间为空时不阻断保存。
|
||||
waybill.setStartDate(parseDate(row.get("startDate"), "开始时间", !draft));
|
||||
waybill.setEndDate(parseDate(row.get("endDate"), "结束时间", !draft));
|
||||
return waybill;
|
||||
}
|
||||
|
||||
@@ -254,8 +275,11 @@ public class WaybillImportBatchServiceImpl extends BaseServiceImpl<WaybillImport
|
||||
return mileage != null && mileage.compareTo(BigDecimal.ONE.negate()) == 0 ? null : mileage;
|
||||
}
|
||||
|
||||
private LocalDate parseDate(Object value, String fieldName) {
|
||||
if (value == null || String.valueOf(value).isBlank()) throw new ServiceException(fieldName + "不能为空");
|
||||
private LocalDate parseDate(Object value, String fieldName, boolean required) {
|
||||
if (value == null || String.valueOf(value).isBlank()) {
|
||||
if (!required) return null;
|
||||
throw new ServiceException(fieldName + "不能为空");
|
||||
}
|
||||
String text = String.valueOf(value).trim();
|
||||
try {
|
||||
return text.length() == 10 ? LocalDate.parse(text) : LocalDate.parse(text, DATE_TIME_FORMATTER);
|
||||
@@ -287,8 +311,8 @@ public class WaybillImportBatchServiceImpl extends BaseServiceImpl<WaybillImport
|
||||
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.setImportTypeName(IMPORT_TYPE_SETTLEMENT.equals(batch.getImportType()) ? "结算单" : "运单");
|
||||
vo.setStatusName(STATUS_DRAFT.equals(batch.getImportStatus()) ? "草稿" : "导入完成");
|
||||
vo.setCreateUserName(UserCache.getUserRealName(batch.getCreateUser()));
|
||||
vo.setUpdateUserName(UserCache.getUserRealName(batch.getUpdateUser()));
|
||||
return vo;
|
||||
|
||||
@@ -6,7 +6,7 @@ CREATE TABLE IF NOT EXISTS `blade_transport_reconciliation` (
|
||||
`reconciliation_no` varchar(100) NOT NULL, `formal_settlement_id` bigint(20) NOT NULL, `formal_settlement_no` varchar(100) NOT NULL,
|
||||
`pre_settlement_nos` varchar(1000) DEFAULT NULL, `settlement_type` varchar(30) NOT NULL, `reconciliation_mode` varchar(30) NOT NULL,
|
||||
`project_id` bigint(20) DEFAULT NULL, `project_name` varchar(100) DEFAULT NULL, `dept_id` bigint(20) DEFAULT NULL, `dept_name` varchar(100) DEFAULT NULL,
|
||||
`contract_id` bigint(20) DEFAULT NULL, `contract_no` varchar(100) DEFAULT NULL, `contract_name` varchar(200) DEFAULT NULL,
|
||||
`contract_id` bigint(20) DEFAULT NULL, `contract_no` varchar(100) DEFAULT NULL, `contract_name` varchar(200) DEFAULT NULL, `customer_name` varchar(200) DEFAULT NULL COMMENT '客户/承运商',
|
||||
`payer_name` varchar(200) DEFAULT NULL, `payee_name` varchar(200) DEFAULT NULL, `currency` varchar(20) DEFAULT 'RMB',
|
||||
`settlement_amount` decimal(18,2) DEFAULT 0, `paid_amount` decimal(18,2) DEFAULT 0, `reconciler_id` bigint(20) DEFAULT NULL,
|
||||
`reconciler_name` varchar(100) DEFAULT NULL, `reconciliation_date` date DEFAULT NULL, `reconciliation_status` varchar(30) NOT NULL DEFAULT 'unfinished',
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
SET @db_name = DATABASE();
|
||||
SET @column_exists = 0;
|
||||
|
||||
SELECT COUNT(*)
|
||||
INTO @column_exists
|
||||
FROM information_schema.columns
|
||||
WHERE table_schema = @db_name
|
||||
AND table_name = 'blade_transport_reconciliation'
|
||||
AND column_name = 'customer_name';
|
||||
|
||||
SET @alter_sql = IF(
|
||||
@column_exists = 0,
|
||||
'ALTER TABLE `blade_transport_reconciliation` ADD COLUMN `customer_name` varchar(200) DEFAULT NULL COMMENT ''客户/承运商'' AFTER `contract_name`',
|
||||
'SELECT 1'
|
||||
);
|
||||
PREPARE alter_statement FROM @alter_sql;
|
||||
EXECUTE alter_statement;
|
||||
DEALLOCATE PREPARE alter_statement;
|
||||
|
||||
UPDATE `blade_transport_reconciliation`
|
||||
SET `customer_name` = CASE
|
||||
WHEN `settlement_type` = 'receivable' THEN `payer_name`
|
||||
ELSE `payee_name`
|
||||
END
|
||||
WHERE `customer_name` IS NULL OR `customer_name` = '';
|
||||
Reference in New Issue
Block a user