platformx-boot/src/main/resources/application-dev.yml
@@ -37,3 +37,7 @@ # swagger 配置 swagger: token-url: ${swagger.gateway}/admin/oauth2/token #bip 配置 bip: url: platformx-business-finance-api/src/main/java/com/by4cloud/platformx/business/dto/ContractPaymentScheduleProcessAddDTO.java
@@ -2,21 +2,27 @@ import com.fasterxml.jackson.annotation.JsonFormat; import io.swagger.v3.oas.annotations.media.Schema; import jakarta.persistence.Column; import lombok.Data; import java.util.Date; import java.util.List; @Data public class ContractPaymentScheduleProcessAddDTO { @Schema(description = "阶段ID") @Column(columnDefinition = "bigint comment '阶段ID'") private Long scheduleId; @Schema(description = "履约时间") @JsonFormat(pattern = "yyyy-MM-dd") @Column(columnDefinition = "date comment '履约时间'") private Date processDate; @Schema(description = "履约单据名称") private String outBoundAttNames; @Schema(description = "履约单据路径") private String outBoundAttPaths; private List<Long> contractOutBoundIds; } platformx-business-finance-api/src/main/java/com/by4cloud/platformx/business/dto/CreditSalesQueryDTO.java
New file @@ -0,0 +1,17 @@ package com.by4cloud.platformx.business.dto; import lombok.Data; @Data public class CreditSalesQueryDTO { private String contractName; private String partyA; private String productNames; private String sortFiled; private String sortMethod; } platformx-business-finance-api/src/main/java/com/by4cloud/platformx/business/entity/Contract.java
@@ -147,6 +147,14 @@ @Column(columnDefinition = "bigint comment '模版ID'") private Long templateId; @Schema(description = "销售模式") @Column(columnDefinition = "VARCHAR(16) comment '销售模式 1 按单生产 2 先产后销 3 代储代销'") private String salesModel; @Schema(description = "已付款金额") @Column(columnDefinition = "decimal(10,2) comment '已付款金额'") private BigDecimal paidAmount; /** * 临时字段 - 用于接收审批人名称等关联查询结果 */ platformx-business-finance-api/src/main/java/com/by4cloud/platformx/business/entity/ContractOutBound.java
@@ -61,4 +61,18 @@ @Schema(description = "单据路径") @Column(columnDefinition="text comment '单据路径'") private String outBoundAttPaths; @Schema(description = "到货时间") @Column(columnDefinition="datetime comment '到货时间'") @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") private Date arrivalTime; @Schema(description = "到货单据名称") @Column(columnDefinition="text comment '到货单据名称'") private String arrivalAttNames; @Schema(description = "到货单据路径") @Column(columnDefinition="text comment '到货单据路径'") private String arrivalAttPaths; } platformx-business-finance-api/src/main/java/com/by4cloud/platformx/business/entity/PaymentOffset.java
New file @@ -0,0 +1,82 @@ package com.by4cloud.platformx.business.entity; import com.by4cloud.platformx.common.data.mybatis.BaseModel; import com.fasterxml.jackson.annotation.JsonFormat; import io.swagger.v3.oas.annotations.media.Schema; import jakarta.persistence.Column; import jakarta.persistence.Entity; import lombok.Data; import org.hibernate.annotations.Table; import org.springframework.format.annotation.DateTimeFormat; import java.math.BigDecimal; import java.util.Date; /** * 2026年4月29日 10:46:07 * syt */ @Data @Entity//加了才能自动生成表 @Table(appliesTo="payment_offset",comment = "抵抹账")//给表加注释 @jakarta.persistence.Table(name = "payment_offset")//数据库创建的表明 public class PaymentOffset extends BaseModel<PaymentOffset> { @Schema(description = "客商名称") @Column(columnDefinition="VARCHAR(64) comment '客商名称'") private String busGuestName; @Schema(description = "客商ID") @Column(columnDefinition="bigint comment '客商ID'") private Long busGuestId; @Schema(description = "合同名称") @Column(columnDefinition="VARCHAR(64) comment '合同名称'") private String contractName; @Schema(description = "合同ID") @Column(columnDefinition="bigint comment '合同ID'") private Long contractId; @Schema(description = "合同编号") @Column(columnDefinition = "VARCHAR(64) comment '合同编号'") private String contractNo; @Schema(description = "抵抹账时间") @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") @Column(columnDefinition="datetime comment '抵抹账时间'") private Date offsetTime; @Schema(description = "合同金额") @Column(columnDefinition="decimal(10,2) comment '合同金额 /元 两位小数'") private BigDecimal contractAmount; @Schema(description = "开票金额") @Column(columnDefinition="decimal(10,2) comment '未付金额 /元 两位小数'") private BigDecimal invoiceAmount; @Schema(description = "付款金额") @Column(columnDefinition="decimal(10,2) comment '付款金额 /元 两位小数'") private BigDecimal paidAmount; @Schema(description = "未付金额") @Column(columnDefinition="decimal(10,2) comment '未付金额 /元 两位小数'") private BigDecimal unpaidAmount; @Schema(description = "可抵抹金额") @Column(columnDefinition="decimal(10,2) comment '可抵抹金额 /元 两位小数'") private BigDecimal wipeOffAmount; @Schema(description = "抵抹金额") @Column(columnDefinition="decimal(10,2) comment '抵抹金额 /元 两位小数'") private BigDecimal offsetAmount; @Schema(description = "协议名称") @Column(columnDefinition="text comment '协议名称'") private String offsetAttNames; @Schema(description = "协议路径") @Column(columnDefinition="text comment '协议路径'") private String offsetAttPaths; } platformx-business-finance-api/src/main/java/com/by4cloud/platformx/business/vo/ContractCreditSalesPageVo.java
New file @@ -0,0 +1,97 @@ package com.by4cloud.platformx.business.vo; import com.by4cloud.platformx.business.entity.ContractPaymentSchedule; import com.by4cloud.platformx.business.entity.ContractSubjectMatter; import com.fasterxml.jackson.annotation.JsonFormat; import io.swagger.v3.oas.annotations.media.Schema; import jakarta.persistence.Column; import lombok.Data; import org.springframework.format.annotation.DateTimeFormat; import java.math.BigDecimal; import java.util.List; @Data public class ContractCreditSalesPageVo { private Long id; @Schema(description = "合同名称") private String contractName; @Schema(description = "甲方id") private Long partyAId; @Schema(description = "甲方名称") private String partyA; @Schema(description = "乙方id") private Long partyBId; @Schema(description = "乙方名称") private String partyB; @Schema(description = "合同金额") private Double amount; @Schema(description = "币种(CNY/USD等)") private String currency; @Schema(description = "合同类型(0-生成式 1-备案式)") private Integer contractType; @Schema(description = "供应属性 0-成品 1-备件 2-大修 3-其他") private Integer supplyAttribute; @Schema(description = "合同状态(0-草稿 1-已生效 2-已终止 3-已过期)") private Integer contractStatus; @Schema(description = "合同服务属性(0-产品销售 1-无形服务)") private Integer contractAttribute; @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm") @JsonFormat(pattern = "yyyy-MM-dd HH:mm") @Schema(description = "签署日期") private String signDate; @Schema(description = "交付周期") private Integer deliveryCycle; @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm") @JsonFormat(pattern = "yyyy-MM-dd HH:mm") @Schema(description = "生效日期") private String effectiveDate; @DateTimeFormat(pattern = "yyyy-MM-dd") @JsonFormat(pattern = "yyyy-MM-dd") @Schema(description = "到期日期") private String expirationDate; @Schema(description = "合同附件URL") private String attachmentUrl; @Schema(description = "备注") private String remark; @Schema(description = "模版ID") private Long templateId; @Schema(description = "已出库金额") private BigDecimal outBoundAmount; @Schema(description = "已开票金额") private BigDecimal billingAmout; @Schema(description = "赊销金额") private BigDecimal creditAmount; @Schema(description = "赊销产品") private String productNames; @Schema(description = "合同编号") private String contractNo; private List<ContractPaymentSchedule> contractPaymentSchedule; private List<ContractSubjectMatter> contractSubjectMatter; } platformx-business-finance-biz/src/main/java/com/by4cloud/platformx/business/controller/ContractController.java
@@ -26,6 +26,7 @@ import lombok.RequiredArgsConstructor; import org.springframework.web.bind.annotation.*; import java.math.BigDecimal; import java.util.List; import java.util.Objects; @@ -150,5 +151,27 @@ return contractService.genCurrentOverdue(); } /** * 生成新合同 * @param id id * @return R */ @Operation(summary = "通过id生成新合同" , description = "通过id生成新合同" ) @GetMapping("/copyNewContract/{id}" ) public R copyNewContract(@PathVariable("id" ) Long id) { return contractService.copyNewContract(id); } /** * 根据客商查询合同 * @param busId id * @return R */ @Operation(summary = "根据客商查询合同" , description = "根据客商查询合同" ) @GetMapping("/listByBusId/{busId}" ) public R listByBusId(@PathVariable("busId" ) Long busId) { return R.ok(contractService.listByScope(Wrappers.<Contract>lambdaQuery().eq(Contract::getPartyAId,busId) .gt(Contract::getBillingAmout,new BigDecimal("0")))); } } platformx-business-finance-biz/src/main/java/com/by4cloud/platformx/business/controller/ContractOutBoundController.java
@@ -121,4 +121,16 @@ public List<ContractOutBound> export(ContractOutBound contractOutBound,Long[] ids) { return contractOutBoundService.list(Wrappers.lambdaQuery(contractOutBound).in(ArrayUtil.isNotEmpty(ids), ContractOutBound::getId, ids)); } /** * 历史出库 * @param contractId 分页对象 * @return */ @GetMapping("/list/{contractId}" ) public R getContractOutBoundPage(@PathVariable("contractId") Long contractId) { return R.ok(contractOutBoundService.list(Wrappers.<ContractOutBound>lambdaQuery().eq(ContractOutBound::getContractId,contractId) .orderByAsc(ContractOutBound::getCreateTime))); } } platformx-business-finance-biz/src/main/java/com/by4cloud/platformx/business/controller/CreditSalesController.java
New file @@ -0,0 +1,61 @@ package com.by4cloud.platformx.business.controller; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.util.ArrayUtil; import cn.hutool.core.util.ObjUtil; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.toolkit.Wrappers; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.by4cloud.platformx.business.dto.ContractAddDTO; import com.by4cloud.platformx.business.dto.ContractUpdateDTO; import com.by4cloud.platformx.business.dto.CreditSalesQueryDTO; import com.by4cloud.platformx.business.entity.Contract; import com.by4cloud.platformx.business.service.ContractService; import com.by4cloud.platformx.business.service.CreditSalesService; import com.by4cloud.platformx.common.core.util.R; import com.by4cloud.platformx.common.data.mybatis.BaseModel; import com.by4cloud.platformx.common.excel.annotation.ResponseExcel; import com.by4cloud.platformx.common.log.annotation.SysLog; import com.by4cloud.platformx.common.security.annotation.Inner; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.security.SecurityRequirement; import io.swagger.v3.oas.annotations.tags.Tag; import lombok.RequiredArgsConstructor; import org.apache.commons.lang3.StringUtils; import org.springdoc.core.annotations.ParameterObject; import org.springframework.http.HttpHeaders; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.web.bind.annotation.*; import java.math.BigDecimal; import java.util.List; /** * 合同管理 * * @author platformx * @date 2026-04-29 16:46:26 */ @RestController @RequiredArgsConstructor @RequestMapping("/creditSales" ) @Tag(description = "creditSales" , name = "赊销" ) @SecurityRequirement(name = HttpHeaders.AUTHORIZATION) public class CreditSalesController { private final CreditSalesService creditSalesService; /** * 分页查询 * @param page 分页对象 * @param queryDTO * @return */ @Operation(summary = "分页查询" , description = "分页查询" ) @GetMapping("/page" ) @PreAuthorize("@pms.hasPermission('business_contract_view')" ) public R page(@ParameterObject Page page, @ParameterObject CreditSalesQueryDTO queryDTO) { return R.ok(creditSalesService.page(page, queryDTO)); } } platformx-business-finance-biz/src/main/java/com/by4cloud/platformx/business/controller/PaymentConfirmController.java
@@ -122,4 +122,12 @@ public List<PaymentConfirm> export(PaymentConfirm paymentConfirm,Long[] ids) { return paymentConfirmService.list(Wrappers.lambdaQuery(paymentConfirm).in(ArrayUtil.isNotEmpty(ids), PaymentConfirm::getId, ids)); } /** * 定时查询收款单 */ @GetMapping("syncPaymentRecepit") public R syncPaymentRecepit(){ return paymentConfirmService.syncPaymentRecepit(); } } platformx-business-finance-biz/src/main/java/com/by4cloud/platformx/business/controller/PaymentOffsetController.java
New file @@ -0,0 +1,123 @@ package com.by4cloud.platformx.business.controller; import cn.hutool.core.util.StrUtil; import cn.hutool.core.util.ArrayUtil; import cn.hutool.core.collection.CollUtil; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.toolkit.Wrappers; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.by4cloud.platformx.common.core.util.R; import com.by4cloud.platformx.common.log.annotation.SysLog; import com.by4cloud.platformx.business.entity.PaymentOffset; import com.by4cloud.platformx.business.service.PaymentOffsetService; import org.springframework.security.access.prepost.PreAuthorize; import com.by4cloud.platformx.common.excel.annotation.ResponseExcel; import io.swagger.v3.oas.annotations.security.SecurityRequirement; import org.springdoc.core.annotations.ParameterObject; import org.springframework.http.HttpHeaders; import io.swagger.v3.oas.annotations.tags.Tag; import io.swagger.v3.oas.annotations.Operation; import lombok.RequiredArgsConstructor; import org.springframework.web.bind.annotation.*; import java.util.List; import java.util.Objects; /** * 抵抹账 * * @author syt * @date 2026-05-19 10:38:26 */ @RestController @RequiredArgsConstructor @RequestMapping("/paymentOffset" ) @Tag(description = "paymentOffset" , name = "抵抹账管理" ) @SecurityRequirement(name = HttpHeaders.AUTHORIZATION) public class PaymentOffsetController { private final PaymentOffsetService paymentOffsetService; /** * 分页查询 * @param page 分页对象 * @param paymentOffset 抵抹账 * @return */ @Operation(summary = "分页查询" , description = "分页查询" ) @GetMapping("/page" ) @PreAuthorize("@pms.hasPermission('business_paymentOffset_view')" ) public R getPaymentOffsetPage(@ParameterObject Page page, @ParameterObject PaymentOffset paymentOffset) { LambdaQueryWrapper<PaymentOffset> wrapper = Wrappers.lambdaQuery(); wrapper.like(StrUtil.isNotBlank(paymentOffset.getBusGuestName()),PaymentOffset::getBusGuestName,paymentOffset.getBusGuestName()); wrapper.like(StrUtil.isNotBlank(paymentOffset.getContractName()),PaymentOffset::getContractName,paymentOffset.getContractName()); wrapper.orderByDesc(PaymentOffset::getCreateTime); return R.ok(paymentOffsetService.page(page, wrapper)); } /** * 通过id查询抵抹账 * @param id id * @return R */ @Operation(summary = "通过id查询" , description = "通过id查询" ) @GetMapping("/{id}" ) @PreAuthorize("@pms.hasPermission('business_paymentOffset_view')" ) public R getById(@PathVariable("id" ) Long id) { return R.ok(paymentOffsetService.getById(id)); } /** * 新增抵抹账 * @param paymentOffset 抵抹账 * @return R */ @Operation(summary = "新增抵抹账" , description = "新增抵抹账" ) @SysLog("新增抵抹账" ) @PostMapping @PreAuthorize("@pms.hasPermission('business_paymentOffset_add')" ) public R save(@RequestBody PaymentOffset paymentOffset) { return paymentOffsetService.add(paymentOffset); } /** * 修改抵抹账 * @param paymentOffset 抵抹账 * @return R */ @Operation(summary = "修改抵抹账" , description = "修改抵抹账" ) @SysLog("修改抵抹账" ) @PutMapping @PreAuthorize("@pms.hasPermission('business_paymentOffset_edit')" ) public R updateById(@RequestBody PaymentOffset paymentOffset) { return R.ok(paymentOffsetService.updateById(paymentOffset)); } /** * 通过id删除抵抹账 * @param ids id列表 * @return R */ @Operation(summary = "通过id删除抵抹账" , description = "通过id删除抵抹账" ) @SysLog("通过id删除抵抹账" ) @DeleteMapping @PreAuthorize("@pms.hasPermission('business_paymentOffset_del')" ) public R removeById(@RequestBody Long[] ids) { return R.ok(paymentOffsetService.removeBatchByIds(CollUtil.toList(ids))); } /** * 导出excel 表格 * @param paymentOffset 查询条件 * @param ids 导出指定ID * @return excel 文件流 */ @ResponseExcel @GetMapping("/export") @PreAuthorize("@pms.hasPermission('business_paymentOffset_export')" ) public List<PaymentOffset> export(PaymentOffset paymentOffset,Long[] ids) { return paymentOffsetService.list(Wrappers.lambdaQuery(paymentOffset).in(ArrayUtil.isNotEmpty(ids), PaymentOffset::getId, ids)); } } platformx-business-finance-biz/src/main/java/com/by4cloud/platformx/business/mapper/ContractMapper.java
@@ -1,12 +1,18 @@ package com.by4cloud.platformx.business.mapper; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.by4cloud.platformx.business.dto.CreditSalesQueryDTO; import com.by4cloud.platformx.business.entity.Contract; import com.by4cloud.platformx.business.vo.ContractCreditSalesPageVo; import com.by4cloud.platformx.common.data.datascope.DataScope; import com.by4cloud.platformx.common.data.datascope.PlatformxBaseMapper; import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Param; /** * @author 28254 */ @Mapper public interface ContractMapper extends PlatformxBaseMapper<Contract> { Page<ContractCreditSalesPageVo> pageByCredit(Page page, @Param("queryDTO") CreditSalesQueryDTO queryDTO, DataScope comp_id); } platformx-business-finance-biz/src/main/java/com/by4cloud/platformx/business/mapper/PaymentOffsetMapper.java
New file @@ -0,0 +1,11 @@ package com.by4cloud.platformx.business.mapper; import com.by4cloud.platformx.common.data.datascope.PlatformxBaseMapper; import com.by4cloud.platformx.business.entity.PaymentOffset; import org.apache.ibatis.annotations.Mapper; @Mapper public interface PaymentOffsetMapper extends PlatformxBaseMapper<PaymentOffset> { } platformx-business-finance-biz/src/main/java/com/by4cloud/platformx/business/service/ContractService.java
@@ -26,4 +26,6 @@ R refuseApproval(Long id); void takeEffect(Long id); R copyNewContract(Long id); } platformx-business-finance-biz/src/main/java/com/by4cloud/platformx/business/service/CreditSalesService.java
New file @@ -0,0 +1,8 @@ package com.by4cloud.platformx.business.service; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.by4cloud.platformx.business.dto.CreditSalesQueryDTO; public interface CreditSalesService { Page page(Page page, CreditSalesQueryDTO queryDTO); } platformx-business-finance-biz/src/main/java/com/by4cloud/platformx/business/service/PaymentConfirmService.java
@@ -8,4 +8,6 @@ public interface PaymentConfirmService extends IIService<PaymentConfirm> { R add(PaymentConfirmAddDTO addDTO); R syncPaymentRecepit(); } platformx-business-finance-biz/src/main/java/com/by4cloud/platformx/business/service/PaymentOffsetService.java
New file @@ -0,0 +1,10 @@ package com.by4cloud.platformx.business.service; import com.baomidou.mybatisplus.extension.service.IService; import com.by4cloud.platformx.business.entity.PaymentOffset; import com.by4cloud.platformx.common.core.util.R; public interface PaymentOffsetService extends IService<PaymentOffset> { R add(PaymentOffset paymentOffset); } platformx-business-finance-biz/src/main/java/com/by4cloud/platformx/business/service/impl/ContractPaymentScheduleProcessServiceImpl.java
@@ -21,6 +21,9 @@ import java.math.BigDecimal; import java.util.Date; import java.util.List; import java.util.Map; import java.util.Objects; import java.util.stream.Collectors; /** * 履约节点 @@ -33,166 +36,330 @@ public class ContractPaymentScheduleProcessServiceImpl extends ServiceImpl<ContractPaymentScheduleProcessMapper, ContractPaymentScheduleProcess> implements ContractPaymentScheduleProcessService { private final ContractPaymentScheduleMapper contractPaymentScheduleMapper; private final ContractPaymentScheduleProcessMapper processMapper; private final ContractMapper contractMapper; private final ContractSubjectMatterMapper subjectMatterMapper; private final PaymentConfirmMapper paymentConfirmMapper; private final ContractOutBoundMapper contractOutBoundMapper; @Override public R add(ContractPaymentScheduleProcessAddDTO addDTO) { ContractPaymentSchedule schedule = contractPaymentScheduleMapper.selectById(addDTO.getScheduleId()); if (ObjUtil.isNull(schedule)){ if (ObjUtil.isNull(schedule)) { return R.failed("履约阶段与合同不一致,请联系技术人员"); } if (schedule.getStageName().equals("货到签收") && ArrayUtil.isEmpty(addDTO.getContractOutBoundIds().toArray())) { return R.failed("请选择到货的出库信息"); } //合同 Contract contract = contractMapper.selectById(schedule.getContractId()); List<ContractSubjectMatter> subjectMatterList = subjectMatterMapper.selectList(Wrappers.<ContractSubjectMatter>lambdaQuery().eq(ContractSubjectMatter::getContractId,contract.getId())); if (ArrayUtil.isEmpty(subjectMatterList.toArray())){ List<ContractSubjectMatter> subjectMatterList = subjectMatterMapper.selectList(Wrappers.<ContractSubjectMatter>lambdaQuery().eq(ContractSubjectMatter::getContractId, contract.getId())); if (ArrayUtil.isEmpty(subjectMatterList.toArray())) { return R.failed("该合同标的物异常,请联系技术人员"); } if (!subjectMatterList.stream().allMatch(item->item.getDeliveryStatus()==2)){ return R.failed("出库数量小于当前合同标的物数量,无法进行当前操作"); // if (!subjectMatterList.stream().allMatch(item -> item.getDeliveryStatus() == 2)) { // return R.failed("出库数量小于当前合同标的物数量,无法进行当前操作"); // } if (schedule.getStageName().equals("货到签收")) { //更新合同出库到货时间 addDTO.getContractOutBoundIds().forEach(contractOutBoundId -> { ContractOutBound contractOutBound = contractOutBoundMapper.selectById(contractOutBoundId); contractOutBound.setArrivalTime(addDTO.getProcessDate()); contractOutBound.setArrivalAttNames(addDTO.getOutBoundAttNames()); contractOutBound.setArrivalAttPaths(addDTO.getOutBoundAttPaths()); contractOutBoundMapper.updateById(contractOutBound); }); } //新增当前阶段应收 PaymentConfirm currentConfim = new PaymentConfirm(); currentConfim.setBusinessType(schedule.getStageName()+"应收"); currentConfim.setBusGuestId(contract.getPartyAId()); currentConfim.setBusGuestName(contract.getPartyA()); currentConfim.setContractId(contract.getId()); currentConfim.setContractName(contract.getContractName()); currentConfim.setContractNo(contract.getContractNo()); currentConfim.setScheduleId(schedule.getId()); currentConfim.setScheduleName(schedule.getStageName()); currentConfim.setConfirmTime(addDTO.getProcessDate()); currentConfim.setTransationAmount(schedule.getPlannedAmount()); currentConfim.setReceivableAmount(schedule.getPlannedAmount()); PaymentConfirm lastConfirm = paymentConfirmMapper.selectOne(Wrappers.<PaymentConfirm>lambdaQuery().eq(PaymentConfirm::getContractId,contract.getId()) .orderByDesc(PaymentConfirm::getCreateTime).last("limit 1")); BigDecimal lastTotal = new BigDecimal("0"); if(ObjUtil.isNotNull(lastConfirm)){ lastTotal = lastConfirm.getTotalAmount(); } currentConfim.setTotalAmount(lastTotal.subtract(currentConfim.getReceivableAmount())); paymentConfirmMapper.insert(currentConfim); //履约 ContractPaymentScheduleProcess contractPaymentScheduleProcess = BeanUtil.copyProperties(addDTO,ContractPaymentScheduleProcess.class); ContractPaymentScheduleProcess contractPaymentScheduleProcess = BeanUtil.copyProperties(addDTO, ContractPaymentScheduleProcess.class); contractPaymentScheduleProcess.setContractId(schedule.getContractId()); contractPaymentScheduleProcess.setContractName(schedule.getContractName()); contractPaymentScheduleProcess.setScheduleId(schedule.getId()); contractPaymentScheduleProcess.setScheduleName(schedule.getStageName()); baseMapper.insert(contractPaymentScheduleProcess); ContractPaymentScheduleProcess lastProcess = baseMapper.selectOne(Wrappers.<ContractPaymentScheduleProcess>lambdaQuery().eq(ContractPaymentScheduleProcess::getContractId, schedule.getContractId()) .eq(ContractPaymentScheduleProcess::getScheduleId, schedule.getId()).last("limit 1")); if (ObjUtil.isNull(lastProcess)) { baseMapper.insert(contractPaymentScheduleProcess); } //更新当前阶段 if (ObjUtil.isNull(schedule.getEffectiveDate())) { schedule.setEffectiveDate(DateUtil.offsetDay(addDTO.getProcessDate(),schedule.getAgreedDays())); if (ObjUtil.isNull(schedule.getEffectiveDate()) && ObjUtil.isNull(schedule.getEffectiveEndDate())) { schedule.setEffectiveDate(DateUtil.offsetDay(addDTO.getProcessDate(), schedule.getAgreedDays())); contractPaymentScheduleMapper.updateById(schedule); } //查询是否有之前阶段 ContractPaymentSchedule beforeSchedule = contractPaymentScheduleMapper.selectOne(Wrappers.<ContractPaymentSchedule>lambdaQuery().eq(ContractPaymentSchedule::getContractId, schedule.getContractId()) .lt(ContractPaymentSchedule::getStageOrder, schedule.getStageOrder()).orderByDesc(ContractPaymentSchedule::getCreateTime).last("limit 1")); if (ObjUtil.isNotNull(beforeSchedule)){ if (ObjUtil.isNotNull(beforeSchedule) && ObjUtil.isNull(beforeSchedule.getEffectiveEndDate())) { beforeSchedule.setEffectiveEndDate(schedule.getEffectiveDate()); contractPaymentScheduleMapper.updateById(beforeSchedule); //之前阶段是否收款完成 // if (beforeSchedule.getPaymentStatus()!=2){ // //新增之前阶段超期 // PaymentConfirm beforeConfim = new PaymentConfirm(); // beforeConfim.setBusinessType("应收超期"); // beforeConfim.setBusGuestId(contract.getPartyAId()); // beforeConfim.setBusGuestName(contract.getPartyA()); // beforeConfim.setContractId(contract.getId()); // beforeConfim.setContractName(contract.getContractName()); // beforeConfim.setContractNo(contract.getContractNo()); // beforeConfim.setScheduleId(schedule.getId()); // beforeConfim.setScheduleName(schedule.getStageName()); // beforeConfim.setConfirmTime(addDTO.getProcessDate()); // beforeConfim.setTransationAmount(schedule.getPlannedAmount()); // PaymentConfirm newLastConfirm = paymentConfirmMapper.selectOne(Wrappers.<PaymentConfirm>lambdaQuery().eq(PaymentConfirm::getContractId,contract.getId()) // .orderByDesc(PaymentConfirm::getCreateTime).last("limit 1")); // beforeConfim.setOverdueAmount(StrUtil.equals(schedule.getPaymentStatus()+"","0")? // schedule.getPlannedAmount(): // schedule.getPlannedAmount().subtract(schedule.getActualAmount())); // beforeConfim.setTotalAmount(newLastConfirm.getTotalAmount()); // paymentConfirmMapper.insert(beforeConfim); // } } } //查询是否有后续阶段 List<ContractPaymentSchedule> afterSchedule = contractPaymentScheduleMapper.selectList(Wrappers.<ContractPaymentSchedule>lambdaQuery() .eq(ContractPaymentSchedule::getContractId, schedule.getContractId()) .gt(ContractPaymentSchedule::getStageOrder, schedule.getStageOrder())); if (ArrayUtil.isNotEmpty(afterSchedule.toArray())&&afterSchedule.size()==1){ //最后阶段生效时间 ContractPaymentSchedule endSchedule = afterSchedule.get(0); if (StrUtil.equals(endSchedule.getStageName(),"质保金")) { endSchedule.setEffectiveDate(DateUtil.offsetDay(addDTO.getProcessDate(), endSchedule.getAgreedDays())); endSchedule.setEffectiveEndDate(contract.getExpirationDate()); contractPaymentScheduleMapper.updateById(endSchedule); //当前阶段生效时间 schedule.setEffectiveDate(DateUtil.offsetDay(addDTO.getProcessDate(), schedule.getAgreedDays())); schedule.setEffectiveEndDate(endSchedule.getEffectiveDate()); contractPaymentScheduleMapper.updateById(schedule); //最后阶段应收 PaymentConfirm newConfim = new PaymentConfirm(); newConfim.setBusinessType(endSchedule.getStageName() + "应收"); newConfim.setBusGuestId(contract.getPartyAId()); newConfim.setBusGuestName(contract.getPartyA()); newConfim.setContractId(contract.getId()); newConfim.setContractName(contract.getContractName()); newConfim.setContractNo(contract.getContractNo()); newConfim.setScheduleId(endSchedule.getId()); newConfim.setScheduleName(schedule.getStageName()); newConfim.setConfirmTime(addDTO.getProcessDate()); newConfim.setTransationAmount(endSchedule.getPlannedAmount()); newConfim.setReceivableAmount(endSchedule.getPlannedAmount()); PaymentConfirm lastNewConfirm = paymentConfirmMapper.selectOne(Wrappers.<PaymentConfirm>lambdaQuery().eq(PaymentConfirm::getContractId, contract.getId()) .orderByDesc(PaymentConfirm::getCreateTime).last("limit 1")); BigDecimal lastNewTotal = new BigDecimal("0"); if (ObjUtil.isNotNull(lastNewConfirm)) { lastNewTotal = lastNewConfirm.getTotalAmount(); List<ContractOutBound> contractOutBoundList = contractOutBoundMapper.selectList(Wrappers.<ContractOutBound>lambdaQuery().eq(ContractOutBound::getContractId, contract.getId()) .isNotNull(ContractOutBound::getArrivalTime)); if (schedule.getStageName().equals("货到签收")) { if (ArrayUtil.isNotEmpty(contractOutBoundList.toArray()) && ArrayUtil.isNotEmpty(subjectMatterList.toArray())) { Map<String, BigDecimal> sumMap = contractOutBoundList.stream() .collect(Collectors.groupingBy( ContractOutBound::getSubjectMatterCode, Collectors.reducing( BigDecimal.ZERO, ContractOutBound::getOutBoundNum, BigDecimal::add ) )); Boolean outFlag = checkQuantityEquality(subjectMatterList, sumMap); //出库到货与合同标的物种类数量一致 if (outFlag) { //新增当前阶段应收 PaymentConfirm currentConfim = new PaymentConfirm(); currentConfim.setBusinessType(schedule.getStageName() + "应收"); currentConfim.setBusGuestId(contract.getPartyAId()); currentConfim.setBusGuestName(contract.getPartyA()); currentConfim.setContractId(contract.getId()); currentConfim.setContractName(contract.getContractName()); currentConfim.setContractNo(contract.getContractNo()); currentConfim.setScheduleId(schedule.getId()); currentConfim.setScheduleName(schedule.getStageName()); currentConfim.setConfirmTime(addDTO.getProcessDate()); currentConfim.setTransationAmount(schedule.getPlannedAmount()); currentConfim.setReceivableAmount(schedule.getPlannedAmount()); PaymentConfirm lastConfirm = paymentConfirmMapper.selectOne(Wrappers.<PaymentConfirm>lambdaQuery().eq(PaymentConfirm::getContractId, contract.getId()) .orderByDesc(PaymentConfirm::getCreateTime).last("limit 1")); BigDecimal lastTotal = new BigDecimal("0"); if (ObjUtil.isNotNull(lastConfirm)) { lastTotal = lastConfirm.getTotalAmount(); } currentConfim.setTotalAmount(lastTotal.subtract(currentConfim.getReceivableAmount())); if (schedule.getPaymentRatio().compareTo(new BigDecimal("0")) > 0) { paymentConfirmMapper.insert(currentConfim); } //查询是否有后续阶段 List<ContractPaymentSchedule> afterSchedule = contractPaymentScheduleMapper.selectList(Wrappers.<ContractPaymentSchedule>lambdaQuery() .eq(ContractPaymentSchedule::getContractId, schedule.getContractId()) .gt(ContractPaymentSchedule::getStageOrder, schedule.getStageOrder())); if (ArrayUtil.isNotEmpty(afterSchedule.toArray()) && afterSchedule.size() == 1) { //最后阶段生效时间 ContractPaymentSchedule endSchedule = afterSchedule.get(0); if (StrUtil.equals(endSchedule.getStageName(), "质保金")) { endSchedule.setEffectiveDate(DateUtil.offsetDay(addDTO.getProcessDate(), endSchedule.getAgreedDays())); endSchedule.setEffectiveEndDate(contract.getExpirationDate()); contractPaymentScheduleMapper.updateById(endSchedule); //当前阶段生效时间 schedule.setEffectiveDate(DateUtil.offsetDay(addDTO.getProcessDate(), schedule.getAgreedDays())); schedule.setEffectiveEndDate(endSchedule.getEffectiveDate()); contractPaymentScheduleMapper.updateById(schedule); //最后阶段应收 PaymentConfirm newConfim = new PaymentConfirm(); newConfim.setBusinessType(endSchedule.getStageName() + "应收"); newConfim.setBusGuestId(contract.getPartyAId()); newConfim.setBusGuestName(contract.getPartyA()); newConfim.setContractId(contract.getId()); newConfim.setContractName(contract.getContractName()); newConfim.setContractNo(contract.getContractNo()); newConfim.setScheduleId(endSchedule.getId()); newConfim.setScheduleName(schedule.getStageName()); newConfim.setConfirmTime(addDTO.getProcessDate()); newConfim.setTransationAmount(endSchedule.getPlannedAmount()); newConfim.setReceivableAmount(endSchedule.getPlannedAmount()); PaymentConfirm lastNewConfirm = paymentConfirmMapper.selectOne(Wrappers.<PaymentConfirm>lambdaQuery().eq(PaymentConfirm::getContractId, contract.getId()) .orderByDesc(PaymentConfirm::getCreateTime).last("limit 1")); BigDecimal lastNewTotal = new BigDecimal("0"); if (ObjUtil.isNotNull(lastNewConfirm)) { lastNewTotal = lastNewConfirm.getTotalAmount(); } newConfim.setTotalAmount(lastNewTotal.subtract(newConfim.getReceivableAmount())); if (endSchedule.getPaymentRatio().compareTo(new BigDecimal("0")) > 0) { paymentConfirmMapper.insert(newConfim); } } //更新合同下个阶段 contract.setNextScheduleName(endSchedule.getStageName()); contractMapper.updateById(contract); } if (ArrayUtil.isNotEmpty(afterSchedule.toArray()) && afterSchedule.size() > 1) { //更新合同下个阶段 contract.setNextScheduleName(afterSchedule.get(0).getStageName()); contractMapper.updateById(contract); } if (ArrayUtil.isEmpty(afterSchedule.toArray())) { schedule.setEffectiveEndDate(contract.getExpirationDate()); contractPaymentScheduleMapper.updateById(schedule); //更新合同下个阶段 contract.setNextScheduleName("无"); contractMapper.updateById(contract); //当前为合同最后阶段 PaymentConfirm lastNewConfirm = paymentConfirmMapper.selectOne(Wrappers.<PaymentConfirm>lambdaQuery().eq(PaymentConfirm::getContractId, contract.getId()) .orderByDesc(PaymentConfirm::getCreateTime).last("limit 1")); if (lastNewConfirm.getTotalAmount().compareTo(new BigDecimal("0")) >= 0) { //有预付且超过应收 关闭合同状态 contract.setContractStatus(3); contractMapper.updateById(contract); } } } newConfim.setTotalAmount(lastNewTotal.subtract(newConfim.getReceivableAmount())); paymentConfirmMapper.insert(newConfim); } //更新合同下个阶段 contract.setNextScheduleName(endSchedule.getStageName()); contractMapper.updateById(contract); } if(ArrayUtil.isNotEmpty(afterSchedule.toArray())&&afterSchedule.size()>1){ //更新合同下个阶段 contract.setNextScheduleName(afterSchedule.get(0).getStageName()); contractMapper.updateById(contract); } if(ArrayUtil.isEmpty(afterSchedule.toArray())){ schedule.setEffectiveEndDate(contract.getExpirationDate()); contractPaymentScheduleMapper.updateById(schedule); //更新合同下个阶段 contract.setNextScheduleName("无"); contractMapper.updateById(contract); //当前为合同最后阶段 PaymentConfirm lastNewConfirm = paymentConfirmMapper.selectOne(Wrappers.<PaymentConfirm>lambdaQuery().eq(PaymentConfirm::getContractId,contract.getId()) } else { //新增当前阶段应收 PaymentConfirm currentConfim = new PaymentConfirm(); currentConfim.setBusinessType(schedule.getStageName() + "应收"); currentConfim.setBusGuestId(contract.getPartyAId()); currentConfim.setBusGuestName(contract.getPartyA()); currentConfim.setContractId(contract.getId()); currentConfim.setContractName(contract.getContractName()); currentConfim.setContractNo(contract.getContractNo()); currentConfim.setScheduleId(schedule.getId()); currentConfim.setScheduleName(schedule.getStageName()); currentConfim.setConfirmTime(addDTO.getProcessDate()); currentConfim.setTransationAmount(schedule.getPlannedAmount()); currentConfim.setReceivableAmount(schedule.getPlannedAmount()); PaymentConfirm lastConfirm = paymentConfirmMapper.selectOne(Wrappers.<PaymentConfirm>lambdaQuery().eq(PaymentConfirm::getContractId, contract.getId()) .orderByDesc(PaymentConfirm::getCreateTime).last("limit 1")); if (lastNewConfirm.getTotalAmount().compareTo(new BigDecimal("0"))>=0){ //有预付且超过应收 关闭合同状态 contract.setContractStatus(3); BigDecimal lastTotal = new BigDecimal("0"); if (ObjUtil.isNotNull(lastConfirm)) { lastTotal = lastConfirm.getTotalAmount(); } currentConfim.setTotalAmount(lastTotal.subtract(currentConfim.getReceivableAmount())); if (schedule.getPaymentRatio().compareTo(new BigDecimal("0")) > 0) { paymentConfirmMapper.insert(currentConfim); } //查询是否有后续阶段 List<ContractPaymentSchedule> afterSchedule = contractPaymentScheduleMapper.selectList(Wrappers.<ContractPaymentSchedule>lambdaQuery() .eq(ContractPaymentSchedule::getContractId, schedule.getContractId()) .gt(ContractPaymentSchedule::getStageOrder, schedule.getStageOrder())); if (ArrayUtil.isNotEmpty(afterSchedule.toArray()) && afterSchedule.size() == 1) { //最后阶段生效时间 ContractPaymentSchedule endSchedule = afterSchedule.get(0); if (StrUtil.equals(endSchedule.getStageName(), "质保金")) { endSchedule.setEffectiveDate(DateUtil.offsetDay(addDTO.getProcessDate(), endSchedule.getAgreedDays())); endSchedule.setEffectiveEndDate(contract.getExpirationDate()); contractPaymentScheduleMapper.updateById(endSchedule); //当前阶段生效时间 schedule.setEffectiveDate(DateUtil.offsetDay(addDTO.getProcessDate(), schedule.getAgreedDays())); schedule.setEffectiveEndDate(endSchedule.getEffectiveDate()); contractPaymentScheduleMapper.updateById(schedule); //最后阶段应收 PaymentConfirm newConfim = new PaymentConfirm(); newConfim.setBusinessType(endSchedule.getStageName() + "应收"); newConfim.setBusGuestId(contract.getPartyAId()); newConfim.setBusGuestName(contract.getPartyA()); newConfim.setContractId(contract.getId()); newConfim.setContractName(contract.getContractName()); newConfim.setContractNo(contract.getContractNo()); newConfim.setScheduleId(endSchedule.getId()); newConfim.setScheduleName(schedule.getStageName()); newConfim.setConfirmTime(addDTO.getProcessDate()); newConfim.setTransationAmount(endSchedule.getPlannedAmount()); newConfim.setReceivableAmount(endSchedule.getPlannedAmount()); PaymentConfirm lastNewConfirm = paymentConfirmMapper.selectOne(Wrappers.<PaymentConfirm>lambdaQuery().eq(PaymentConfirm::getContractId, contract.getId()) .orderByDesc(PaymentConfirm::getCreateTime).last("limit 1")); BigDecimal lastNewTotal = new BigDecimal("0"); if (ObjUtil.isNotNull(lastNewConfirm)) { lastNewTotal = lastNewConfirm.getTotalAmount(); } newConfim.setTotalAmount(lastNewTotal.subtract(newConfim.getReceivableAmount())); if (endSchedule.getPaymentRatio().compareTo(new BigDecimal("0")) > 0) { paymentConfirmMapper.insert(newConfim); } } //更新合同下个阶段 contract.setNextScheduleName(endSchedule.getStageName()); contractMapper.updateById(contract); } if (ArrayUtil.isNotEmpty(afterSchedule.toArray()) && afterSchedule.size() > 1) { //更新合同下个阶段 contract.setNextScheduleName(afterSchedule.get(0).getStageName()); contractMapper.updateById(contract); } if (ArrayUtil.isEmpty(afterSchedule.toArray())) { schedule.setEffectiveEndDate(contract.getExpirationDate()); contractPaymentScheduleMapper.updateById(schedule); //更新合同下个阶段 contract.setNextScheduleName("无"); contractMapper.updateById(contract); //当前为合同最后阶段 PaymentConfirm lastNewConfirm = paymentConfirmMapper.selectOne(Wrappers.<PaymentConfirm>lambdaQuery().eq(PaymentConfirm::getContractId, contract.getId()) .orderByDesc(PaymentConfirm::getCreateTime).last("limit 1")); if (lastNewConfirm.getTotalAmount().compareTo(new BigDecimal("0")) >= 0) { //有预付且超过应收 关闭合同状态 contract.setContractStatus(3); contractMapper.updateById(contract); } } } return R.ok(); } public boolean checkQuantityEquality(List<ContractSubjectMatter> subjectMatterList, Map<String, BigDecimal> materialCodeMap) { // 1. 基本校验 if (subjectMatterList == null || materialCodeMap == null) { return false; } // 如果要求两者包含的物料代码完全一致且数量一致,先比较 Key 的数量 // 提取 List 中非空的 materialCode List<String> listCodes = subjectMatterList.stream() .map(ContractSubjectMatter::getMaterialCode) .filter(Objects::nonNull) .distinct() .sorted() .collect(Collectors.toList()); List<String> mapKeys = materialCodeMap.keySet().stream() .sorted() .collect(Collectors.toList()); // 如果物料编码集合不一致,直接返回 false if (!listCodes.equals(mapKeys)) { return false; } // 2. 逐个比较数量 // 假设 ContractSubjectMatter 中有 getQuantity() 方法返回 BigDecimal 或 Number for (ContractSubjectMatter item : subjectMatterList) { String code = item.getMaterialCode(); if (code == null) continue; BigDecimal mapValue = materialCodeMap.get(code); BigDecimal listValue = item.getQuantity(); // 假设这是 List 中代表数量的字段 // 处理 null 情况 if (mapValue == null && listValue == null) { continue; // 都为空视为相等,或根据业务定为不等 } if (mapValue == null || listValue == null) { return false; // 一个为空一个不为空,不等 } // 使用 compareTo 比较 BigDecimal 值,0 表示相等 if (listValue.compareTo(mapValue) != 0) { return false; // 发现不相等,立即返回 } } return true; // 所有匹配项数量均相等 } @Override public R selectScheduleProcess(Long id) { MPJLambdaWrapper<ContractPaymentSchedule> wrapper = new MPJLambdaWrapper<ContractPaymentSchedule>() .select(ContractPaymentSchedule::getId,ContractPaymentSchedule::getStageName,ContractPaymentSchedule::getEffectiveDate, ContractPaymentSchedule::getPlannedAmount,ContractPaymentSchedule::getPlannedAmount, ContractPaymentSchedule::getEffectiveEndDate,ContractPaymentSchedule::getPaymentDate, ContractPaymentSchedule::getPaymentStatus,ContractPaymentSchedule::getActualAmount, .select(ContractPaymentSchedule::getId, ContractPaymentSchedule::getStageName, ContractPaymentSchedule::getEffectiveDate, ContractPaymentSchedule::getPlannedAmount, ContractPaymentSchedule::getPlannedAmount, ContractPaymentSchedule::getEffectiveEndDate, ContractPaymentSchedule::getPaymentDate, ContractPaymentSchedule::getPaymentStatus, ContractPaymentSchedule::getActualAmount, ContractPaymentSchedule::getAgreedDays) .select(ContractPaymentScheduleProcess::getProcessDate) .leftJoin(ContractPaymentScheduleProcess.class,ContractPaymentScheduleProcess::getScheduleId,ContractPaymentSchedule::getId) .eq(ContractPaymentSchedule::getContractId,id) .leftJoin(ContractPaymentScheduleProcess.class, ContractPaymentScheduleProcess::getScheduleId, ContractPaymentSchedule::getId) .eq(ContractPaymentSchedule::getContractId, id) .orderByAsc(ContractPaymentSchedule::getCreateTime); List<ContractPaymentScheduleVo> scheduleVoList = contractPaymentScheduleMapper.selectJoinList(ContractPaymentScheduleVo.class,wrapper); List<ContractPaymentScheduleVo> scheduleVoList = contractPaymentScheduleMapper.selectJoinList(ContractPaymentScheduleVo.class, wrapper); return R.ok(scheduleVoList); } } platformx-business-finance-biz/src/main/java/com/by4cloud/platformx/business/service/impl/ContractServiceImpl.java
@@ -52,6 +52,7 @@ contract.setPartyBId(SecurityUtils.getUser().getCompId()); contract.setPartyB(SecurityUtils.getUser().getCompName()); contract.setContractNo(ContractNumberGenerator.generateContractNumber()); contract.setPaidAmount(new BigDecimal("0")); contract.setBillingStatus("0"); contract.setErpPushFlag("0"); List<Contract> contracts; @@ -122,6 +123,7 @@ contract.setContractNo(ContractNumberGenerator.generateContractNumber()); contract.setBillingStatus("0"); contract.setErpPushFlag("0"); contract.setPaidAmount(new BigDecimal("0")); List<Contract> contracts; contracts = baseMapper.selectList(Wrappers.<Contract>lambdaQuery().eq(Contract::getContractNo,contract.getContractNo())); while (ArrayUtil.isNotEmpty(contracts.toArray())){ @@ -226,7 +228,9 @@ lastNewTotal = lastNewConfirm.getTotalAmount(); } paymentConfirm.setTotalAmount(lastNewTotal.subtract(paymentConfirm.getReceivableAmount())); paymentConfirmMapper.insert(paymentConfirm); if (fitstSchedule.getPaymentRatio().compareTo(new BigDecimal("0"))>0){ paymentConfirmMapper.insert(paymentConfirm); } //新增合同履约记录 ContractPaymentScheduleProcess process = new ContractPaymentScheduleProcess(); process.setContractId(contract.getId()); @@ -238,7 +242,7 @@ //当前为合同最后阶段 PaymentConfirm newConfirm = paymentConfirmMapper.selectOne(Wrappers.<PaymentConfirm>lambdaQuery().eq(PaymentConfirm::getContractId,contract.getId()) .orderByDesc(PaymentConfirm::getCreateTime).last("limit 1")); if (newConfirm.getTotalAmount().compareTo(new BigDecimal("0"))>=0){ if (ObjUtil.isNotNull(newConfirm)&&newConfirm.getTotalAmount().compareTo(new BigDecimal("0"))>=0){ //有预付且超过应收 关闭合同状态 contract.setContractStatus(3); baseMapper.updateById(contract); @@ -277,7 +281,9 @@ lastNewTotal = lastNewConfirm.getTotalAmount(); } paymentConfirm.setTotalAmount(lastNewTotal.subtract(paymentConfirm.getReceivableAmount())); paymentConfirmMapper.insert(paymentConfirm); if (fitstSchedule.getPaymentRatio().compareTo(new BigDecimal("0"))>0) { paymentConfirmMapper.insert(paymentConfirm); } } //查询是否有后续阶段 List<ContractPaymentSchedule> afterSchedule = contractPaymentScheduleMapper.selectList(Wrappers.<ContractPaymentSchedule>lambdaQuery() @@ -316,7 +322,9 @@ lastNewTotal = lastNewConfirm.getTotalAmount(); } newConfim.setTotalAmount(lastNewTotal.subtract(newConfim.getReceivableAmount())); paymentConfirmMapper.insert(newConfim); if (endSchedule.getPaymentRatio().compareTo(new BigDecimal("0"))>0) { paymentConfirmMapper.insert(newConfim); } } //更新合同下个阶段 contract.setNextScheduleName(endSchedule.getStageName()); @@ -369,7 +377,7 @@ //判断当前阶段是否已生成上阶段应收超期 PaymentConfirm oiverdueConfirm = paymentConfirmMapper.selectOne(Wrappers.<PaymentConfirm>lambdaQuery().eq(PaymentConfirm::getScheduleId, contractPaymentSchedule.getId()) .eq(PaymentConfirm::getBusinessType, "应收超期")); if (ObjUtil.isNull(oiverdueConfirm)) { if (ObjUtil.isNull(oiverdueConfirm)&&overdueConfirm.getTransationAmount().compareTo(new BigDecimal("0"))>0) { overdueConfirm.setCompId(contractPaymentSchedule.getCompId()); paymentConfirmMapper.insert(overdueConfirm); } @@ -390,7 +398,9 @@ .eq(CurrentOverdue::getScheduleId,currentOverdue.getScheduleId()).last("limit 1")); if (ObjUtil.isNull(overdue)){ currentOverdue.setCompId(contractPaymentSchedule.getCompId()); currentOverdueMapper.insert(currentOverdue); if (currentOverdue.getReceivableAmount().compareTo(new BigDecimal("0"))>0){ currentOverdueMapper.insert(currentOverdue); } }else { overdue.setOverdueDuration(BigDecimal.valueOf(DateUtil.betweenDay(contractPaymentSchedule.getEffectiveEndDate(),new Date(),true))); currentOverdueMapper.updateById(overdue); @@ -407,4 +417,22 @@ baseMapper.updateById(contract); return R.ok(); } @Override public R copyNewContract(Long id) { Contract oldContract = baseMapper.selectById(id); Contract newContract = BeanUtil.copyProperties(oldContract,Contract.class,"id","createTime"); newContract.setContractNo(ContractNumberGenerator.generateContractNumber()); newContract.setPaidAmount(new BigDecimal("0")); newContract.setBillingStatus("0"); newContract.setErpPushFlag("0"); List<Contract> contracts; contracts = baseMapper.selectList(Wrappers.<Contract>lambdaQuery().eq(Contract::getContractNo,newContract.getContractNo())); while (ArrayUtil.isNotEmpty(contracts.toArray())){ newContract.setContractNo(ContractNumberGenerator.generateContractNumber()); contracts = baseMapper.selectList(Wrappers.<Contract>lambdaQuery().eq(Contract::getContractNo,newContract.getContractNo())); } baseMapper.insert(newContract); return R.ok(); } } platformx-business-finance-biz/src/main/java/com/by4cloud/platformx/business/service/impl/CreditSalesServiceImpl.java
New file @@ -0,0 +1,27 @@ package com.by4cloud.platformx.business.service.impl; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.by4cloud.platformx.business.dto.CreditSalesQueryDTO; import com.by4cloud.platformx.business.mapper.ContractMapper; import com.by4cloud.platformx.business.service.CreditSalesService; import com.by4cloud.platformx.common.data.datascope.DataScope; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; /** * 赊销 * * @author syt * @date 2026-05-15 14:13:59 */ @Service @RequiredArgsConstructor public class CreditSalesServiceImpl implements CreditSalesService { private final ContractMapper contractMapper; @Override public Page page(Page page, CreditSalesQueryDTO queryDTO) { return contractMapper.pageByCredit(page, queryDTO, DataScope.of("comp_id")); } } platformx-business-finance-biz/src/main/java/com/by4cloud/platformx/business/service/impl/OutBoundServiceImpl.java
@@ -59,19 +59,16 @@ if (ArrayUtil.isEmpty(subjectMatterList.toArray())) { return R.failed("没有查询到相关合同订单"); } Double outTotal = subjectMatterList.stream().mapToDouble(item -> { // 优先判断 remainNum if (item.getRemainingQuantity() != null && item.getRemainingQuantity().compareTo(new BigDecimal("0")) > 0) { return item.getRemainingQuantity().doubleValue(); } else { // remainNum 为 null 或 0 时,使用 quantity return item.getQuantity() == null ? 0.0 : item.getQuantity().doubleValue(); } }).sum(); BigDecimal orderNum = addDTO.getSubjectMatterList().stream().map(OutSubjectMatterAddDTO::getOutBoundNum) List<String> erpCodeList = subjectMatterList.stream().map(ContractSubjectMatter::getMaterialCode).collect(Collectors.toList()); BigDecimal orderNum = subjectMatterList.stream().filter(item ->item.getDeliveryStatus()!=2) .map(item ->item.getDeliveryStatus()==0?item.getQuantity():item.getRemainingQuantity()) .reduce(BigDecimal.ZERO, BigDecimal::add); BigDecimal outTotal = addDTO.getSubjectMatterList().stream() .filter(item->erpCodeList.contains(item.getSubjectMatterCode())) .map(OutSubjectMatterAddDTO::getOutBoundNum) .filter(num -> num != null) // 过滤掉 null 值,防止 NullPointerException .reduce(BigDecimal.ZERO, BigDecimal::add); if (new BigDecimal(outTotal).compareTo(orderNum) < 0) { if (outTotal.compareTo(orderNum) > 0) { return R.failed("出库数量超出合同订单数量"); } //当前入库标的物 @@ -203,16 +200,22 @@ paymentConfirm.setTransationAmount(paymentConfirm.getTransationAmount().subtract(fhTotalAmount)); paymentConfirm.setReceivableAmount(paymentConfirm.getTransationAmount()); paymentConfirm.setTotalAmount(lastConfirm.getTotalAmount().subtract(paymentConfirm.getTransationAmount())); paymentConfirmMapper.insert(paymentConfirm); if(schedule.getPaymentRatio().compareTo(new BigDecimal("0"))>0) { paymentConfirmMapper.insert(paymentConfirm); } } else { //不存在发货应收 出库总额 paymentConfirm.setTotalAmount(lastConfirm.getTotalAmount().subtract(paymentConfirm.getTransationAmount())); paymentConfirmMapper.insert(paymentConfirm); if(schedule.getPaymentRatio().compareTo(new BigDecimal("0"))>0) { paymentConfirmMapper.insert(paymentConfirm); } } } else { //无之前阶段应收 paymentConfirm.setTotalAmount(paymentConfirm.getTransationAmount().multiply(new BigDecimal("-1"))); paymentConfirmMapper.insert(paymentConfirm); if(schedule.getPaymentRatio().compareTo(new BigDecimal("0"))>0) { paymentConfirmMapper.insert(paymentConfirm); } } //更新发货前收款生效时间 @@ -278,7 +281,9 @@ lastNewTotal = lastNewConfirm.getTotalAmount(); } newConfim.setTotalAmount(lastNewTotal.subtract(newConfim.getReceivableAmount())); paymentConfirmMapper.insert(newConfim); if(endSchedule.getPaymentRatio().compareTo(new BigDecimal("0"))>0) { paymentConfirmMapper.insert(newConfim); } } //更新合同下个阶段 contract.setNextScheduleName(endSchedule.getStageName()); platformx-business-finance-biz/src/main/java/com/by4cloud/platformx/business/service/impl/PaymentConfirmServiceImpl.java
@@ -1,9 +1,12 @@ package com.by4cloud.platformx.business.service.impl; import cn.hutool.core.bean.BeanUtil; import cn.hutool.core.date.DateUtil; import cn.hutool.core.util.ArrayUtil; import cn.hutool.core.util.ObjUtil; import cn.hutool.core.util.StrUtil; import cn.hutool.http.HttpUtil; import com.alibaba.fastjson.JSONObject; import com.baomidou.mybatisplus.core.toolkit.Wrappers; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.by4cloud.platformx.business.dto.PaymentConfirmAddDTO; @@ -17,6 +20,7 @@ import com.by4cloud.platformx.business.service.PaymentConfirmService; import com.by4cloud.platformx.common.core.util.R; import lombok.RequiredArgsConstructor; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; import java.math.BigDecimal; @@ -39,6 +43,10 @@ private final ContractPaymentScheduleMapper contractPaymentScheduleMapper; private final CurrentOverdueMapper currentOverdueMapper; private final HistoryOverdueMapper historyOverdueMapper; @Value("${bip.url}") private String url; @Override public R add(PaymentConfirmAddDTO addDTO) { @@ -92,6 +100,7 @@ entity.setConfirmTime(new Date()); baseMapper.insert(entity); } //更新付款阶段付款 List<ContractPaymentSchedule> scheduleList = contractPaymentScheduleMapper.selectList(Wrappers.<ContractPaymentSchedule>lambdaQuery() .eq(ContractPaymentSchedule::getContractId,contract.getId()).ne(ContractPaymentSchedule::getPaymentStatus,2) .orderByAsc(ContractPaymentSchedule::getCreateTime)); @@ -145,6 +154,17 @@ } } } //更新合同已付款 BigDecimal paid = new BigDecimal("0"); if (ObjUtil.isNotNull(contract.getPaidAmount())){ paid = contract.getPaidAmount(); } paid = paid.add(addDTO.getTransationAmount()); contract.setPaidAmount(paid); if (paid.compareTo(contract.getAmount())>0){ contract.setPaidAmount(contract.getAmount()); } contractService.updateById(contract); } //转出 if (StrUtil.equals(addDTO.getInOrOut(),"2")){ @@ -179,4 +199,25 @@ } return R.ok(); } @Override public R syncPaymentRecepit() { JSONObject params = new JSONObject(); params.put("pageIndex", 1); params.put("pageSize", 999); params.put("open_billDate_begin", DateUtil.offsetDay(new Date(),-1) + " 00:00:00"); params.put("open_billDate_begin", DateUtil.today() + " 00:00:00"); //单据状态已审批 params.put("verifyState", new String[]{"2"}); //往来对象客户 params.put("objectType", new String[]{"1"}); //单位 // JSONObject simpleMap = new JSONObject(); // simpleMap.put("financeOrg.code", bipCode); // params.put("simple", simpleMap); HttpUtil.post(url+"/yonbip/EFI/collection/list",params.toJSONString()); return null; } } platformx-business-finance-biz/src/main/java/com/by4cloud/platformx/business/service/impl/PaymentOffsetServiceImpl.java
New file @@ -0,0 +1,133 @@ package com.by4cloud.platformx.business.service.impl; import cn.hutool.core.bean.BeanUtil; import cn.hutool.core.util.ArrayUtil; import cn.hutool.core.util.ObjUtil; import cn.hutool.core.util.StrUtil; import com.baomidou.mybatisplus.core.toolkit.Wrappers; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.by4cloud.platformx.business.entity.*; import com.by4cloud.platformx.business.mapper.*; import com.by4cloud.platformx.business.service.ContractService; import com.by4cloud.platformx.business.service.PaymentOffsetService; import com.by4cloud.platformx.common.core.util.R; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; import java.math.BigDecimal; import java.util.List; import java.util.Objects; /** * 抵抹账 * * @author syt * @date 2026-05-19 10:38:26 */ @Service @RequiredArgsConstructor public class PaymentOffsetServiceImpl extends ServiceImpl<PaymentOffsetMapper, PaymentOffset> implements PaymentOffsetService { private final ContractService contractService; private final PaymentConfirmMapper paymentConfirmMapper; private final ContractPaymentScheduleMapper contractPaymentScheduleMapper; private final CurrentOverdueMapper currentOverdueMapper; private final HistoryOverdueMapper historyOverdueMapper; @Override public R add(PaymentOffset paymentOffset) { baseMapper.insert(paymentOffset); Contract contract = contractService.getById(paymentOffset.getContractId()); PaymentConfirm lastConfirm = paymentConfirmMapper.selectOne(Wrappers.<PaymentConfirm>lambdaQuery().eq(PaymentConfirm::getContractId,contract.getId()) .orderByDesc(PaymentConfirm::getCreateTime).last("limit 1")); BigDecimal lastTotal = new BigDecimal("0"); if(ObjUtil.isNotNull(lastConfirm)){ lastTotal = lastConfirm.getTotalAmount(); } PaymentConfirm entity = new PaymentConfirm(); entity.setContractId(contract.getId()); entity.setContractName(contract.getContractName()); entity.setContractNo(contract.getContractNo()); entity.setBusGuestId(paymentOffset.getBusGuestId()); entity.setBusGuestName(paymentOffset.getBusGuestName()); entity.setBusinessType("抵抹账"); entity.setConfirmTime(paymentOffset.getOffsetTime()); entity.setTransationAmount(paymentOffset.getOffsetAmount()); entity.setTotalAmount(paymentOffset.getOffsetAmount().add(lastTotal)); paymentConfirmMapper.insert(entity); //更新付款阶段付款 List<ContractPaymentSchedule> scheduleList = contractPaymentScheduleMapper.selectList(Wrappers.<ContractPaymentSchedule>lambdaQuery() .eq(ContractPaymentSchedule::getContractId,contract.getId()).ne(ContractPaymentSchedule::getPaymentStatus,2) .orderByAsc(ContractPaymentSchedule::getCreateTime)); if (ArrayUtil.isNotEmpty(scheduleList.toArray())){ BigDecimal remain = paymentOffset.getOffsetAmount(); for (ContractPaymentSchedule schedule:scheduleList) { BigDecimal lastRemain = remain; remain = remain.subtract(StrUtil.equals(schedule.getPaymentStatus()+"","0")?schedule.getPlannedAmount(): schedule.getPlannedAmount().subtract(schedule.getActualAmount())); if (remain.compareTo(new BigDecimal("0"))>=0){ schedule.setActualAmount(schedule.getPlannedAmount()); schedule.setPaymentDate(paymentOffset.getOffsetTime()); schedule.setPaymentStatus(2); contractPaymentScheduleMapper.updateById(schedule); //查询是否有当前逾期 CurrentOverdue currentOverdue = currentOverdueMapper.selectOne(Wrappers.<CurrentOverdue>lambdaQuery().eq(CurrentOverdue::getScheduleId,schedule.getId()) .eq(CurrentOverdue::getContractId,schedule.getContractId()).last("limit 1")); if (ObjUtil.isNotNull(currentOverdue)){ //新增逾期历史 HistoryOverdue historyOverdue = BeanUtil.copyProperties(currentOverdue,HistoryOverdue.class,"id"); historyOverdue.setPaymentTime(paymentOffset.getOffsetTime()); historyOverdue.setCompId(schedule.getCompId()); historyOverdueMapper.insert(historyOverdue); //删除当前逾期 currentOverdueMapper.deleteById(currentOverdue); } }else { schedule.setActualAmount(StrUtil.equals(schedule.getPaymentStatus()+"","0")?schedule.getPlannedAmount().add(remain): schedule.getActualAmount().add(lastRemain)); schedule.setPaymentDate(paymentOffset.getOffsetTime()); schedule.setPaymentStatus(1); contractPaymentScheduleMapper.updateById(schedule); //查询是否有当前逾期 CurrentOverdue currentOverdue = currentOverdueMapper.selectOne(Wrappers.<CurrentOverdue>lambdaQuery().eq(CurrentOverdue::getScheduleId,schedule.getId()) .eq(CurrentOverdue::getContractId,schedule.getContractId()).last("limit 1")); if (ObjUtil.isNotNull(currentOverdue)){ //新增逾期历史 HistoryOverdue historyOverdue = BeanUtil.copyProperties(currentOverdue,HistoryOverdue.class,"id"); historyOverdue.setReceivableAmount(lastRemain); historyOverdue.setPaymentTime(paymentOffset.getOffsetTime()); historyOverdue.setCompId(schedule.getCompId()); historyOverdueMapper.insert(historyOverdue); //查询历史已付逾期金额 List<HistoryOverdue> historyOverdueList = historyOverdueMapper.selectList(Wrappers.<HistoryOverdue>lambdaQuery().eq(HistoryOverdue::getScheduleId,currentOverdue.getScheduleId())); BigDecimal hisTotal = historyOverdueList.stream().map(item->item.getReceivableAmount()).reduce(BigDecimal.ZERO,BigDecimal::add); //更新当前逾期 currentOverdue.setReceivableAmount(schedule.getPlannedAmount().subtract(hisTotal)); currentOverdueMapper.updateById(currentOverdue); } break; } } } //更新合同已付款 BigDecimal paid = new BigDecimal("0"); if (ObjUtil.isNotNull(contract.getPaidAmount())){ paid = contract.getPaidAmount(); } paid = paid.add(paymentOffset.getOffsetAmount()); contract.setPaidAmount(paid); if (paid.compareTo(contract.getAmount())>0){ contract.setPaidAmount(contract.getAmount()); } contractService.updateById(contract); // 查询所有付款阶段是否都付款完成 if (ArrayUtil.isNotEmpty(scheduleList.toArray())){ if (scheduleList.stream().allMatch(item -> Objects.equals(item.getPaymentStatus(), 2))){ contract.setContractStatus(3); contractService.updateById(contract); }; } return R.ok(); } } platformx-business-finance-biz/src/main/resources/mapper/ContractMapper.xml
@@ -4,4 +4,100 @@ <mapper namespace="com.by4cloud.platformx.business.mapper.ContractMapper"> <select id="pageByCredit" resultType="com.by4cloud.platformx.business.vo.ContractCreditSalesPageVo"> SELECT id, contract_no, contract_name, party_a_id, party_a, party_b_id, party_b, amount, currency, contract_type, supply_attribute, contract_status, contract_attribute, sign_date, effective_date, delivery_cycle, expiration_date, attachment_url, remark, parent_id, approve_time, arrival_schedule_id, accept_schedule_id, erp_push_flag, billing_status, next_schedule_name, template_id, sales_model, paid_amount, create_by, update_by, create_time, update_time, del_flag, comp_id, (SELECT GROUP_CONCAT(DISTINCT t1.material_internal_name) from contract_subject_matter t1 WHERE t1.contract_id = t.id) productNames, IFNULL( t.billing_amout, 0 ) billing_amout, ( SELECT IFNULL( sum( unit_price * delivered_quantity ), 0 ) FROM contract_subject_matter t1 WHERE t1.contract_id = t.id ) outBoundAmount, (( SELECT IFNULL( sum( unit_price * delivered_quantity ), 0 ) FROM contract_subject_matter t1 WHERE t1.contract_id = t.id ) - IFNULL( t.billing_amout, 0 )) creditAmount FROM contract t WHERE ( IFNULL( t.billing_amout, 0 )<( SELECT IFNULL( sum( unit_price * delivered_quantity ), 0 ) FROM contract_subject_matter t1 WHERE t1.contract_id = t.id ))=1 <if test="queryDTO.contractName !=null and queryDTO.contractName !=''"> and t.contract_name LIKE CONCAT('%', #{queryDTO.contractName}, '%') </if> <if test="queryDTO.partyA !=null and queryDTO.partyA !=''"> and t.party_a LIKE CONCAT('%', #{queryDTO.partyA}, '%') </if> <if test="queryDTO.productNames !=null and queryDTO.productNames !=''"> and (SELECT GROUP_CONCAT(DISTINCT t1.material_internal_name) from contract_subject_matter t1 WHERE t1.contract_id = t.id) LIKE CONCAT('%', #{queryDTO.productNames}, '%') </if> <choose> <when test="queryDTO.sortFiled !=null and queryDTO.sortFiled !='' and queryDTO.sortFiled == 'sign_date'"> order by ${queryDTO.sortFiled} </when> <when test="queryDTO.sortFiled !=null and queryDTO.sortFiled !='' and queryDTO.sortFiled == 'creditAmount'"> order by (( SELECT IFNULL( sum( unit_price * delivered_quantity ), 0 ) FROM contract_subject_matter t1 WHERE t1.contract_id = t.id ) - IFNULL( t.billing_amout, 0 )) </when> <otherwise> order by t.create_time </otherwise> </choose> <choose> <when test="queryDTO.sortMethod !=null and queryDTO.sortMethod !=''"> ${queryDTO.sortMethod} </when> <otherwise> desc </otherwise> </choose> </select> </mapper> platformx-business-finance-biz/src/main/resources/mapper/PaymentOffsetMapper.xml
New file @@ -0,0 +1,29 @@ <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.by4cloud.platformx.business.mapper.PaymentOffsetMapper"> <resultMap id="paymentOffsetMap" type="com.by4cloud.platformx.business.entity.PaymentOffset"> <id property="id" column="id"/> <result property="compId" column="comp_id"/> <result property="busGuestId" column="bus_guest_id"/> <result property="busGuestName" column="bus_guest_name"/> <result property="contractAmount" column="contract_amount"/> <result property="contractId" column="contract_id"/> <result property="contractName" column="contract_name"/> <result property="contractNo" column="contract_no"/> <result property="offsetAttNames" column="offset_att_names"/> <result property="offsetAttPaths" column="offset_att_paths"/> <result property="offsetTime" column="offset_time"/> <result property="unpaidAmount" column="unpaid_amount"/> <result property="wipeOffAmount" column="wipe_off_amount"/> <result property="invoiceAmount" column="invoice_amount"/> <result property="offsetAmount" column="offset_amount"/> <result property="paidAmount" column="paid_amount"/> <result property="createBy" column="create_by"/> <result property="createTime" column="create_time"/> <result property="updateBy" column="update_by"/> <result property="updateTime" column="update_time"/> <result property="delFlag" column="del_flag"/> </resultMap> </mapper>