调整预结算、正式结算
This commit is contained in:
+12
@@ -28,4 +28,16 @@ public class FormalSettlementSaveRequest implements Serializable {
|
||||
private BigDecimal exchangeRate;
|
||||
private String attachmentsJson;
|
||||
private String remark;
|
||||
private List<SummaryFee> summaryFees;
|
||||
|
||||
@Data
|
||||
public static class SummaryFee implements Serializable {
|
||||
@Serial private static final long serialVersionUID = 1L;
|
||||
private Long id;
|
||||
private String feeType;
|
||||
private String feeItem;
|
||||
private BigDecimal adjustAmount;
|
||||
private String remark;
|
||||
private Integer manualFlag;
|
||||
}
|
||||
}
|
||||
|
||||
+18
@@ -57,6 +57,15 @@ public class CommonRoute extends TenantEntity {
|
||||
@Schema(description = "发货地")
|
||||
private String departureName;
|
||||
|
||||
@Schema(description = "发货省ID")
|
||||
private String departureProvinceId;
|
||||
|
||||
@Schema(description = "发货市ID")
|
||||
private String departureCityId;
|
||||
|
||||
@Schema(description = "发货区ID")
|
||||
private String departureDistrictId;
|
||||
|
||||
@Schema(description = "发货地址")
|
||||
private String departureAddress;
|
||||
|
||||
@@ -78,6 +87,15 @@ public class CommonRoute extends TenantEntity {
|
||||
@Schema(description = "收货地")
|
||||
private String arrivalName;
|
||||
|
||||
@Schema(description = "收货省ID")
|
||||
private String arrivalProvinceId;
|
||||
|
||||
@Schema(description = "收货市ID")
|
||||
private String arrivalCityId;
|
||||
|
||||
@Schema(description = "收货区ID")
|
||||
private String arrivalDistrictId;
|
||||
|
||||
@Schema(description = "收货地址")
|
||||
private String arrivalAddress;
|
||||
|
||||
|
||||
+40
@@ -0,0 +1,40 @@
|
||||
/**
|
||||
* BladeX Commercial License Agreement
|
||||
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
|
||||
* <p>
|
||||
* Use of this software is governed by the Commercial License Agreement obtained after purchasing a license from BladeX.
|
||||
* <p>
|
||||
* Author: Chill Zhuang (bladejava@qq.com)
|
||||
*/
|
||||
package org.springblade.transport.pojo.entity;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import org.springblade.core.tenant.mp.TenantEntity;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.math.BigDecimal;
|
||||
|
||||
/**
|
||||
* 正式结算合计费用实体类
|
||||
*
|
||||
* @author Chill
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@TableName("blade_formal_settlement_summary_fee")
|
||||
@Schema(description = "正式结算合计费用")
|
||||
public class FormalSettlementSummaryFee extends TenantEntity {
|
||||
@Serial private static final long serialVersionUID = 1L;
|
||||
private Long formalSettlementId;
|
||||
private Integer lineNo;
|
||||
private String feeType;
|
||||
private String feeItem;
|
||||
private BigDecimal originalAmount;
|
||||
private BigDecimal adjustAmount;
|
||||
private BigDecimal settlementAmount;
|
||||
private String remark;
|
||||
private Integer manualFlag;
|
||||
}
|
||||
+2
@@ -15,6 +15,7 @@ import org.springblade.transport.pojo.entity.FormalSettlement;
|
||||
import org.springblade.transport.pojo.entity.FormalSettlementDetail;
|
||||
import org.springblade.transport.pojo.entity.FormalSettlementSource;
|
||||
import org.springblade.transport.pojo.entity.FormalSettlementPayment;
|
||||
import org.springblade.transport.pojo.entity.FormalSettlementSummaryFee;
|
||||
import org.springframework.format.annotation.DateTimeFormat;
|
||||
|
||||
import java.io.Serial;
|
||||
@@ -39,5 +40,6 @@ public class FormalSettlementVO extends FormalSettlement {
|
||||
@TableField(exist = false) private String preSettlementNo;
|
||||
@TableField(exist = false) private List<FormalSettlementSource> sources;
|
||||
@TableField(exist = false) private List<FormalSettlementDetail> details;
|
||||
@TableField(exist = false) private List<FormalSettlementSummaryFee> summaryFees;
|
||||
@TableField(exist = false) private List<FormalSettlementPayment> payments;
|
||||
}
|
||||
|
||||
+31
-16
@@ -73,64 +73,79 @@ public class FormalSettlementController extends BladeController {
|
||||
@GetMapping("/contract-options")
|
||||
@ApiOperationSupport(order = 4)
|
||||
@Operation(summary = "可选合同")
|
||||
public R<List<Map<String, Object>>> contractOptions(@RequestParam(required = false) String keyword) {
|
||||
return R.data(preSettlementService.contractOptions(keyword));
|
||||
public R<List<Map<String, Object>>> contractOptions(@RequestParam(required = false) String keyword,
|
||||
@RequestParam(required = false) Long projectId) {
|
||||
return R.data(preSettlementService.contractOptions(keyword, projectId));
|
||||
}
|
||||
|
||||
@GetMapping("/next-no")
|
||||
@ApiOperationSupport(order = 5)
|
||||
@Operation(summary = "获取最新正式结算单号")
|
||||
public R<String> nextNo() {
|
||||
return R.data(formalSettlementService.nextNo());
|
||||
}
|
||||
|
||||
@GetMapping("/fee-options")
|
||||
@ApiOperationSupport(order = 6)
|
||||
@Operation(summary = "可选费用类型及费用项")
|
||||
public R<List<Map<String, Object>>> feeOptions() {
|
||||
return R.data(preSettlementService.feeOptions());
|
||||
}
|
||||
|
||||
@GetMapping("/candidate-details")
|
||||
@ApiOperationSupport(order = 5)
|
||||
@ApiOperationSupport(order = 7)
|
||||
@Operation(summary = "可选应收应付明细")
|
||||
public R<IPage<Map<String, Object>>> candidateDetails(Query query, @RequestParam Long contractId,
|
||||
@RequestParam String settlementType, @RequestParam(required = false) String batchNo,
|
||||
@RequestParam(required = false) String feeStartDate, @RequestParam(required = false) String feeEndDate) {
|
||||
return R.data(preSettlementService.candidateDetails(Condition.getPage(query), contractId,
|
||||
settlementType, batchNo, feeStartDate, feeEndDate));
|
||||
@RequestParam(required = false) String createStartDate, @RequestParam(required = false) String createEndDate) {
|
||||
return R.data(preSettlementService.candidateDetailsByCreateTime(Condition.getPage(query), contractId,
|
||||
settlementType, batchNo, createStartDate, createEndDate));
|
||||
}
|
||||
|
||||
@PostMapping("/save")
|
||||
@ApiOperationSupport(order = 6)
|
||||
@ApiOperationSupport(order = 8)
|
||||
@Operation(summary = "保存正式结算草稿")
|
||||
public R<Long> save(@RequestBody FormalSettlementSaveRequest request) { return R.data(formalSettlementService.saveDraft(request)); }
|
||||
|
||||
@PostMapping("/remove")
|
||||
@ApiOperationSupport(order = 7)
|
||||
@ApiOperationSupport(order = 9)
|
||||
@Operation(summary = "删除正式结算草稿")
|
||||
public R remove(@RequestParam Long id) { formalSettlementService.removeDraft(id); return R.success("删除成功"); }
|
||||
|
||||
@PostMapping("/submit")
|
||||
@ApiOperationSupport(order = 8)
|
||||
@ApiOperationSupport(order = 10)
|
||||
@Operation(summary = "提交审批")
|
||||
public R submit(@RequestBody FormalSettlementStatusRequest request) { formalSettlementService.submit(request); return R.success("提交成功"); }
|
||||
|
||||
@PostMapping("/approve")
|
||||
@ApiOperationSupport(order = 9)
|
||||
@ApiOperationSupport(order = 11)
|
||||
@Operation(summary = "审批通过")
|
||||
public R approve(@RequestBody FormalSettlementStatusRequest request) { formalSettlementService.approve(request); return R.success("审批通过"); }
|
||||
|
||||
@PostMapping("/return")
|
||||
@ApiOperationSupport(order = 10)
|
||||
@ApiOperationSupport(order = 12)
|
||||
@Operation(summary = "审批驳回")
|
||||
public R returnBill(@RequestBody FormalSettlementStatusRequest request) { formalSettlementService.returnBill(request); return R.success("已驳回"); }
|
||||
|
||||
@PostMapping("/void")
|
||||
@ApiOperationSupport(order = 11)
|
||||
@ApiOperationSupport(order = 13)
|
||||
@Operation(summary = "作废正式结算单")
|
||||
public R voidBill(@RequestBody FormalSettlementStatusRequest request) { formalSettlementService.voidBill(request); return R.success("作废成功"); }
|
||||
|
||||
@PostMapping("/sync-kingdee")
|
||||
@ApiOperationSupport(order = 12)
|
||||
@ApiOperationSupport(order = 14)
|
||||
@Operation(summary = "推送金蝶应付单")
|
||||
public R<String> syncKingdee(@RequestParam Long id) { return R.data(formalSettlementService.syncKingdee(id)); }
|
||||
|
||||
@GetMapping("/detail-fees")
|
||||
@ApiOperationSupport(order = 13)
|
||||
@ApiOperationSupport(order = 15)
|
||||
@Operation(summary = "正式结算货物费用快照")
|
||||
public R<List<FormalSettlementDetailFee>> detailFees(@RequestParam Long detailId) {
|
||||
return R.data(formalSettlementService.detailFees(detailId));
|
||||
}
|
||||
|
||||
@PostMapping("/adjust-detail")
|
||||
@ApiOperationSupport(order = 14)
|
||||
@ApiOperationSupport(order = 16)
|
||||
@Operation(summary = "调整草稿结算明细")
|
||||
public R adjustDetail(@RequestBody PreSettlementDetailAdjustRequest request) {
|
||||
formalSettlementService.adjustDetail(request);
|
||||
@@ -138,7 +153,7 @@ public class FormalSettlementController extends BladeController {
|
||||
}
|
||||
|
||||
@PostMapping("/apply-payment")
|
||||
@ApiOperationSupport(order = 15)
|
||||
@ApiOperationSupport(order = 17)
|
||||
@Operation(summary = "发起尾款付款申请")
|
||||
public R<String> applyPayment(@RequestBody FormalSettlementPaymentRequest request) {
|
||||
return R.data(formalSettlementService.applyPayment(request));
|
||||
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
/**
|
||||
* BladeX Commercial License Agreement
|
||||
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
|
||||
* <p>
|
||||
* Use of this software is governed by the Commercial License Agreement obtained after purchasing a license from BladeX.
|
||||
* <p>
|
||||
* Author: Chill Zhuang (bladejava@qq.com)
|
||||
*/
|
||||
package org.springblade.transport.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import org.springblade.transport.pojo.entity.FormalSettlementSummaryFee;
|
||||
|
||||
/**
|
||||
* 正式结算合计费用 Mapper
|
||||
*
|
||||
* @author Chill
|
||||
*/
|
||||
public interface FormalSettlementSummaryFeeMapper extends BaseMapper<FormalSettlementSummaryFee> {
|
||||
}
|
||||
+1
@@ -29,6 +29,7 @@ import org.springblade.transport.pojo.dto.FormalSettlementPaymentRequest;
|
||||
public interface IFormalSettlementService extends BaseService<FormalSettlement> {
|
||||
IPage<FormalSettlementVO> selectPage(IPage<FormalSettlement> page, FormalSettlementVO query);
|
||||
IPage<PreSettlementVO> candidatePreSettlements(IPage<PreSettlement> page, PreSettlementVO query);
|
||||
String nextNo();
|
||||
FormalSettlementVO detail(Long id);
|
||||
Long saveDraft(FormalSettlementSaveRequest request);
|
||||
void removeDraft(Long id);
|
||||
|
||||
+8
-1
@@ -33,13 +33,20 @@ public interface IPreSettlementService extends BaseService<PreSettlement> {
|
||||
|
||||
PreSettlementVO detail(Long id);
|
||||
|
||||
List<Map<String, Object>> contractOptions(String keyword);
|
||||
default List<Map<String, Object>> contractOptions(String keyword) {
|
||||
return contractOptions(keyword, null);
|
||||
}
|
||||
|
||||
List<Map<String, Object>> contractOptions(String keyword, Long projectId);
|
||||
|
||||
List<Map<String, Object>> feeOptions();
|
||||
|
||||
IPage<Map<String, Object>> candidateDetails(IPage<?> page, Long contractId, String settlementType,
|
||||
String batchNo, String feeStartDate, String feeEndDate);
|
||||
|
||||
IPage<Map<String, Object>> candidateDetailsByCreateTime(IPage<?> page, Long contractId,
|
||||
String settlementType, String batchNo, String createStartDate, String createEndDate);
|
||||
|
||||
Long saveDraft(PreSettlementSaveRequest request);
|
||||
|
||||
void removeDraft(Long id);
|
||||
|
||||
+32
@@ -194,10 +194,16 @@ public class CommonRouteServiceImpl extends BaseServiceImpl<CommonRouteMapper, C
|
||||
commonRoute.setRouteCode(TransportBusinessSupport.trimToNull(commonRoute.getRouteCode()));
|
||||
commonRoute.setRouteName(TransportBusinessSupport.trimToNull(commonRoute.getRouteName()));
|
||||
commonRoute.setDepartureName(TransportBusinessSupport.trimToNull(commonRoute.getDepartureName()));
|
||||
commonRoute.setDepartureProvinceId(TransportBusinessSupport.trimToNull(commonRoute.getDepartureProvinceId()));
|
||||
commonRoute.setDepartureCityId(TransportBusinessSupport.trimToNull(commonRoute.getDepartureCityId()));
|
||||
commonRoute.setDepartureDistrictId(TransportBusinessSupport.trimToNull(commonRoute.getDepartureDistrictId()));
|
||||
commonRoute.setDepartureAddress(TransportBusinessSupport.trimToNull(commonRoute.getDepartureAddress()));
|
||||
commonRoute.setDepartureContact(TransportBusinessSupport.trimToNull(commonRoute.getDepartureContact()));
|
||||
commonRoute.setDeparturePhone(TransportBusinessSupport.trimToNull(commonRoute.getDeparturePhone()));
|
||||
commonRoute.setArrivalName(TransportBusinessSupport.trimToNull(commonRoute.getArrivalName()));
|
||||
commonRoute.setArrivalProvinceId(TransportBusinessSupport.trimToNull(commonRoute.getArrivalProvinceId()));
|
||||
commonRoute.setArrivalCityId(TransportBusinessSupport.trimToNull(commonRoute.getArrivalCityId()));
|
||||
commonRoute.setArrivalDistrictId(TransportBusinessSupport.trimToNull(commonRoute.getArrivalDistrictId()));
|
||||
commonRoute.setArrivalAddress(TransportBusinessSupport.trimToNull(commonRoute.getArrivalAddress()));
|
||||
commonRoute.setArrivalContact(TransportBusinessSupport.trimToNull(commonRoute.getArrivalContact()));
|
||||
commonRoute.setArrivalPhone(TransportBusinessSupport.trimToNull(commonRoute.getArrivalPhone()));
|
||||
@@ -217,15 +223,33 @@ public class CommonRouteServiceImpl extends BaseServiceImpl<CommonRouteMapper, C
|
||||
TransportBusinessSupport.validateRequired(commonRoute.getDepartureAddress(), "发货地址不能为空");
|
||||
TransportBusinessSupport.validateRequired(commonRoute.getArrivalName(), "收货地不能为空");
|
||||
TransportBusinessSupport.validateRequired(commonRoute.getArrivalAddress(), "收货地址不能为空");
|
||||
validateRegionIds(
|
||||
commonRoute.getDepartureProvinceId(),
|
||||
commonRoute.getDepartureCityId(),
|
||||
commonRoute.getDepartureDistrictId(),
|
||||
"发货地址"
|
||||
);
|
||||
validateRegionIds(
|
||||
commonRoute.getArrivalProvinceId(),
|
||||
commonRoute.getArrivalCityId(),
|
||||
commonRoute.getArrivalDistrictId(),
|
||||
"收货地址"
|
||||
);
|
||||
validateRouteNameUnique(commonRoute);
|
||||
validateAddressCombinationUnique(commonRoute);
|
||||
TransportBusinessSupport.validateLength(commonRoute.getRouteCode(), 255, "线路编号不能超过255字");
|
||||
TransportBusinessSupport.validateLength(commonRoute.getRouteName(), 255, "线路名称不能超过255字");
|
||||
TransportBusinessSupport.validateLength(commonRoute.getDepartureName(), 255, "发货地不能超过255字");
|
||||
TransportBusinessSupport.validateLength(commonRoute.getDepartureProvinceId(), 32, "发货省ID不能超过32字");
|
||||
TransportBusinessSupport.validateLength(commonRoute.getDepartureCityId(), 32, "发货市ID不能超过32字");
|
||||
TransportBusinessSupport.validateLength(commonRoute.getDepartureDistrictId(), 32, "发货区ID不能超过32字");
|
||||
TransportBusinessSupport.validateLength(commonRoute.getDepartureAddress(), 255, "发货地址不能超过255字");
|
||||
TransportBusinessSupport.validateLength(commonRoute.getDepartureContact(), 255, "发货联系人不能超过255字");
|
||||
TransportBusinessSupport.validateLength(commonRoute.getDeparturePhone(), 255, "发货联系方式不能超过255字");
|
||||
TransportBusinessSupport.validateLength(commonRoute.getArrivalName(), 255, "收货地不能超过255字");
|
||||
TransportBusinessSupport.validateLength(commonRoute.getArrivalProvinceId(), 32, "收货省ID不能超过32字");
|
||||
TransportBusinessSupport.validateLength(commonRoute.getArrivalCityId(), 32, "收货市ID不能超过32字");
|
||||
TransportBusinessSupport.validateLength(commonRoute.getArrivalDistrictId(), 32, "收货区ID不能超过32字");
|
||||
TransportBusinessSupport.validateLength(commonRoute.getArrivalAddress(), 255, "收货地址不能超过255字");
|
||||
TransportBusinessSupport.validateLength(commonRoute.getArrivalContact(), 255, "收货联系人不能超过255字");
|
||||
TransportBusinessSupport.validateLength(commonRoute.getArrivalPhone(), 255, "收货联系方式不能超过255字");
|
||||
@@ -239,6 +263,14 @@ public class CommonRouteServiceImpl extends BaseServiceImpl<CommonRouteMapper, C
|
||||
TransportBusinessSupport.validateCoordinate(commonRoute.getArrivalLatitude(), false);
|
||||
}
|
||||
|
||||
private void validateRegionIds(String provinceId, String cityId, String districtId, String addressLabel) {
|
||||
boolean allEmpty = Func.isEmpty(provinceId) && Func.isEmpty(cityId) && Func.isEmpty(districtId);
|
||||
boolean allPresent = Func.isNotEmpty(provinceId) && Func.isNotEmpty(cityId) && Func.isNotEmpty(districtId);
|
||||
if (!allEmpty && !allPresent) {
|
||||
throw new ServiceException(addressLabel + "的省、市、区ID必须完整");
|
||||
}
|
||||
}
|
||||
|
||||
private void validateRouteNameUnique(CommonRoute commonRoute) {
|
||||
LambdaQueryWrapper<CommonRoute> queryWrapper = Wrappers.<CommonRoute>lambdaQuery()
|
||||
.eq(CommonRoute::getIsDeleted, 0)
|
||||
|
||||
+262
-11
@@ -21,10 +21,12 @@ import org.springblade.transport.mapper.FormalSettlementDetailMapper;
|
||||
import org.springblade.transport.mapper.FormalSettlementDetailFeeMapper;
|
||||
import org.springblade.transport.mapper.FormalSettlementMapper;
|
||||
import org.springblade.transport.mapper.FormalSettlementSourceMapper;
|
||||
import org.springblade.transport.mapper.FormalSettlementSummaryFeeMapper;
|
||||
import org.springblade.transport.mapper.FormalSettlementPaymentMapper;
|
||||
import org.springblade.transport.mapper.PreSettlementDetailMapper;
|
||||
import org.springblade.transport.mapper.PreSettlementDetailFeeMapper;
|
||||
import org.springblade.transport.mapper.PreSettlementMapper;
|
||||
import org.springblade.transport.mapper.PreSettlementSummaryFeeMapper;
|
||||
import org.springblade.transport.mapper.ReceivablePayableDetailMapper;
|
||||
import org.springblade.transport.mapper.ReceivablePayableCargoFeeMapper;
|
||||
import org.springblade.transport.pojo.dto.FormalSettlementSaveRequest;
|
||||
@@ -35,11 +37,13 @@ import org.springblade.transport.pojo.entity.FormalSettlement;
|
||||
import org.springblade.transport.pojo.entity.FormalSettlementDetail;
|
||||
import org.springblade.transport.pojo.entity.FormalSettlementDetailFee;
|
||||
import org.springblade.transport.pojo.entity.FormalSettlementSource;
|
||||
import org.springblade.transport.pojo.entity.FormalSettlementSummaryFee;
|
||||
import org.springblade.transport.pojo.entity.FormalSettlementPayment;
|
||||
import org.springblade.transport.pojo.entity.ContractManage;
|
||||
import org.springblade.transport.pojo.entity.PreSettlement;
|
||||
import org.springblade.transport.pojo.entity.PreSettlementDetail;
|
||||
import org.springblade.transport.pojo.entity.PreSettlementDetailFee;
|
||||
import org.springblade.transport.pojo.entity.PreSettlementSummaryFee;
|
||||
import org.springblade.transport.pojo.entity.ReceivablePayableDetail;
|
||||
import org.springblade.transport.pojo.entity.ReceivablePayableCargoFee;
|
||||
import org.springblade.transport.pojo.entity.Waybill;
|
||||
@@ -47,6 +51,7 @@ import org.springblade.transport.pojo.vo.FormalSettlementVO;
|
||||
import org.springblade.transport.pojo.vo.PreSettlementVO;
|
||||
import org.springblade.transport.service.IFormalSettlementService;
|
||||
import org.springblade.transport.service.IContractManageService;
|
||||
import org.springblade.transport.service.IPreSettlementService;
|
||||
import org.springblade.transport.service.IWaybillService;
|
||||
import org.springblade.transport.wrapper.PreSettlementWrapper;
|
||||
import org.springblade.core.tool.jackson.JsonUtil;
|
||||
@@ -55,12 +60,17 @@ import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.math.RoundingMode;
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
@@ -79,15 +89,18 @@ public class FormalSettlementServiceImpl extends BaseServiceImpl<FormalSettlemen
|
||||
private static final String RETURNED = "returned";
|
||||
private static final String VOIDED = "voided";
|
||||
private final FormalSettlementSourceMapper sourceMapper;
|
||||
private final FormalSettlementSummaryFeeMapper summaryFeeMapper;
|
||||
private final FormalSettlementPaymentMapper paymentMapper;
|
||||
private final FormalSettlementDetailMapper detailMapper;
|
||||
private final FormalSettlementDetailFeeMapper detailFeeMapper;
|
||||
private final PreSettlementMapper preSettlementMapper;
|
||||
private final PreSettlementSummaryFeeMapper preSummaryFeeMapper;
|
||||
private final PreSettlementDetailMapper preDetailMapper;
|
||||
private final PreSettlementDetailFeeMapper preDetailFeeMapper;
|
||||
private final ReceivablePayableDetailMapper receivablePayableMapper;
|
||||
private final ReceivablePayableCargoFeeMapper receivablePayableCargoFeeMapper;
|
||||
private final IContractManageService contractManageService;
|
||||
private final IPreSettlementService preSettlementService;
|
||||
private final IWaybillService waybillService;
|
||||
|
||||
@Override
|
||||
@@ -130,6 +143,26 @@ public class FormalSettlementServiceImpl extends BaseServiceImpl<FormalSettlemen
|
||||
return PreSettlementWrapper.build().pageVO(result);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized String nextNo() {
|
||||
String prefix = "JS" + LocalDate.now().format(DateTimeFormatter.BASIC_ISO_DATE);
|
||||
List<String> numbers = list(Wrappers.<FormalSettlement>lambdaQuery()
|
||||
.select(FormalSettlement::getFormalSettlementNo)
|
||||
.likeRight(FormalSettlement::getFormalSettlementNo, prefix))
|
||||
.stream().map(FormalSettlement::getFormalSettlementNo).toList();
|
||||
int sequence = 1;
|
||||
if (!numbers.isEmpty()) {
|
||||
String latest = numbers.stream().max(String::compareTo).orElse(prefix);
|
||||
try {
|
||||
sequence = Integer.parseInt(latest.substring(prefix.length())) + 1;
|
||||
} catch (RuntimeException ignored) {
|
||||
sequence = Math.toIntExact(count(Wrappers.<FormalSettlement>lambdaQuery()
|
||||
.likeRight(FormalSettlement::getFormalSettlementNo, prefix))) + 1;
|
||||
}
|
||||
}
|
||||
return prefix + String.format("%04d", sequence);
|
||||
}
|
||||
|
||||
@Override
|
||||
public FormalSettlementVO detail(Long id) {
|
||||
FormalSettlement settlement = existing(id);
|
||||
@@ -138,6 +171,7 @@ public class FormalSettlementServiceImpl extends BaseServiceImpl<FormalSettlemen
|
||||
.eq(FormalSettlementSource::getFormalSettlementId, id).orderByAsc(FormalSettlementSource::getCreateTime)));
|
||||
vo.setDetails(detailMapper.selectList(Wrappers.<FormalSettlementDetail>lambdaQuery()
|
||||
.eq(FormalSettlementDetail::getFormalSettlementId, id).orderByAsc(FormalSettlementDetail::getLineNo)));
|
||||
vo.setSummaryFees(listSummaryFees(id));
|
||||
vo.setPayments(paymentMapper.selectList(Wrappers.<FormalSettlementPayment>lambdaQuery()
|
||||
.eq(FormalSettlementPayment::getFormalSettlementId, id).orderByDesc(FormalSettlementPayment::getCreateTime)));
|
||||
return vo;
|
||||
@@ -192,6 +226,9 @@ public class FormalSettlementServiceImpl extends BaseServiceImpl<FormalSettlemen
|
||||
settlement.setRemark(limit(request.getRemark(), 200));
|
||||
saveOrUpdate(settlement);
|
||||
rebuildSnapshots(settlement, sources, directDetails);
|
||||
rebuildSummaryFees(settlement.getId());
|
||||
applySummaryRequest(settlement.getId(), request.getSummaryFees());
|
||||
refreshSettlementAmount(settlement);
|
||||
return settlement.getId();
|
||||
}
|
||||
|
||||
@@ -205,6 +242,8 @@ public class FormalSettlementServiceImpl extends BaseServiceImpl<FormalSettlemen
|
||||
if (!detailIds.isEmpty()) detailFeeMapper.delete(Wrappers.<FormalSettlementDetailFee>lambdaQuery()
|
||||
.in(FormalSettlementDetailFee::getFormalSettlementDetailId, detailIds));
|
||||
detailMapper.delete(Wrappers.<FormalSettlementDetail>lambdaQuery().eq(FormalSettlementDetail::getFormalSettlementId, id));
|
||||
summaryFeeMapper.delete(Wrappers.<FormalSettlementSummaryFee>lambdaQuery()
|
||||
.eq(FormalSettlementSummaryFee::getFormalSettlementId, id));
|
||||
removeById(id);
|
||||
}
|
||||
|
||||
@@ -312,14 +351,232 @@ public class FormalSettlementServiceImpl extends BaseServiceImpl<FormalSettlemen
|
||||
detail.setAdjustAmount(detail.getSettlementAmountTax().subtract(detail.getOriginalAmount()));
|
||||
detail.setRemark(reason);
|
||||
detailMapper.updateById(detail);
|
||||
BigDecimal amount = detailMapper.selectList(Wrappers.<FormalSettlementDetail>lambdaQuery()
|
||||
.eq(FormalSettlementDetail::getFormalSettlementId, settlement.getId())).stream()
|
||||
.map(FormalSettlementDetail::getSettlementAmountTax).map(this::money).reduce(BigDecimal.ZERO, BigDecimal::add);
|
||||
rebuildSummaryFees(settlement.getId());
|
||||
refreshSettlementAmount(settlement);
|
||||
}
|
||||
|
||||
private void rebuildSummaryFees(Long settlementId) {
|
||||
List<FormalSettlementSummaryFee> existingRows = listSummaryFees(settlementId);
|
||||
Map<String, FormalSettlementSummaryFee> existingGenerated = existingRows.stream()
|
||||
.filter(row -> !Integer.valueOf(1).equals(row.getManualFlag()))
|
||||
.collect(Collectors.toMap(this::summaryKey, Function.identity(), (first, second) -> first));
|
||||
List<FormalSettlementSummaryFee> existingManualRows = existingRows.stream()
|
||||
.filter(row -> Integer.valueOf(1).equals(row.getManualFlag())).toList();
|
||||
Map<String, BigDecimal> aggregates = new LinkedHashMap<>();
|
||||
for (FormalSettlementSource source : sourceMapper.selectList(Wrappers.<FormalSettlementSource>lambdaQuery()
|
||||
.eq(FormalSettlementSource::getFormalSettlementId, settlementId))) {
|
||||
List<PreSettlementSummaryFee> sourceSummary = preSummaryFeeMapper.selectList(
|
||||
Wrappers.<PreSettlementSummaryFee>lambdaQuery()
|
||||
.eq(PreSettlementSummaryFee::getPreSettlementId, source.getPreSettlementId())
|
||||
.eq(PreSettlementSummaryFee::getIsDeleted, 0));
|
||||
sourceSummary.forEach(row -> {
|
||||
BigDecimal additionalAmount = Integer.valueOf(1).equals(row.getManualFlag())
|
||||
? money(row.getSettlementAmount()) : money(row.getAdjustAmount());
|
||||
aggregates.merge(summaryKey(row.getFeeType(), row.getFeeItem()), additionalAmount, BigDecimal::add);
|
||||
});
|
||||
}
|
||||
Map<String, String> feeTypeMap = feeTypeMap();
|
||||
for (FormalSettlementDetail detail : detailMapper.selectList(Wrappers.<FormalSettlementDetail>lambdaQuery()
|
||||
.eq(FormalSettlementDetail::getFormalSettlementId, settlementId))) {
|
||||
List<FormalSettlementDetailFee> detailFees = detailFeeMapper.selectList(
|
||||
Wrappers.<FormalSettlementDetailFee>lambdaQuery()
|
||||
.eq(FormalSettlementDetailFee::getFormalSettlementDetailId, detail.getId())
|
||||
.eq(FormalSettlementDetailFee::getIsDeleted, 0));
|
||||
appendFeeAggregates(aggregates, feeTypeMap, detailFees);
|
||||
}
|
||||
summaryFeeMapper.delete(Wrappers.<FormalSettlementSummaryFee>lambdaQuery()
|
||||
.eq(FormalSettlementSummaryFee::getFormalSettlementId, settlementId)
|
||||
.eq(FormalSettlementSummaryFee::getManualFlag, 0));
|
||||
int lineNo = 1;
|
||||
for (Map.Entry<String, BigDecimal> entry : aggregates.entrySet()) {
|
||||
String[] keyParts = entry.getKey().split("@@@", 2);
|
||||
FormalSettlementSummaryFee old = existingGenerated.get(entry.getKey());
|
||||
FormalSettlementSummaryFee row = new FormalSettlementSummaryFee();
|
||||
row.setFormalSettlementId(settlementId);
|
||||
row.setFeeType(keyParts[0]);
|
||||
row.setFeeItem(keyParts.length > 1 ? keyParts[1] : "");
|
||||
row.setOriginalAmount(money(entry.getValue()));
|
||||
row.setAdjustAmount(old == null ? BigDecimal.ZERO.setScale(2) : money(old.getAdjustAmount()));
|
||||
row.setSettlementAmount(row.getOriginalAmount().add(row.getAdjustAmount()));
|
||||
row.setRemark(old == null ? "" : old.getRemark());
|
||||
row.setManualFlag(0);
|
||||
row.setLineNo(lineNo++);
|
||||
summaryFeeMapper.insert(row);
|
||||
}
|
||||
for (FormalSettlementSummaryFee manualRow : existingManualRows) {
|
||||
manualRow.setLineNo(lineNo++);
|
||||
summaryFeeMapper.updateById(manualRow);
|
||||
}
|
||||
renumberSummaryFees(settlementId);
|
||||
}
|
||||
|
||||
private void appendFeeAggregates(Map<String, BigDecimal> aggregates, Map<String, String> feeTypeMap,
|
||||
List<FormalSettlementDetailFee> detailFees) {
|
||||
for (FormalSettlementDetailFee fee : detailFees) {
|
||||
Map<String, BigDecimal> feeItems = parseFeeItems(fee.getFeeItemsJson());
|
||||
boolean containsFreight = feeItems.keySet().stream().anyMatch(this::isFreightFeeItem);
|
||||
BigDecimal knownAmount = feeItems.values().stream().map(this::money)
|
||||
.reduce(BigDecimal.ZERO, BigDecimal::add);
|
||||
if (!containsFreight) {
|
||||
BigDecimal freightAmount = money(fee.getFreightAmount());
|
||||
aggregates.merge(summaryKey("物流配送", "运输费"), freightAmount, BigDecimal::add);
|
||||
knownAmount = knownAmount.add(freightAmount);
|
||||
}
|
||||
feeItems.forEach((feeItem, amount) -> aggregates.merge(
|
||||
summaryKey(feeTypeMap.getOrDefault(feeItem,
|
||||
isFreightFeeItem(feeItem) ? "物流配送" : "其他费用"), feeItem),
|
||||
money(amount), BigDecimal::add));
|
||||
BigDecimal residualAmount = money(fee.getSettlementAmountTax()).subtract(knownAmount);
|
||||
if (residualAmount.signum() != 0) {
|
||||
aggregates.merge(summaryKey("其他费用", "其他费用"), residualAmount, BigDecimal::add);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void applySummaryRequest(Long settlementId, List<FormalSettlementSaveRequest.SummaryFee> requestRows) {
|
||||
if (requestRows == null) return;
|
||||
Map<String, Set<String>> allowedManualFees = new LinkedHashMap<>();
|
||||
for (Map<String, Object> option : preSettlementService.feeOptions()) {
|
||||
Set<String> feeItems = new LinkedHashSet<>();
|
||||
if (option.get("feeItems") instanceof List<?> values) {
|
||||
values.forEach(value -> feeItems.add(String.valueOf(value)));
|
||||
}
|
||||
allowedManualFees.put(String.valueOf(option.get("feeType")), feeItems);
|
||||
}
|
||||
Map<Long, FormalSettlementSummaryFee> existingMap = listSummaryFees(settlementId).stream()
|
||||
.collect(Collectors.toMap(FormalSettlementSummaryFee::getId, Function.identity()));
|
||||
List<FormalSettlementSummaryFee> existingManualRows = existingMap.values().stream()
|
||||
.filter(row -> Integer.valueOf(1).equals(row.getManualFlag())).toList();
|
||||
Set<Long> retainedManualIds = new LinkedHashSet<>();
|
||||
int nextLineNo = existingMap.size() + 1;
|
||||
for (FormalSettlementSaveRequest.SummaryFee requestRow : requestRows) {
|
||||
if (Integer.valueOf(1).equals(requestRow.getManualFlag())) {
|
||||
String feeType = requiredText(requestRow.getFeeType(), "费用类型");
|
||||
String feeItem = requiredText(requestRow.getFeeItem(), "费用项");
|
||||
if (!allowedManualFees.getOrDefault(feeType, Set.of()).contains(feeItem)) {
|
||||
throw new ServiceException("费用类型与费用项不匹配或费用项已停用");
|
||||
}
|
||||
FormalSettlementSummaryFee row = requestRow.getId() == null ? null : existingMap.get(requestRow.getId());
|
||||
if (row == null && requestRow.getId() == null) row = new FormalSettlementSummaryFee();
|
||||
if (row == null || row.getId() != null && !Integer.valueOf(1).equals(row.getManualFlag())) {
|
||||
throw new ServiceException("存在无效的手工费用行");
|
||||
}
|
||||
row.setFormalSettlementId(settlementId);
|
||||
row.setFeeType(feeType);
|
||||
row.setFeeItem(feeItem);
|
||||
row.setOriginalAmount(BigDecimal.ZERO.setScale(2));
|
||||
row.setAdjustAmount(money(requestRow.getAdjustAmount()));
|
||||
row.setSettlementAmount(row.getAdjustAmount());
|
||||
row.setRemark(limit(requestRow.getRemark(), 50));
|
||||
row.setManualFlag(1);
|
||||
if (row.getId() == null) {
|
||||
row.setLineNo(nextLineNo++);
|
||||
summaryFeeMapper.insert(row);
|
||||
} else {
|
||||
summaryFeeMapper.updateById(row);
|
||||
}
|
||||
retainedManualIds.add(row.getId());
|
||||
continue;
|
||||
}
|
||||
FormalSettlementSummaryFee row = existingMap.get(requestRow.getId());
|
||||
if (row == null) {
|
||||
row = existingMap.values().stream()
|
||||
.filter(item -> !Integer.valueOf(1).equals(item.getManualFlag()))
|
||||
.filter(item -> Objects.equals(summaryKey(item),
|
||||
summaryKey(requestRow.getFeeType(), requestRow.getFeeItem())))
|
||||
.findFirst().orElse(null);
|
||||
}
|
||||
if (row == null || Integer.valueOf(1).equals(row.getManualFlag())) {
|
||||
throw new ServiceException("存在无效的结算合计行");
|
||||
}
|
||||
row.setAdjustAmount(money(requestRow.getAdjustAmount()));
|
||||
row.setSettlementAmount(money(row.getOriginalAmount()).add(row.getAdjustAmount()));
|
||||
row.setRemark(limit(requestRow.getRemark(), 50));
|
||||
summaryFeeMapper.updateById(row);
|
||||
}
|
||||
for (FormalSettlementSummaryFee manualRow : existingManualRows) {
|
||||
if (!retainedManualIds.contains(manualRow.getId())) summaryFeeMapper.deleteById(manualRow.getId());
|
||||
}
|
||||
renumberSummaryFees(settlementId);
|
||||
}
|
||||
|
||||
private void refreshSettlementAmount(FormalSettlement settlement) {
|
||||
BigDecimal amount = listSummaryFees(settlement.getId()).stream()
|
||||
.map(FormalSettlementSummaryFee::getSettlementAmount).map(this::money)
|
||||
.reduce(BigDecimal.ZERO, BigDecimal::add);
|
||||
settlement.setSettlementAmount(amount);
|
||||
settlement.setLocalSettlementAmount(amount.multiply(settlement.getExchangeRate() == null ? BigDecimal.ONE : settlement.getExchangeRate()));
|
||||
settlement.setLocalSettlementAmount(amount.multiply(
|
||||
settlement.getExchangeRate() == null ? BigDecimal.ONE : settlement.getExchangeRate()));
|
||||
updateById(settlement);
|
||||
}
|
||||
|
||||
private List<FormalSettlementSummaryFee> listSummaryFees(Long settlementId) {
|
||||
return summaryFeeMapper.selectList(Wrappers.<FormalSettlementSummaryFee>lambdaQuery()
|
||||
.eq(FormalSettlementSummaryFee::getFormalSettlementId, settlementId)
|
||||
.eq(FormalSettlementSummaryFee::getIsDeleted, 0)
|
||||
.orderByAsc(FormalSettlementSummaryFee::getLineNo));
|
||||
}
|
||||
|
||||
private void renumberSummaryFees(Long settlementId) {
|
||||
List<FormalSettlementSummaryFee> rows = listSummaryFees(settlementId);
|
||||
for (int index = 0; index < rows.size(); index++) {
|
||||
FormalSettlementSummaryFee row = rows.get(index);
|
||||
row.setLineNo(index + 1);
|
||||
summaryFeeMapper.updateById(row);
|
||||
}
|
||||
}
|
||||
|
||||
private Map<String, String> feeTypeMap() {
|
||||
Map<String, String> result = new LinkedHashMap<>();
|
||||
for (Map<String, Object> option : preSettlementService.feeOptions()) {
|
||||
if (option.get("feeItems") instanceof List<?> values) {
|
||||
values.forEach(value -> result.putIfAbsent(String.valueOf(value),
|
||||
String.valueOf(option.get("feeType"))));
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private Map<String, BigDecimal> parseFeeItems(String json) {
|
||||
Map<String, BigDecimal> result = new LinkedHashMap<>();
|
||||
if (Func.isEmpty(json)) return result;
|
||||
try {
|
||||
Object parsed = JsonUtil.parse(json, Map.class);
|
||||
if (parsed instanceof Map<?, ?> map) {
|
||||
map.forEach((key, value) -> result.put(String.valueOf(key), decimal(value)));
|
||||
}
|
||||
} catch (RuntimeException ignored) {
|
||||
// 兼容历史费用JSON,不影响正式结算保存。
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private BigDecimal decimal(Object value) {
|
||||
if (value == null || String.valueOf(value).isBlank()) return BigDecimal.ZERO;
|
||||
try {
|
||||
return new BigDecimal(String.valueOf(value));
|
||||
} catch (NumberFormatException ignored) {
|
||||
return BigDecimal.ZERO;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isFreightFeeItem(String name) {
|
||||
return name != null && (name.contains("运费") || name.contains("运输费"));
|
||||
}
|
||||
|
||||
private String summaryKey(FormalSettlementSummaryFee row) {
|
||||
return summaryKey(row.getFeeType(), row.getFeeItem());
|
||||
}
|
||||
|
||||
private String summaryKey(String feeType, String feeItem) {
|
||||
return String.valueOf(feeType) + "@@@" + String.valueOf(feeItem);
|
||||
}
|
||||
|
||||
private String requiredText(String value, String field) {
|
||||
if (Func.isEmpty(value)) throw new ServiceException(field + "不能为空");
|
||||
return value.trim();
|
||||
}
|
||||
|
||||
private void rebuildSnapshots(FormalSettlement settlement, List<PreSettlement> sources, List<ReceivablePayableDetail> directDetails) {
|
||||
List<Long> existingDetailIds = detailMapper.selectList(Wrappers.<FormalSettlementDetail>lambdaQuery()
|
||||
.eq(FormalSettlementDetail::getFormalSettlementId, settlement.getId())).stream().map(FormalSettlementDetail::getId).toList();
|
||||
@@ -490,12 +747,6 @@ public class FormalSettlementServiceImpl extends BaseServiceImpl<FormalSettlemen
|
||||
target.setCurrency(Func.isEmpty(source.getCurrency()) ? "RMB" : source.getCurrency()); target.setLocalCurrency("RMB");
|
||||
}
|
||||
|
||||
private synchronized String nextNo() {
|
||||
String prefix = "JS" + LocalDate.now().format(DateTimeFormatter.BASIC_ISO_DATE);
|
||||
long count = count(Wrappers.<FormalSettlement>lambdaQuery().likeRight(FormalSettlement::getFormalSettlementNo, prefix));
|
||||
return prefix + String.format("%04d", count + 1);
|
||||
}
|
||||
|
||||
private synchronized String nextPaymentNo() {
|
||||
String prefix = "FK" + LocalDate.now().format(DateTimeFormatter.BASIC_ISO_DATE);
|
||||
long count = paymentMapper.selectCount(Wrappers.<FormalSettlementPayment>lambdaQuery()
|
||||
@@ -503,7 +754,7 @@ public class FormalSettlementServiceImpl extends BaseServiceImpl<FormalSettlemen
|
||||
return prefix + String.format("%04d", count + 1);
|
||||
}
|
||||
|
||||
private BigDecimal money(BigDecimal value) { return value == null ? BigDecimal.ZERO : value; }
|
||||
private BigDecimal money(BigDecimal value) { return (value == null ? BigDecimal.ZERO : value).setScale(2, RoundingMode.HALF_UP); }
|
||||
private BigDecimal nonNegative(BigDecimal value, String field) { if (value == null || value.signum() < 0) throw new ServiceException(field + "不能小于0"); return value; }
|
||||
private BigDecimal positive(BigDecimal value, String field) { if (value == null || value.signum() <= 0) throw new ServiceException(field + "必须大于0"); return value; }
|
||||
private String required(String value, String field) { if (Func.isEmpty(value)) throw new ServiceException("请填写" + field); return value; }
|
||||
|
||||
+51
-12
@@ -174,11 +174,12 @@ public class PreSettlementServiceImpl extends BaseServiceImpl<PreSettlementMappe
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Map<String, Object>> contractOptions(String keyword) {
|
||||
public List<Map<String, Object>> contractOptions(String keyword, Long projectId) {
|
||||
LambdaQueryWrapper<ContractManage> wrapper = Wrappers.<ContractManage>lambdaQuery()
|
||||
.eq(ContractManage::getIsDeleted, 0)
|
||||
.in(ContractManage::getApprovalStatus, "approved", "change_approved")
|
||||
.ne(ContractManage::getContractStage, "terminated")
|
||||
.eq(projectId != null, ContractManage::getProjectId, projectId)
|
||||
.and(Func.isNotEmpty(keyword), query -> query.like(ContractManage::getContractName, keyword)
|
||||
.or().like(ContractManage::getContractNo, keyword))
|
||||
.orderByDesc(ContractManage::getCreateTime);
|
||||
@@ -201,12 +202,28 @@ public class PreSettlementServiceImpl extends BaseServiceImpl<PreSettlementMappe
|
||||
@Override
|
||||
public IPage<Map<String, Object>> candidateDetails(IPage<?> page, Long contractId, String settlementType,
|
||||
String batchNo, String feeStartDate, String feeEndDate) {
|
||||
return candidateDetails(page, contractId, settlementType, batchNo, feeStartDate, feeEndDate,
|
||||
false, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public IPage<Map<String, Object>> candidateDetailsByCreateTime(IPage<?> page, Long contractId,
|
||||
String settlementType, String batchNo, String createStartDate, String createEndDate) {
|
||||
return candidateDetails(page, contractId, settlementType, batchNo, createStartDate, createEndDate,
|
||||
true, false);
|
||||
}
|
||||
|
||||
private IPage<Map<String, Object>> candidateDetails(IPage<?> page, Long contractId, String settlementType,
|
||||
String batchNo, String startDate, String endDate, boolean byCreateTime,
|
||||
boolean validateContractType) {
|
||||
if (contractId == null) {
|
||||
throw new ServiceException("请先选择合同");
|
||||
}
|
||||
validateSettlementType(settlementType);
|
||||
ContractManage contract = loadAvailableContract(contractId);
|
||||
if (!Objects.equals(contractSettlementType(contract), settlementType)) {
|
||||
// 正式结算需兼容历史单据及预结算转正式结算时保留的结算类型,
|
||||
// 候选数据仍由合同、项目、组织、结算类型及未结算状态共同约束。
|
||||
if (validateContractType && !Objects.equals(contractSettlementType(contract), settlementType)) {
|
||||
throw new ServiceException("结算类型与合同类别不一致");
|
||||
}
|
||||
LambdaQueryWrapper<ReceivablePayableDetail> wrapper = Wrappers.<ReceivablePayableDetail>lambdaQuery()
|
||||
@@ -223,8 +240,14 @@ public class PreSettlementServiceImpl extends BaseServiceImpl<PreSettlementMappe
|
||||
.and(query -> query.eq(ReceivablePayableDetail::getCustomerName, contract.getPartyA())
|
||||
.or().eq(ReceivablePayableDetail::getCustomerName, contract.getPartyB()))
|
||||
.like(Func.isNotEmpty(batchNo), ReceivablePayableDetail::getBatchNo, batchNo)
|
||||
.ge(Func.isNotEmpty(feeStartDate), ReceivablePayableDetail::getFeeDate, parseDate(feeStartDate))
|
||||
.le(Func.isNotEmpty(feeEndDate), ReceivablePayableDetail::getFeeDate, parseDate(feeEndDate))
|
||||
.ge(!byCreateTime && Func.isNotEmpty(startDate), ReceivablePayableDetail::getFeeDate,
|
||||
parseDate(startDate))
|
||||
.le(!byCreateTime && Func.isNotEmpty(endDate), ReceivablePayableDetail::getFeeDate,
|
||||
parseDate(endDate))
|
||||
.ge(byCreateTime && Func.isNotEmpty(startDate), ReceivablePayableDetail::getCreateTime,
|
||||
byCreateTime && Func.isNotEmpty(startDate) ? parseDate(startDate).atStartOfDay() : null)
|
||||
.lt(byCreateTime && Func.isNotEmpty(endDate), ReceivablePayableDetail::getCreateTime,
|
||||
byCreateTime && Func.isNotEmpty(endDate) ? parseDate(endDate).plusDays(1).atStartOfDay() : null)
|
||||
.orderByDesc(ReceivablePayableDetail::getCreateTime);
|
||||
IPage<ReceivablePayableDetail> sourcePage = sourceDetailMapper.selectPage(
|
||||
new Page<>(page.getCurrent(), page.getSize()), wrapper);
|
||||
@@ -613,30 +636,46 @@ public class PreSettlementServiceImpl extends BaseServiceImpl<PreSettlementMappe
|
||||
|
||||
private Map<String, Object> candidateMap(ReceivablePayableDetail source) {
|
||||
Map<String, Object> result = new LinkedHashMap<>();
|
||||
Waybill waybill = source.getWaybillId() == null ? null : waybillService.getById(source.getWaybillId());
|
||||
result.put("id", source.getId());
|
||||
result.put("documentNo", source.getDocumentNo());
|
||||
result.put("createTime", source.getCreateTime());
|
||||
result.put("projectName", source.getProjectName());
|
||||
result.put("deptName", source.getDeptName());
|
||||
result.put("feeDate", source.getFeeDate());
|
||||
result.put("customerName", source.getCustomerName());
|
||||
result.put("departureAddress", waybillValue(source.getWaybillId(), Waybill::getDepartureAddress));
|
||||
result.put("arrivalAddress", waybillValue(source.getWaybillId(), Waybill::getArrivalAddress));
|
||||
result.put("contractNo", source.getContractNo());
|
||||
result.put("contractName", source.getContractName());
|
||||
result.put("sourceType", source.getSourceType());
|
||||
result.put("preSettlementNo", source.getPreSettlementNo());
|
||||
result.put("formalSettlementNo", source.getFormalSettlementNo());
|
||||
result.put("waybillNo", source.getWaybillNo());
|
||||
result.put("vehicleNo", source.getVehicleNo());
|
||||
result.put("departureAddress", waybill == null ? "" :
|
||||
firstNotEmpty(waybill.getDepartureAddress(), waybill.getDepartureName()));
|
||||
result.put("arrivalAddress", waybill == null ? "" :
|
||||
firstNotEmpty(waybill.getArrivalAddress(), waybill.getArrivalName()));
|
||||
result.put("actualDepartureTime", waybill == null || waybill.getStartDate() == null ? null :
|
||||
waybill.getStartDate().atStartOfDay());
|
||||
result.put("actualCompletionTime", waybill == null || waybill.getEndDate() == null ? null :
|
||||
waybill.getEndDate().atStartOfDay());
|
||||
result.put("transportType", source.getTransportType());
|
||||
result.put("cargoName", source.getCargoName());
|
||||
result.put("cargoType", source.getCargoType());
|
||||
result.put("transportQuantity", source.getTransportQuantity());
|
||||
result.put("quantityUnit", source.getQuantityUnit());
|
||||
result.put("mileage", source.getMileage());
|
||||
result.put("batchNo", source.getBatchNo());
|
||||
result.put("unitPrice", source.getUnitPrice());
|
||||
result.put("freightAmount", money(source.getFreightAmount()));
|
||||
result.put("feeItemsJson", source.getFeeItemsJson());
|
||||
result.put("totalAmount", money(source.getTotalAmount()));
|
||||
result.put("currency", source.getCurrency());
|
||||
result.put("settlementStatusName", "待结算");
|
||||
result.put("remark", source.getRemark());
|
||||
return result;
|
||||
}
|
||||
|
||||
private String waybillValue(Long waybillId, Function<Waybill, String> getter) {
|
||||
if (waybillId == null) return "";
|
||||
Waybill waybill = waybillService.getById(waybillId);
|
||||
return waybill == null ? "" : getter.apply(waybill);
|
||||
}
|
||||
|
||||
private void synchronizeDetails(PreSettlement settlement, List<Long> requestedIds, boolean allowSourceMismatch) {
|
||||
List<Long> distinctIds = requestedIds.stream().filter(Objects::nonNull).distinct().toList();
|
||||
List<PreSettlementDetail> existingDetails = listDetails(settlement.getId());
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
ALTER TABLE `blade_common_route`
|
||||
ADD COLUMN `departure_province_id` varchar(32) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '发货省ID' AFTER `departure_name`,
|
||||
ADD COLUMN `departure_city_id` varchar(32) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '发货市ID' AFTER `departure_province_id`,
|
||||
ADD COLUMN `departure_district_id` varchar(32) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '发货区ID' AFTER `departure_city_id`,
|
||||
ADD COLUMN `arrival_province_id` varchar(32) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '收货省ID' AFTER `arrival_name`,
|
||||
ADD COLUMN `arrival_city_id` varchar(32) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '收货市ID' AFTER `arrival_province_id`,
|
||||
ADD COLUMN `arrival_district_id` varchar(32) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '收货区ID' AFTER `arrival_city_id`;
|
||||
@@ -62,6 +62,22 @@ CREATE TABLE IF NOT EXISTS `blade_formal_settlement_detail_fee` (
|
||||
KEY `idx_formal_detail_fee_detail` (`formal_settlement_detail_id`), KEY `idx_formal_detail_fee_source` (`source_fee_id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='正式结算货物费用快照';
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `blade_formal_settlement_summary_fee` (
|
||||
`id` bigint(20) NOT NULL COMMENT '主键', `tenant_id` varchar(12) COLLATE utf8mb4_general_ci NOT NULL DEFAULT '000000' COMMENT '租户ID',
|
||||
`create_user` bigint(20) DEFAULT NULL COMMENT '创建人', `create_dept` bigint(20) DEFAULT NULL COMMENT '创建部门',
|
||||
`create_time` datetime DEFAULT NULL COMMENT '创建时间', `update_user` bigint(20) DEFAULT NULL COMMENT '修改人',
|
||||
`update_time` datetime DEFAULT NULL COMMENT '修改时间', `status` int(11) DEFAULT '1' COMMENT '状态',
|
||||
`is_deleted` int(11) DEFAULT '0' COMMENT '是否已删除', `formal_settlement_id` bigint(20) NOT NULL COMMENT '正式结算单ID',
|
||||
`line_no` int(11) NOT NULL COMMENT '行号', `fee_type` varchar(100) COLLATE utf8mb4_general_ci NOT NULL COMMENT '费用类型',
|
||||
`fee_item` varchar(100) COLLATE utf8mb4_general_ci NOT NULL COMMENT '费用项',
|
||||
`original_amount` decimal(18,2) NOT NULL DEFAULT '0.00' COMMENT '原金额',
|
||||
`adjust_amount` decimal(18,2) NOT NULL DEFAULT '0.00' COMMENT '调整金额',
|
||||
`settlement_amount` decimal(18,2) NOT NULL DEFAULT '0.00' COMMENT '结算金额',
|
||||
`remark` varchar(50) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '备注',
|
||||
`manual_flag` int(11) NOT NULL DEFAULT '0' COMMENT '是否手工添加', PRIMARY KEY (`id`) USING BTREE,
|
||||
KEY `idx_formal_settlement_summary_bill` (`formal_settlement_id`) USING BTREE
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='正式结算合计费用';
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `blade_formal_settlement_payment` (
|
||||
`id` bigint(20) NOT NULL, `tenant_id` varchar(12) NOT NULL DEFAULT '000000', `create_user` bigint(20) DEFAULT NULL,
|
||||
`create_dept` bigint(20) DEFAULT NULL, `create_time` datetime DEFAULT NULL, `update_user` bigint(20) DEFAULT NULL,
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
-- 正式结算新增结算合计费用表
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `blade_formal_settlement_summary_fee` (
|
||||
`id` bigint(20) NOT NULL COMMENT '主键',
|
||||
`tenant_id` varchar(12) COLLATE utf8mb4_general_ci NOT NULL DEFAULT '000000' COMMENT '租户ID',
|
||||
`create_user` bigint(20) DEFAULT NULL COMMENT '创建人',
|
||||
`create_dept` bigint(20) DEFAULT NULL COMMENT '创建部门',
|
||||
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
|
||||
`update_user` bigint(20) DEFAULT NULL COMMENT '修改人',
|
||||
`update_time` datetime DEFAULT NULL COMMENT '修改时间',
|
||||
`status` int(11) DEFAULT '1' COMMENT '状态',
|
||||
`is_deleted` int(11) DEFAULT '0' COMMENT '是否已删除',
|
||||
`formal_settlement_id` bigint(20) NOT NULL COMMENT '正式结算单ID',
|
||||
`line_no` int(11) NOT NULL COMMENT '行号',
|
||||
`fee_type` varchar(100) COLLATE utf8mb4_general_ci NOT NULL COMMENT '费用类型',
|
||||
`fee_item` varchar(100) COLLATE utf8mb4_general_ci NOT NULL COMMENT '费用项',
|
||||
`original_amount` decimal(18,2) NOT NULL DEFAULT '0.00' COMMENT '原金额',
|
||||
`adjust_amount` decimal(18,2) NOT NULL DEFAULT '0.00' COMMENT '调整金额',
|
||||
`settlement_amount` decimal(18,2) NOT NULL DEFAULT '0.00' COMMENT '结算金额',
|
||||
`remark` varchar(50) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '备注',
|
||||
`manual_flag` int(11) NOT NULL DEFAULT '0' COMMENT '是否手工添加',
|
||||
PRIMARY KEY (`id`) USING BTREE,
|
||||
KEY `idx_formal_settlement_summary_bill` (`formal_settlement_id`) USING BTREE
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='正式结算合计费用';
|
||||
@@ -18,6 +18,9 @@ CREATE TABLE `blade_common_route` (
|
||||
`route_name` varchar(100) DEFAULT NULL COMMENT '线路名称',
|
||||
`departure_address_id` bigint(20) DEFAULT NULL COMMENT '发货地址ID',
|
||||
`departure_name` varchar(100) DEFAULT NULL COMMENT '发货地',
|
||||
`departure_province_id` varchar(32) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '发货省ID',
|
||||
`departure_city_id` varchar(32) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '发货市ID',
|
||||
`departure_district_id` varchar(32) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '发货区ID',
|
||||
`departure_address` varchar(255) DEFAULT NULL COMMENT '发货地址',
|
||||
`departure_longitude` decimal(18,6) DEFAULT NULL COMMENT '发货经度',
|
||||
`departure_latitude` decimal(18,6) DEFAULT NULL COMMENT '发货纬度',
|
||||
@@ -25,6 +28,9 @@ CREATE TABLE `blade_common_route` (
|
||||
`departure_phone` varchar(100) DEFAULT NULL COMMENT '发货联系方式',
|
||||
`arrival_address_id` bigint(20) DEFAULT NULL COMMENT '收货地址ID',
|
||||
`arrival_name` varchar(100) DEFAULT NULL COMMENT '收货地',
|
||||
`arrival_province_id` varchar(32) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '收货省ID',
|
||||
`arrival_city_id` varchar(32) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '收货市ID',
|
||||
`arrival_district_id` varchar(32) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '收货区ID',
|
||||
`arrival_address` varchar(255) DEFAULT NULL COMMENT '收货地址',
|
||||
`arrival_longitude` decimal(18,6) DEFAULT NULL COMMENT '收货经度',
|
||||
`arrival_latitude` decimal(18,6) DEFAULT NULL COMMENT '收货纬度',
|
||||
|
||||
Reference in New Issue
Block a user