1、新增预结算单

2、新增正式结算单
3、调整IAM认证登录
This commit is contained in:
2026-08-18 21:31:59 +08:00
parent c8b8b59c50
commit 154cc4a7cb
53 changed files with 4517 additions and 13 deletions
@@ -25,6 +25,7 @@
*/
package org.springblade.system.feign;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.AllArgsConstructor;
import org.springblade.core.tenant.annotation.NonDS;
import org.springblade.core.tool.api.R;
@@ -63,6 +64,8 @@ public class SysClient implements ISysClient {
private final IRegionService regionService;
private final IFeeItemService feeItemService;
@Override
@GetMapping(MENU)
public R<Menu> getMenu(Long id) {
@@ -200,5 +203,14 @@ public class SysClient implements ISysClient {
return R.data(regionService.getById(code));
}
@Override
@GetMapping(FEE_ITEMS)
public R<List<FeeItem>> getFeeItems() {
return R.data(feeItemService.list(Wrappers.<FeeItem>lambdaQuery()
.eq(FeeItem::getStatus, 1)
.eq(FeeItem::getIsDeleted, 0)
.orderByAsc(FeeItem::getFeeCategory, FeeItem::getName)));
}
}
@@ -108,6 +108,12 @@ public class UserClient implements IUserClient {
return R.data(service.submit(user));
}
@Override
@PostMapping(SAVE_IAM_USER)
public R<Boolean> saveIamUser(@RequestBody User user) {
return R.data(service.saveIamUser(user));
}
@Override
@PostMapping(REGISTER_USER)
public R<String> registerUser(User user) {
@@ -280,6 +280,14 @@ public interface IUserService extends BaseService<User> {
*/
boolean registerUser(User user);
/**
* 新建IAM统一身份认证用户(按可信租户落库)
*
* @param user 用户实体
* @return 是否成功
*/
boolean saveIamUser(User user);
/**
* 配置用户平台扩展信息(租户守卫校验用户归属)
*
@@ -74,6 +74,7 @@ import org.springframework.transaction.annotation.Transactional;
import java.security.SecureRandom;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
@@ -549,6 +550,35 @@ public class UserServiceImpl extends BaseServiceImpl<UserMapper, User> implement
return saveUser(user);
}
@Override
@Transactional(rollbackFor = Exception.class)
public boolean saveIamUser(User user) {
if (AuthUtil.hasAuth()) {
throw new ServiceException("IAM用户创建仅允许统一身份认证流程调用!");
}
Tenant tenant = SysCache.getTenant(user.getTenantId());
if (tenant == null || tenant.getId() == null) {
throw new ServiceException("租户信息错误!");
}
if (user.getUserType() == null) {
user.setUserType(UserType.WEB.getCategory());
}
if (StringUtil.isBlank(user.getRoleId())) {
user.setRoleId(StringPool.MINUS_ONE);
}
if (StringUtil.isBlank(user.getDeptId())) {
user.setDeptId(StringPool.MINUS_ONE);
}
if (StringUtil.isBlank(user.getPostId())) {
user.setPostId(StringPool.MINUS_ONE);
}
user.setIsOa(1);
user.setSyncTime(new Date());
user.setStatus(StatusType.ACTIVE.getType());
applyUserDefaults(user);
return saveUser(user);
}
@Override
@Transactional(rollbackFor = Exception.class)
public boolean updatePlatform(Long userId, Integer userType, String userExt) {
@@ -0,0 +1,146 @@
/**
* 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.controller;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.AllArgsConstructor;
import org.springblade.core.boot.ctrl.BladeController;
import org.springblade.core.mp.support.Condition;
import org.springblade.core.mp.support.Query;
import org.springblade.core.secure.annotation.PreAuth;
import org.springblade.core.tool.api.R;
import org.springblade.transport.pojo.dto.FormalSettlementSaveRequest;
import org.springblade.transport.pojo.dto.FormalSettlementPaymentRequest;
import org.springblade.transport.pojo.dto.FormalSettlementStatusRequest;
import org.springblade.transport.pojo.dto.PreSettlementDetailAdjustRequest;
import org.springblade.transport.pojo.entity.FormalSettlementDetailFee;
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.IPreSettlementService;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
import java.util.Map;
/**
* 正式结算单控制器
*
* @author Chill
*/
@RestController
@AllArgsConstructor
@PreAuth(menu = "formal_settlement")
@RequestMapping("/formal-settlement")
@Tag(name = "正式结算单", description = "正式结算单管理")
public class FormalSettlementController extends BladeController {
private final IFormalSettlementService formalSettlementService;
private final IPreSettlementService preSettlementService;
@GetMapping("/list")
@ApiOperationSupport(order = 1)
@Operation(summary = "正式结算单分页")
public R<IPage<FormalSettlementVO>> list(FormalSettlementVO query, Query pageQuery) {
return R.data(formalSettlementService.selectPage(Condition.getPage(pageQuery), query));
}
@GetMapping("/detail")
@ApiOperationSupport(order = 2)
@Operation(summary = "正式结算单详情")
public R<FormalSettlementVO> detail(@RequestParam Long id) { return R.data(formalSettlementService.detail(id)); }
@GetMapping("/candidate-pre-settlements")
@ApiOperationSupport(order = 3)
@Operation(summary = "可合并的预结算单")
public R<IPage<PreSettlementVO>> candidates(PreSettlementVO query, Query pageQuery) {
return R.data(formalSettlementService.candidatePreSettlements(Condition.getPage(pageQuery), query));
}
@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));
}
@GetMapping("/candidate-details")
@ApiOperationSupport(order = 5)
@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));
}
@PostMapping("/save")
@ApiOperationSupport(order = 6)
@Operation(summary = "保存正式结算草稿")
public R<Long> save(@RequestBody FormalSettlementSaveRequest request) { return R.data(formalSettlementService.saveDraft(request)); }
@PostMapping("/remove")
@ApiOperationSupport(order = 7)
@Operation(summary = "删除正式结算草稿")
public R remove(@RequestParam Long id) { formalSettlementService.removeDraft(id); return R.success("删除成功"); }
@PostMapping("/submit")
@ApiOperationSupport(order = 8)
@Operation(summary = "提交审批")
public R submit(@RequestBody FormalSettlementStatusRequest request) { formalSettlementService.submit(request); return R.success("提交成功"); }
@PostMapping("/approve")
@ApiOperationSupport(order = 9)
@Operation(summary = "审批通过")
public R approve(@RequestBody FormalSettlementStatusRequest request) { formalSettlementService.approve(request); return R.success("审批通过"); }
@PostMapping("/return")
@ApiOperationSupport(order = 10)
@Operation(summary = "审批驳回")
public R returnBill(@RequestBody FormalSettlementStatusRequest request) { formalSettlementService.returnBill(request); return R.success("已驳回"); }
@PostMapping("/void")
@ApiOperationSupport(order = 11)
@Operation(summary = "作废正式结算单")
public R voidBill(@RequestBody FormalSettlementStatusRequest request) { formalSettlementService.voidBill(request); return R.success("作废成功"); }
@PostMapping("/sync-kingdee")
@ApiOperationSupport(order = 12)
@Operation(summary = "推送金蝶应付单")
public R<String> syncKingdee(@RequestParam Long id) { return R.data(formalSettlementService.syncKingdee(id)); }
@GetMapping("/detail-fees")
@ApiOperationSupport(order = 13)
@Operation(summary = "正式结算货物费用快照")
public R<List<FormalSettlementDetailFee>> detailFees(@RequestParam Long detailId) {
return R.data(formalSettlementService.detailFees(detailId));
}
@PostMapping("/adjust-detail")
@ApiOperationSupport(order = 14)
@Operation(summary = "调整草稿结算明细")
public R adjustDetail(@RequestBody PreSettlementDetailAdjustRequest request) {
formalSettlementService.adjustDetail(request);
return R.success("保存成功");
}
@PostMapping("/apply-payment")
@ApiOperationSupport(order = 15)
@Operation(summary = "发起尾款付款申请")
public R<String> applyPayment(@RequestBody FormalSettlementPaymentRequest request) {
return R.data(formalSettlementService.applyPayment(request));
}
}
@@ -0,0 +1,262 @@
/**
* 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>
* 1. This software is for development use only under a valid license
* from BladeX.
* <p>
* 2. Redistribution of this software's source code to any third party
* without a commercial license is strictly prohibited.
* <p>
* 3. Licensees may copyright their own code but cannot use segments
* from this software for such purposes. Copyright of this software
* remains with BladeX.
* <p>
* Using this software signifies agreement to this License, and the software
* must not be used for illegal purposes.
* <p>
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
* not liable for any claims arising from secondary or illegal development.
* <p>
* Author: Chill Zhuang (bladejava@qq.com)
*/
package org.springblade.transport.controller;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.servlet.http.HttpServletResponse;
import lombok.AllArgsConstructor;
import org.springblade.core.boot.ctrl.BladeController;
import org.springblade.core.excel.util.ExcelUtil;
import org.springblade.core.mp.support.Condition;
import org.springblade.core.mp.support.Query;
import org.springblade.core.secure.annotation.PreAuth;
import org.springblade.core.tool.api.R;
import org.springblade.core.tool.utils.DateUtil;
import org.springblade.transport.excel.PreSettlementExcel;
import org.springblade.transport.pojo.dto.PreSettlementAdvanceRequest;
import org.springblade.transport.pojo.dto.PreSettlementDetailAdjustRequest;
import org.springblade.transport.pojo.dto.PreSettlementSaveRequest;
import org.springblade.transport.pojo.dto.PreSettlementStatusRequest;
import org.springblade.transport.pojo.entity.PreSettlementDetailFee;
import org.springblade.transport.pojo.vo.PreSettlementVO;
import org.springblade.transport.service.IPreSettlementService;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.List;
import java.util.Map;
/**
* 预结算单控制器
*
* @author Chill
*/
@RestController
@AllArgsConstructor
@PreAuth(menu = "pre_settlement")
@RequestMapping("/pre-settlement")
@Tag(name = "预结算单", description = "预结算单管理")
public class PreSettlementController extends BladeController {
private final IPreSettlementService preSettlementService;
@GetMapping("/list")
@ApiOperationSupport(order = 1)
@Operation(summary = "预结算单分页")
public R<IPage<PreSettlementVO>> list(PreSettlementVO query, Query pageQuery) {
return R.data(preSettlementService.selectPage(Condition.getPage(pageQuery), query));
}
@GetMapping("/detail")
@ApiOperationSupport(order = 2)
@Operation(summary = "预结算单详情")
public R<PreSettlementVO> detail(@RequestParam Long id) {
return R.data(preSettlementService.detail(id));
}
@GetMapping("/contract-options")
@ApiOperationSupport(order = 3)
@Operation(summary = "可选合同")
public R<List<Map<String, Object>>> contractOptions(@RequestParam(required = false) String keyword) {
return R.data(preSettlementService.contractOptions(keyword));
}
@GetMapping("/fee-options")
@ApiOperationSupport(order = 4)
@Operation(summary = "费用类型及费用项")
public R<List<Map<String, Object>>> feeOptions() {
return R.data(preSettlementService.feeOptions());
}
@GetMapping("/candidate-details")
@ApiOperationSupport(order = 5)
@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));
}
@PostMapping("/save")
@ApiOperationSupport(order = 5)
@Operation(summary = "保存预结算草稿")
public R<Long> save(@RequestBody PreSettlementSaveRequest request) {
return R.data(preSettlementService.saveDraft(request));
}
@PostMapping("/remove")
@ApiOperationSupport(order = 6)
@Operation(summary = "删除预结算草稿")
public R remove(@RequestParam Long id) {
preSettlementService.removeDraft(id);
return R.success("删除成功");
}
@PostMapping("/remove-detail")
@ApiOperationSupport(order = 7)
@Operation(summary = "移除预结算明细")
public R removeDetail(@RequestParam Long id, @RequestParam Long detailId) {
preSettlementService.removeDetail(id, detailId);
return R.success("移除成功");
}
@PostMapping("/submit")
@ApiOperationSupport(order = 8)
@Operation(summary = "提交预结算审批")
public R submit(@RequestBody PreSettlementStatusRequest request) {
preSettlementService.submit(request);
return R.success("审批流程已发起");
}
@PostMapping("/approve")
@ApiOperationSupport(order = 9)
@Operation(summary = "预结算审批通过")
public R approve(@RequestBody PreSettlementStatusRequest request) {
preSettlementService.approve(request);
return R.success("审批通过");
}
@PostMapping("/return")
@ApiOperationSupport(order = 10)
@Operation(summary = "预结算审批驳回")
public R returnBill(@RequestBody PreSettlementStatusRequest request) {
preSettlementService.returnBill(request);
return R.success("已驳回");
}
@PostMapping("/void")
@ApiOperationSupport(order = 11)
@Operation(summary = "作废预结算单")
public R voidBill(@RequestBody PreSettlementStatusRequest request) {
preSettlementService.voidBill(request);
return R.success("作废成功");
}
@PostMapping("/apply-advance")
@ApiOperationSupport(order = 12)
@Operation(summary = "发起预付申请")
public R applyAdvance(@RequestBody PreSettlementAdvanceRequest request) {
preSettlementService.applyAdvance(request);
return R.success("预付申请提交成功");
}
@PostMapping("/update-advance-paid")
@ApiOperationSupport(order = 13)
@Operation(summary = "回写预付付款金额")
public R updateAdvancePaid(@RequestParam Long advanceId, @RequestParam BigDecimal paidAmount,
@RequestParam(required = false) String kingdeeAdvanceNo) {
preSettlementService.updateAdvancePaidAmount(advanceId, paidAmount, kingdeeAdvanceNo);
return R.success("付款金额更新成功");
}
@PostMapping("/void-advance")
@ApiOperationSupport(order = 14)
@Operation(summary = "作废预付申请")
public R voidAdvance(@RequestParam Long advanceId, @RequestParam(required = false) String reason) {
preSettlementService.voidAdvance(advanceId, reason);
return R.success("预付申请作废成功");
}
@PostMapping("/formal-settlement")
@ApiOperationSupport(order = 16)
@Operation(summary = "尾款结算")
public R<String> formalSettlement(@RequestParam Long id) {
return R.data(preSettlementService.formalSettlement(id));
}
@GetMapping("/detail-fees")
@ApiOperationSupport(order = 15)
@Operation(summary = "结算明细费用")
public R<List<PreSettlementDetailFee>> detailFees(@RequestParam Long detailId) {
return R.data(preSettlementService.detailFees(detailId));
}
@PostMapping("/adjust-detail")
@ApiOperationSupport(order = 17)
@Operation(summary = "调整结算明细")
public R adjustDetail(@RequestBody PreSettlementDetailAdjustRequest request) {
preSettlementService.adjustDetail(request);
return R.success("保存成功");
}
@GetMapping("/print-templates")
@ApiOperationSupport(order = 18)
@Operation(summary = "预结算打印模板")
public R<List<Map<String, String>>> printTemplates(@RequestParam Long id) {
return R.data(preSettlementService.printTemplates(id));
}
@GetMapping("/export")
@ApiOperationSupport(order = 19)
@Operation(summary = "导出预结算单")
public void export(PreSettlementVO query, HttpServletResponse response) {
IPage<PreSettlementVO> page = preSettlementService.selectPage(new Page<>(1, 100000), query);
List<PreSettlementExcel> rows = page.getRecords().stream().map(this::toExcel).toList();
ExcelUtil.export(response, "预结算单" + DateUtil.time(), "预结算单", rows, PreSettlementExcel.class);
}
private PreSettlementExcel toExcel(PreSettlementVO vo) {
PreSettlementExcel excel = new PreSettlementExcel();
excel.setPreSettlementNo(vo.getPreSettlementNo());
excel.setSourceType(vo.getSourceType());
excel.setPayerName(vo.getPayerName());
excel.setPayeeName(vo.getPayeeName());
excel.setProjectName(vo.getProjectName());
excel.setDeptName(vo.getDeptName());
excel.setContractNo(vo.getContractNo());
excel.setContractName(vo.getContractName());
excel.setSettlementAmount(formatMoney(vo.getSettlementAmount(), vo.getCurrency()));
excel.setLocalSettlementAmount(formatMoney(vo.getLocalSettlementAmount(), vo.getLocalCurrency()));
excel.setExchangeRate(vo.getExchangeRate() == null ? "" : vo.getExchangeRate().stripTrailingZeros().toPlainString());
excel.setAdvanceAppliedAmount(formatMoney(vo.getAdvanceAppliedAmount(), vo.getCurrency()));
excel.setAdvancePaidAmount(formatMoney(vo.getAdvancePaidAmount(), vo.getCurrency()));
excel.setApprovalStatusName(vo.getApprovalStatusName());
excel.setCurrentNode(vo.getCurrentNode());
excel.setCurrentProcessor(vo.getCurrentProcessor());
excel.setCreateUserName(vo.getCreateUserName());
excel.setCreateTime(vo.getCreateTime());
return excel;
}
private String formatMoney(BigDecimal value, String currency) {
if (value == null) return "";
return value.setScale(2, RoundingMode.HALF_UP).toPlainString() + " " +
(currency == null || currency.isBlank() ? "RMB" : currency);
}
}
@@ -0,0 +1,72 @@
/**
* 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.excel;
import cn.idev.excel.annotation.ExcelProperty;
import cn.idev.excel.annotation.write.style.ColumnWidth;
import cn.idev.excel.annotation.write.style.ContentRowHeight;
import cn.idev.excel.annotation.write.style.HeadRowHeight;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
import java.util.Date;
/**
* 预结算单 Excel
*
* @author Chill
*/
@Data
@ColumnWidth(22)
@HeadRowHeight(20)
@ContentRowHeight(18)
public class PreSettlementExcel implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
@ExcelProperty("预结算单号")
private String preSettlementNo;
@ExcelProperty("来源")
private String sourceType;
@ExcelProperty("付款方")
private String payerName;
@ExcelProperty("收款方")
private String payeeName;
@ExcelProperty("项目名称")
private String projectName;
@ExcelProperty("所属组织")
private String deptName;
@ExcelProperty("合同编号")
private String contractNo;
@ExcelProperty("合同名称")
private String contractName;
@ExcelProperty("原币结算金额")
private String settlementAmount;
@ExcelProperty("本位币结算金额")
private String localSettlementAmount;
@ExcelProperty("结算汇率")
private String exchangeRate;
@ExcelProperty("申请预付金额")
private String advanceAppliedAmount;
@ExcelProperty("已付款金额")
private String advancePaidAmount;
@ExcelProperty("审核状态")
private String approvalStatusName;
@ExcelProperty("当前节点")
private String currentNode;
@ExcelProperty("当前处理人")
private String currentProcessor;
@ExcelProperty("创建人")
private String createUserName;
@ExcelProperty("创建时间")
private Date createTime;
}
@@ -0,0 +1,18 @@
/**
* 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.apache.ibatis.annotations.Mapper;
import org.springblade.transport.pojo.entity.FormalSettlementDetailFee;
/** 正式结算货物费用 Mapper。 @author Chill */
@Mapper
public interface FormalSettlementDetailFeeMapper extends BaseMapper<FormalSettlementDetailFee> {
}
@@ -0,0 +1,18 @@
/**
* 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.apache.ibatis.annotations.Mapper;
import org.springblade.transport.pojo.entity.FormalSettlementDetail;
/** 正式结算明细 Mapper。 @author Chill */
@Mapper
public interface FormalSettlementDetailMapper extends BaseMapper<FormalSettlementDetail> {
}
@@ -0,0 +1,18 @@
/**
* 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.apache.ibatis.annotations.Mapper;
import org.springblade.transport.pojo.entity.FormalSettlement;
/** 正式结算单 Mapper。 @author Chill */
@Mapper
public interface FormalSettlementMapper extends BaseMapper<FormalSettlement> {
}
@@ -0,0 +1,18 @@
/**
* 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.apache.ibatis.annotations.Mapper;
import org.springblade.transport.pojo.entity.FormalSettlementPayment;
/** 正式结算付款申请 Mapper。 @author Chill */
@Mapper
public interface FormalSettlementPaymentMapper extends BaseMapper<FormalSettlementPayment> {
}
@@ -0,0 +1,18 @@
/**
* 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.apache.ibatis.annotations.Mapper;
import org.springblade.transport.pojo.entity.FormalSettlementSource;
/** 正式结算来源 Mapper。 @author Chill */
@Mapper
public interface FormalSettlementSourceMapper extends BaseMapper<FormalSettlementSource> {
}
@@ -0,0 +1,22 @@
/**
* 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.apache.ibatis.annotations.Mapper;
import org.springblade.transport.pojo.entity.PreSettlementAdvance;
/**
* 预结算预付记录 Mapper
*
* @author Chill
*/
@Mapper
public interface PreSettlementAdvanceMapper extends BaseMapper<PreSettlementAdvance> {
}
@@ -0,0 +1,22 @@
/**
* 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.apache.ibatis.annotations.Mapper;
import org.springblade.transport.pojo.entity.PreSettlementChangeRecord;
/**
* 预结算变更记录 Mapper
*
* @author Chill
*/
@Mapper
public interface PreSettlementChangeRecordMapper extends BaseMapper<PreSettlementChangeRecord> {
}
@@ -0,0 +1,22 @@
/**
* 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.apache.ibatis.annotations.Mapper;
import org.springblade.transport.pojo.entity.PreSettlementDetailFee;
/**
* 预结算明细费用 Mapper
*
* @author Chill
*/
@Mapper
public interface PreSettlementDetailFeeMapper extends BaseMapper<PreSettlementDetailFee> {
}
@@ -0,0 +1,22 @@
/**
* 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.apache.ibatis.annotations.Mapper;
import org.springblade.transport.pojo.entity.PreSettlementDetail;
/**
* 预结算明细 Mapper
*
* @author Chill
*/
@Mapper
public interface PreSettlementDetailMapper extends BaseMapper<PreSettlementDetail> {
}
@@ -0,0 +1,22 @@
/**
* 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.apache.ibatis.annotations.Mapper;
import org.springblade.transport.pojo.entity.PreSettlement;
/**
* 预结算单 Mapper
*
* @author Chill
*/
@Mapper
public interface PreSettlementMapper extends BaseMapper<PreSettlement> {
}
@@ -0,0 +1,22 @@
/**
* 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.apache.ibatis.annotations.Mapper;
import org.springblade.transport.pojo.entity.PreSettlementSummaryFee;
/**
* 预结算合计费用 Mapper
*
* @author Chill
*/
@Mapper
public interface PreSettlementSummaryFeeMapper extends BaseMapper<PreSettlementSummaryFee> {
}
@@ -0,0 +1,43 @@
/**
* 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.service;
import com.baomidou.mybatisplus.core.metadata.IPage;
import org.springblade.core.mp.base.BaseService;
import org.springblade.transport.pojo.dto.FormalSettlementSaveRequest;
import org.springblade.transport.pojo.dto.FormalSettlementStatusRequest;
import org.springblade.transport.pojo.entity.FormalSettlement;
import org.springblade.transport.pojo.vo.FormalSettlementVO;
import org.springblade.transport.pojo.vo.PreSettlementVO;
import org.springblade.transport.pojo.entity.PreSettlement;
import org.springblade.transport.pojo.dto.PreSettlementDetailAdjustRequest;
import org.springblade.transport.pojo.entity.FormalSettlementDetailFee;
import java.util.List;
import org.springblade.transport.pojo.dto.FormalSettlementPaymentRequest;
/**
* 正式结算单服务
*
* @author Chill
*/
public interface IFormalSettlementService extends BaseService<FormalSettlement> {
IPage<FormalSettlementVO> selectPage(IPage<FormalSettlement> page, FormalSettlementVO query);
IPage<PreSettlementVO> candidatePreSettlements(IPage<PreSettlement> page, PreSettlementVO query);
FormalSettlementVO detail(Long id);
Long saveDraft(FormalSettlementSaveRequest request);
void removeDraft(Long id);
void submit(FormalSettlementStatusRequest request);
void approve(FormalSettlementStatusRequest request);
void returnBill(FormalSettlementStatusRequest request);
void voidBill(FormalSettlementStatusRequest request);
String syncKingdee(Long id);
List<FormalSettlementDetailFee> detailFees(Long detailId);
void adjustDetail(PreSettlementDetailAdjustRequest request);
String applyPayment(FormalSettlementPaymentRequest request);
}
@@ -0,0 +1,71 @@
/**
* 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.service;
import com.baomidou.mybatisplus.core.metadata.IPage;
import org.springblade.core.mp.base.BaseService;
import org.springblade.transport.pojo.dto.PreSettlementAdvanceRequest;
import org.springblade.transport.pojo.dto.PreSettlementDetailAdjustRequest;
import org.springblade.transport.pojo.dto.PreSettlementSaveRequest;
import org.springblade.transport.pojo.dto.PreSettlementStatusRequest;
import org.springblade.transport.pojo.entity.PreSettlement;
import org.springblade.transport.pojo.entity.PreSettlementDetailFee;
import org.springblade.transport.pojo.vo.PreSettlementVO;
import java.math.BigDecimal;
import java.util.List;
import java.util.Map;
/**
* 预结算单服务
*
* @author Chill
*/
public interface IPreSettlementService extends BaseService<PreSettlement> {
IPage<PreSettlementVO> selectPage(IPage<PreSettlement> page, PreSettlementVO query);
PreSettlementVO detail(Long id);
List<Map<String, Object>> contractOptions(String keyword);
List<Map<String, Object>> feeOptions();
IPage<Map<String, Object>> candidateDetails(IPage<?> page, Long contractId, String settlementType,
String batchNo, String feeStartDate, String feeEndDate);
Long saveDraft(PreSettlementSaveRequest request);
void removeDraft(Long id);
void removeDetail(Long id, Long detailId);
void submit(PreSettlementStatusRequest request);
void approve(PreSettlementStatusRequest request);
void returnBill(PreSettlementStatusRequest request);
void voidBill(PreSettlementStatusRequest request);
void applyAdvance(PreSettlementAdvanceRequest request);
void updateAdvancePaidAmount(Long advanceId, BigDecimal paidAmount, String kingdeeAdvanceNo);
void voidAdvance(Long advanceId, String reason);
String formalSettlement(Long id);
List<PreSettlementDetailFee> detailFees(Long detailId);
void adjustDetail(PreSettlementDetailAdjustRequest request);
List<Map<String, String>> printTemplates(Long id);
}
@@ -0,0 +1,511 @@
/**
* 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.service.impl;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.RequiredArgsConstructor;
import org.springblade.core.log.exception.ServiceException;
import org.springblade.core.mp.base.BaseServiceImpl;
import org.springblade.core.secure.utils.AuthUtil;
import org.springblade.core.tool.utils.BeanUtil;
import org.springblade.core.tool.utils.Func;
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.FormalSettlementPaymentMapper;
import org.springblade.transport.mapper.PreSettlementDetailMapper;
import org.springblade.transport.mapper.PreSettlementDetailFeeMapper;
import org.springblade.transport.mapper.PreSettlementMapper;
import org.springblade.transport.mapper.ReceivablePayableDetailMapper;
import org.springblade.transport.mapper.ReceivablePayableCargoFeeMapper;
import org.springblade.transport.pojo.dto.FormalSettlementSaveRequest;
import org.springblade.transport.pojo.dto.FormalSettlementPaymentRequest;
import org.springblade.transport.pojo.dto.FormalSettlementStatusRequest;
import org.springblade.transport.pojo.dto.PreSettlementDetailAdjustRequest;
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.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.ReceivablePayableDetail;
import org.springblade.transport.pojo.entity.ReceivablePayableCargoFee;
import org.springblade.transport.pojo.entity.Waybill;
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.IWaybillService;
import org.springblade.transport.wrapper.PreSettlementWrapper;
import org.springblade.core.tool.jackson.JsonUtil;
import org.springblade.transport.wrapper.FormalSettlementWrapper;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;
/**
* 正式结算单服务实现类
*
* @author Chill
*/
@Service
@RequiredArgsConstructor
public class FormalSettlementServiceImpl extends BaseServiceImpl<FormalSettlementMapper, FormalSettlement>
implements IFormalSettlementService {
private static final String DRAFT = "draft";
private static final String REVIEWING = "reviewing";
private static final String APPROVED = "approved";
private static final String RETURNED = "returned";
private static final String VOIDED = "voided";
private final FormalSettlementSourceMapper sourceMapper;
private final FormalSettlementPaymentMapper paymentMapper;
private final FormalSettlementDetailMapper detailMapper;
private final FormalSettlementDetailFeeMapper detailFeeMapper;
private final PreSettlementMapper preSettlementMapper;
private final PreSettlementDetailMapper preDetailMapper;
private final PreSettlementDetailFeeMapper preDetailFeeMapper;
private final ReceivablePayableDetailMapper receivablePayableMapper;
private final ReceivablePayableCargoFeeMapper receivablePayableCargoFeeMapper;
private final IContractManageService contractManageService;
private final IWaybillService waybillService;
@Override
public IPage<FormalSettlementVO> selectPage(IPage<FormalSettlement> page, FormalSettlementVO query) {
LambdaQueryWrapper<FormalSettlement> wrapper = Wrappers.<FormalSettlement>lambdaQuery()
.like(Func.isNotEmpty(query.getFormalSettlementNo()), FormalSettlement::getFormalSettlementNo, query.getFormalSettlementNo())
.like(Func.isNotEmpty(query.getProjectName()), FormalSettlement::getProjectName, query.getProjectName())
.like(Func.isNotEmpty(query.getDeptName()), FormalSettlement::getDeptName, query.getDeptName())
.like(Func.isNotEmpty(query.getContractNo()), FormalSettlement::getContractNo, query.getContractNo())
.like(Func.isNotEmpty(query.getContractName()), FormalSettlement::getContractName, query.getContractName())
.like(Func.isNotEmpty(query.getPayerName()), FormalSettlement::getPayerName, query.getPayerName())
.like(Func.isNotEmpty(query.getPayeeName()), FormalSettlement::getPayeeName, query.getPayeeName())
.eq(Func.isNotEmpty(query.getSettlementType()), FormalSettlement::getSettlementType, query.getSettlementType())
.eq(Func.isNotEmpty(query.getInvoiceStatus()), FormalSettlement::getInvoiceStatus, query.getInvoiceStatus())
.eq(Func.isNotEmpty(query.getPaymentStatus()), FormalSettlement::getPaymentStatus, query.getPaymentStatus())
.eq(Func.isNotEmpty(query.getKingdeeSyncStatus()), FormalSettlement::getKingdeeSyncStatus, query.getKingdeeSyncStatus())
.eq(Func.isNotEmpty(query.getApprovalStatus()), FormalSettlement::getApprovalStatus, query.getApprovalStatus())
.ge(query.getCreateStartDate() != null, FormalSettlement::getCreateTime, query.getCreateStartDate() == null ? null : query.getCreateStartDate().atStartOfDay())
.lt(query.getCreateEndDate() != null, FormalSettlement::getCreateTime, query.getCreateEndDate() == null ? null : query.getCreateEndDate().plusDays(1).atStartOfDay());
if (Func.isNotEmpty(query.getPreSettlementNo())) {
List<Long> ids = sourceMapper.selectList(Wrappers.<FormalSettlementSource>lambdaQuery()
.like(FormalSettlementSource::getPreSettlementNo, query.getPreSettlementNo()))
.stream().map(FormalSettlementSource::getFormalSettlementId).distinct().toList();
if (ids.isEmpty()) wrapper.eq(FormalSettlement::getId, -1L); else wrapper.in(FormalSettlement::getId, ids);
}
IPage<FormalSettlement> result = page(page, wrapper.orderByDesc(FormalSettlement::getCreateTime));
return result.convert(this::toVO);
}
@Override
public IPage<PreSettlementVO> candidatePreSettlements(IPage<PreSettlement> page, PreSettlementVO query) {
IPage<PreSettlement> result = preSettlementMapper.selectPage(page, Wrappers.<PreSettlement>lambdaQuery()
.eq(PreSettlement::getApprovalStatus, APPROVED)
.and(w -> w.isNull(PreSettlement::getFormalSettlementNo).or().eq(PreSettlement::getFormalSettlementNo, ""))
.eq(query.getContractId() != null, PreSettlement::getContractId, query.getContractId())
.like(Func.isNotEmpty(query.getPreSettlementNo()), PreSettlement::getPreSettlementNo, query.getPreSettlementNo())
.like(Func.isNotEmpty(query.getContractNo()), PreSettlement::getContractNo, query.getContractNo())
.like(Func.isNotEmpty(query.getContractName()), PreSettlement::getContractName, query.getContractName())
.orderByDesc(PreSettlement::getCreateTime));
return PreSettlementWrapper.build().pageVO(result);
}
@Override
public FormalSettlementVO detail(Long id) {
FormalSettlement settlement = existing(id);
FormalSettlementVO vo = toVO(settlement);
vo.setSources(sourceMapper.selectList(Wrappers.<FormalSettlementSource>lambdaQuery()
.eq(FormalSettlementSource::getFormalSettlementId, id).orderByAsc(FormalSettlementSource::getCreateTime)));
vo.setDetails(detailMapper.selectList(Wrappers.<FormalSettlementDetail>lambdaQuery()
.eq(FormalSettlementDetail::getFormalSettlementId, id).orderByAsc(FormalSettlementDetail::getLineNo)));
vo.setPayments(paymentMapper.selectList(Wrappers.<FormalSettlementPayment>lambdaQuery()
.eq(FormalSettlementPayment::getFormalSettlementId, id).orderByDesc(FormalSettlementPayment::getCreateTime)));
return vo;
}
@Override
@Transactional(rollbackFor = Exception.class)
public Long saveDraft(FormalSettlementSaveRequest request) {
if (Func.isEmpty(request.getSourcePreSettlementIds()) && Func.isEmpty(request.getSourceDetailIds())) {
throw new ServiceException("请至少选择一张预结算单或一条应收应付明细");
}
FormalSettlement settlement = request.getId() == null ? new FormalSettlement() : editable(request.getId());
if (settlement.getId() != null) releaseSources(settlement);
List<PreSettlement> sources = Func.isEmpty(request.getSourcePreSettlementIds()) ? List.of()
: request.getSourcePreSettlementIds().stream().distinct().map(this::availableSource).toList();
List<ReceivablePayableDetail> directDetails = Func.isEmpty(request.getSourceDetailIds()) ? List.of()
: request.getSourceDetailIds().stream().distinct().map(this::availableDetail).toList();
Long contractId = sources.isEmpty() ? request.getContractId() : sources.get(0).getContractId();
String settlementType = sources.isEmpty() ? request.getSettlementType() : sources.get(0).getSettlementType();
if (contractId == null || Func.isEmpty(settlementType)) throw new ServiceException("请选择合同并确认结算类型");
if (sources.stream().anyMatch(item -> !Objects.equals(contractId, item.getContractId())
|| !Objects.equals(settlementType, item.getSettlementType()))
|| directDetails.stream().anyMatch(item -> !Objects.equals(contractId, item.getContractId())
|| !Objects.equals(settlementType, item.getSettlementType())
|| (!sources.isEmpty() && !Objects.equals(sources.get(0).getCurrency(), item.getCurrency())))) {
throw new ServiceException("合并的预结算单必须属于同一合同、结算类型及币种");
}
PreSettlement first = sources.isEmpty() ? null : sources.get(0);
ContractManage contract = contractManageService.getById(contractId);
if (contract == null || Objects.equals(contract.getIsDeleted(), 1)) throw new ServiceException("合同不存在");
if (settlement.getId() == null) {
settlement.setFormalSettlementNo(nextNo());
settlement.setApprovalStatus(DRAFT);
settlement.setCurrentNode("草稿");
settlement.setSourceType(sources.isEmpty() ? "应收应付" : directDetails.isEmpty() ? "预结算合并" : "混合来源");
settlement.setInvoiceStatus("unreceived");
settlement.setPaymentStatus("unpaid");
settlement.setKingdeeSyncStatus("unsynced");
}
if (first == null) copyHeader(contract, settlementType, directDetails.get(0), settlement); else copyHeader(first, settlement);
settlement.setExchangeRateDate(request.getExchangeRateDate());
settlement.setExchangeRate(request.getExchangeRate() == null ? BigDecimal.ONE : positive(request.getExchangeRate(), "结算汇率"));
BigDecimal sourceAmount = sources.stream().map(PreSettlement::getSettlementAmount).map(this::money).reduce(BigDecimal.ZERO, BigDecimal::add);
BigDecimal detailAmount = directDetails.stream().map(ReceivablePayableDetail::getTotalAmount).map(this::money).reduce(BigDecimal.ZERO, BigDecimal::add);
settlement.setSettlementAmount(sourceAmount.add(detailAmount));
settlement.setAppliedPaymentAmount(sources.stream().map(PreSettlement::getAdvanceAppliedAmount)
.map(this::money).reduce(BigDecimal.ZERO, BigDecimal::add));
settlement.setPaidAmount(sources.stream().map(PreSettlement::getAdvancePaidAmount)
.map(this::money).reduce(BigDecimal.ZERO, BigDecimal::add));
settlement.setLocalSettlementAmount(settlement.getSettlementAmount().multiply(settlement.getExchangeRate()));
settlement.setAttachmentsJson(request.getAttachmentsJson());
settlement.setRemark(limit(request.getRemark(), 200));
saveOrUpdate(settlement);
rebuildSnapshots(settlement, sources, directDetails);
return settlement.getId();
}
@Override @Transactional(rollbackFor = Exception.class)
public void removeDraft(Long id) {
FormalSettlement settlement = editable(id);
releaseSources(settlement);
sourceMapper.delete(Wrappers.<FormalSettlementSource>lambdaQuery().eq(FormalSettlementSource::getFormalSettlementId, id));
List<Long> detailIds = detailMapper.selectList(Wrappers.<FormalSettlementDetail>lambdaQuery()
.eq(FormalSettlementDetail::getFormalSettlementId, id)).stream().map(FormalSettlementDetail::getId).toList();
if (!detailIds.isEmpty()) detailFeeMapper.delete(Wrappers.<FormalSettlementDetailFee>lambdaQuery()
.in(FormalSettlementDetailFee::getFormalSettlementDetailId, detailIds));
detailMapper.delete(Wrappers.<FormalSettlementDetail>lambdaQuery().eq(FormalSettlementDetail::getFormalSettlementId, id));
removeById(id);
}
@Override public void submit(FormalSettlementStatusRequest request) { changeStatus(request.getId(), DRAFT, REVIEWING, "财务审核", null); }
@Override public void returnBill(FormalSettlementStatusRequest request) { changeStatus(request.getId(), REVIEWING, RETURNED, "已驳回", request.getReason()); }
@Override
public void approve(FormalSettlementStatusRequest request) {
FormalSettlement settlement = existing(request.getId());
if (!REVIEWING.equals(settlement.getApprovalStatus())) throw new ServiceException("仅审批中的正式结算单允许审核");
settlement.setApprovalStatus(APPROVED);
settlement.setCurrentNode("审批通过");
settlement.setCurrentProcessor(AuthUtil.getUserName());
settlement.setApprovedTime(LocalDateTime.now());
updateById(settlement);
}
@Override
public void voidBill(FormalSettlementStatusRequest request) {
FormalSettlement settlement = existing(request.getId());
if (!APPROVED.equals(settlement.getApprovalStatus())) throw new ServiceException("仅审批通过的正式结算单允许作废");
if ("synced".equals(settlement.getKingdeeSyncStatus())) throw new ServiceException("已同步金蝶的正式结算单不能直接作废");
settlement.setApprovalStatus(VOIDED);
settlement.setCurrentNode("已作废");
settlement.setVoidReason(required(limit(request.getReason(), 200), "作废原因"));
updateById(settlement);
}
@Override
public String syncKingdee(Long id) {
FormalSettlement settlement = existing(id);
if (!APPROVED.equals(settlement.getApprovalStatus())) throw new ServiceException("仅审批通过的正式结算单允许同步金蝶");
if ("synced".equals(settlement.getKingdeeSyncStatus())) return settlement.getKingdeeBillNo();
String kingdeeNo = "K3AP" + DateTimeFormatter.ofPattern("yyyyMMddHHmmss").format(LocalDateTime.now());
settlement.setKingdeeBillNo(kingdeeNo);
settlement.setKingdeeSyncStatus("synced");
settlement.setSyncedTime(LocalDateTime.now());
updateById(settlement);
return kingdeeNo;
}
@Override
@Transactional(rollbackFor = Exception.class)
public String applyPayment(FormalSettlementPaymentRequest request) {
FormalSettlement settlement = existing(request.getId());
if (!APPROVED.equals(settlement.getApprovalStatus())) throw new ServiceException("仅审批通过的正式结算单允许发起付款申请");
if (!"payable".equals(settlement.getSettlementType())) throw new ServiceException("仅应付正式结算单允许发起付款申请");
BigDecimal amount = positive(request.getAppliedAmount(), "申请付款金额");
BigDecimal available = money(settlement.getSettlementAmount()).subtract(money(settlement.getAppliedPaymentAmount()));
if (amount.compareTo(available) > 0) throw new ServiceException("申请付款金额不能超过剩余可申请金额" + available);
FormalSettlementPayment payment = new FormalSettlementPayment();
payment.setFormalSettlementId(settlement.getId());
payment.setPaymentNo(nextPaymentNo());
payment.setPaymentType("final");
payment.setAppliedAmount(amount);
payment.setPaidAmount(BigDecimal.ZERO);
payment.setBillStatus(REVIEWING);
payment.setRemark(limit(request.getRemark(), 200));
paymentMapper.insert(payment);
settlement.setAppliedPaymentAmount(money(settlement.getAppliedPaymentAmount()).add(amount));
updateById(settlement);
return payment.getPaymentNo();
}
@Override
public List<FormalSettlementDetailFee> detailFees(Long detailId) {
FormalSettlementDetail detail = detailMapper.selectById(detailId);
if (detail == null || Objects.equals(detail.getIsDeleted(), 1)) throw new ServiceException("正式结算明细不存在");
return detailFeeMapper.selectList(Wrappers.<FormalSettlementDetailFee>lambdaQuery()
.eq(FormalSettlementDetailFee::getFormalSettlementDetailId, detailId)
.orderByAsc(FormalSettlementDetailFee::getLineNo));
}
@Override
@Transactional(rollbackFor = Exception.class)
public void adjustDetail(PreSettlementDetailAdjustRequest request) {
FormalSettlementDetail detail = detailMapper.selectById(request.getDetailId());
if (detail == null || Objects.equals(detail.getIsDeleted(), 1)) throw new ServiceException("正式结算明细不存在");
FormalSettlement settlement = editable(detail.getFormalSettlementId());
if (Func.isEmpty(request.getRows())) throw new ServiceException("请填写需要调整的货物费用行");
String reason = required(limit(request.getChangeReason(), 200), "调整原因");
Map<Long, FormalSettlementDetailFee> existing = detailFees(detail.getId()).stream()
.collect(Collectors.toMap(FormalSettlementDetailFee::getId, item -> item));
if (existing.size() != request.getRows().size()) throw new ServiceException("费用调整行数据不完整");
for (PreSettlementDetailAdjustRequest.FeeRow row : request.getRows()) {
FormalSettlementDetailFee fee = existing.get(row.getId());
if (fee == null) throw new ServiceException("存在无效的货物费用行");
fee.setTransportQuantity(nonNegative(row.getTransportQuantity(), "运输总量"));
fee.setMileage(nonNegative(row.getMileage(), "里程"));
fee.setUnitPrice(nonNegative(row.getUnitPrice(), "运输单价"));
fee.setFreightAmount(nonNegative(row.getFreightAmount(), "运费"));
fee.setFeeItemsJson(JsonUtil.toJson(row.getFeeItems() == null ? java.util.Map.of() : row.getFeeItems()));
fee.setSettlementAmountTax(nonNegative(row.getSettlementAmountTax(), "结算金额(含税)"));
fee.setSettlementAmountNoTax(row.getSettlementAmountNoTax() == null ? null : nonNegative(row.getSettlementAmountNoTax(), "结算金额(不含税)"));
fee.setAdjustAmount(fee.getSettlementAmountTax().subtract(money(fee.getOriginalAmount())));
fee.setRemark(limit(row.getRemark(), 200));
detailFeeMapper.updateById(fee);
}
List<FormalSettlementDetailFee> rows = detailFees(detail.getId());
detail.setTransportQuantity(rows.stream().map(FormalSettlementDetailFee::getTransportQuantity).filter(Objects::nonNull).reduce(BigDecimal.ZERO, BigDecimal::add));
detail.setFreightAmount(rows.stream().map(FormalSettlementDetailFee::getFreightAmount).map(this::money).reduce(BigDecimal.ZERO, BigDecimal::add));
detail.setOriginalAmount(rows.stream().map(FormalSettlementDetailFee::getOriginalAmount).map(this::money).reduce(BigDecimal.ZERO, BigDecimal::add));
detail.setSettlementAmountTax(rows.stream().map(FormalSettlementDetailFee::getSettlementAmountTax).map(this::money).reduce(BigDecimal.ZERO, BigDecimal::add));
detail.setSettlementAmountNoTax(rows.stream().map(FormalSettlementDetailFee::getSettlementAmountNoTax).filter(Objects::nonNull).reduce(BigDecimal.ZERO, BigDecimal::add));
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);
settlement.setSettlementAmount(amount);
settlement.setLocalSettlementAmount(amount.multiply(settlement.getExchangeRate() == null ? BigDecimal.ONE : settlement.getExchangeRate()));
updateById(settlement);
}
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();
if (!existingDetailIds.isEmpty()) detailFeeMapper.delete(Wrappers.<FormalSettlementDetailFee>lambdaQuery()
.in(FormalSettlementDetailFee::getFormalSettlementDetailId, existingDetailIds));
sourceMapper.delete(Wrappers.<FormalSettlementSource>lambdaQuery().eq(FormalSettlementSource::getFormalSettlementId, settlement.getId()));
detailMapper.delete(Wrappers.<FormalSettlementDetail>lambdaQuery().eq(FormalSettlementDetail::getFormalSettlementId, settlement.getId()));
int lineNo = 1;
for (PreSettlement source : sources) {
FormalSettlementSource relation = new FormalSettlementSource();
relation.setFormalSettlementId(settlement.getId()); relation.setPreSettlementId(source.getId());
relation.setPreSettlementNo(source.getPreSettlementNo()); relation.setSettlementAmount(source.getSettlementAmount());
relation.setAdvanceAppliedAmount(source.getAdvanceAppliedAmount()); relation.setAdvancePaidAmount(source.getAdvancePaidAmount());
sourceMapper.insert(relation);
int reserved = preSettlementMapper.update(null, Wrappers.<PreSettlement>lambdaUpdate()
.eq(PreSettlement::getId, source.getId())
.eq(PreSettlement::getApprovalStatus, APPROVED)
.and(w -> w.isNull(PreSettlement::getFormalSettlementNo).or().eq(PreSettlement::getFormalSettlementNo, ""))
.set(PreSettlement::getFormalSettlementNo, settlement.getFormalSettlementNo())
.set(PreSettlement::getFormalSettledTime, LocalDateTime.now())
.set(PreSettlement::getCurrentNode, "已锁定(正式结算)"));
if (reserved != 1) throw new ServiceException("预结算单" + source.getPreSettlementNo() + "已被其他正式结算占用");
for (PreSettlementDetail item : preDetailMapper.selectList(Wrappers.<PreSettlementDetail>lambdaQuery().eq(PreSettlementDetail::getPreSettlementId, source.getId()))) {
FormalSettlementDetail detail = Objects.requireNonNull(BeanUtil.copyProperties(item, FormalSettlementDetail.class));
detail.setId(null); detail.setFormalSettlementId(settlement.getId()); detail.setSourcePreSettlementId(source.getId());
detail.setSourcePreSettlementDetailId(item.getId()); detail.setLineNo(lineNo++); detailMapper.insert(detail);
copyPreDetailFees(item, detail);
ReceivablePayableDetail original = receivablePayableMapper.selectById(item.getSourceDetailId());
if (original != null) { original.setFormalSettlementNo(settlement.getFormalSettlementNo()); original.setSettlementStatus("formal_settled"); receivablePayableMapper.updateById(original); }
}
}
for (ReceivablePayableDetail source : directDetails) {
FormalSettlementDetail detail = new FormalSettlementDetail();
detail.setFormalSettlementId(settlement.getId()); detail.setSourceDetailId(source.getId()); detail.setLineNo(lineNo++);
detail.setDocumentNo(source.getDocumentNo()); detail.setWaybillId(source.getWaybillId()); detail.setWaybillNo(source.getWaybillNo());
detail.setVehicleNo(source.getVehicleNo()); detail.setTransportType(source.getTransportType()); detail.setCargoName(source.getCargoName());
detail.setCargoType(source.getCargoType()); detail.setTransportQuantity(source.getTransportQuantity()); detail.setQuantityUnit(source.getQuantityUnit());
detail.setMileage(source.getMileage()); detail.setBatchNo(source.getBatchNo()); detail.setUnitPrice(source.getUnitPrice());
detail.setFreightAmount(money(source.getFreightAmount())); detail.setFeeItemsJson(source.getFeeItemsJson());
detail.setOriginalAmount(money(source.getTotalAmount())); detail.setAdjustAmount(BigDecimal.ZERO);
detail.setSettlementAmountTax(money(source.getTotalAmount())); detail.setCurrency(Func.isEmpty(source.getCurrency()) ? "RMB" : source.getCurrency());
Waybill waybill = source.getWaybillId() == null ? null : waybillService.getById(source.getWaybillId());
if (waybill != null) {
detail.setDepartureAddress(Func.isNotEmpty(waybill.getDepartureAddress()) ? waybill.getDepartureAddress() : waybill.getDepartureName());
detail.setArrivalAddress(Func.isNotEmpty(waybill.getArrivalAddress()) ? waybill.getArrivalAddress() : waybill.getArrivalName());
detail.setActualDepartureTime(waybill.getStartDate() == null ? null : waybill.getStartDate().atStartOfDay());
detail.setActualCompletionTime(waybill.getEndDate() == null ? null : waybill.getEndDate().atStartOfDay());
}
detail.setRemark(source.getRemark()); detailMapper.insert(detail);
copyDirectDetailFees(source, detail);
int affected = receivablePayableMapper.update(null, Wrappers.<ReceivablePayableDetail>lambdaUpdate()
.eq(ReceivablePayableDetail::getId, source.getId())
.eq(ReceivablePayableDetail::getSettlementStatus, "pending")
.and(w -> w.isNull(ReceivablePayableDetail::getPreSettlementNo).or().eq(ReceivablePayableDetail::getPreSettlementNo, ""))
.and(w -> w.isNull(ReceivablePayableDetail::getFormalSettlementNo).or().eq(ReceivablePayableDetail::getFormalSettlementNo, ""))
.set(ReceivablePayableDetail::getFormalSettlementNo, settlement.getFormalSettlementNo())
.set(ReceivablePayableDetail::getSettlementStatus, "formal_settled"));
if (affected != 1) throw new ServiceException("单据" + source.getDocumentNo() + "已被其他结算单选择");
}
}
private void copyPreDetailFees(PreSettlementDetail source, FormalSettlementDetail target) {
List<PreSettlementDetailFee> fees = preDetailFeeMapper.selectList(Wrappers.<PreSettlementDetailFee>lambdaQuery()
.eq(PreSettlementDetailFee::getPreSettlementDetailId, source.getId()).orderByAsc(PreSettlementDetailFee::getLineNo));
for (PreSettlementDetailFee item : fees) {
FormalSettlementDetailFee fee = Objects.requireNonNull(BeanUtil.copyProperties(item, FormalSettlementDetailFee.class));
fee.setId(null); fee.setFormalSettlementDetailId(target.getId()); fee.setSourceFeeId(item.getId()); detailFeeMapper.insert(fee);
}
if (fees.isEmpty()) createSingleFee(target);
}
private void copyDirectDetailFees(ReceivablePayableDetail source, FormalSettlementDetail target) {
List<ReceivablePayableCargoFee> fees = receivablePayableCargoFeeMapper.selectList(Wrappers.<ReceivablePayableCargoFee>lambdaQuery()
.eq(ReceivablePayableCargoFee::getDetailId, source.getId()).orderByAsc(ReceivablePayableCargoFee::getLineNo));
for (ReceivablePayableCargoFee item : fees) {
FormalSettlementDetailFee fee = Objects.requireNonNull(BeanUtil.copyProperties(item, FormalSettlementDetailFee.class));
fee.setId(null); fee.setFormalSettlementDetailId(target.getId()); fee.setSourceFeeId(item.getId());
fee.setSettlementAmountTax(item.getAfterAmount() == null ? money(item.getOriginalAmount()) : item.getAfterAmount());
fee.setSettlementAmountNoTax(null); detailFeeMapper.insert(fee);
}
if (fees.isEmpty()) createSingleFee(target);
}
private void createSingleFee(FormalSettlementDetail target) {
FormalSettlementDetailFee fee = Objects.requireNonNull(BeanUtil.copyProperties(target, FormalSettlementDetailFee.class));
fee.setId(null); fee.setFormalSettlementDetailId(target.getId()); fee.setLineNo("0001"); detailFeeMapper.insert(fee);
}
private void releaseSources(FormalSettlement settlement) {
for (FormalSettlementSource relation : sourceMapper.selectList(Wrappers.<FormalSettlementSource>lambdaQuery().eq(FormalSettlementSource::getFormalSettlementId, settlement.getId()))) {
PreSettlement source = preSettlementMapper.selectById(relation.getPreSettlementId());
if (source != null && Objects.equals(source.getFormalSettlementNo(), settlement.getFormalSettlementNo())) {
preSettlementMapper.update(null, Wrappers.<PreSettlement>lambdaUpdate()
.eq(PreSettlement::getId, source.getId())
.set(PreSettlement::getFormalSettlementNo, null)
.set(PreSettlement::getFormalSettledTime, null)
.set(PreSettlement::getCurrentNode, "审批通过"));
}
}
for (FormalSettlementDetail detail : detailMapper.selectList(Wrappers.<FormalSettlementDetail>lambdaQuery().eq(FormalSettlementDetail::getFormalSettlementId, settlement.getId()))) {
ReceivablePayableDetail source = receivablePayableMapper.selectById(detail.getSourceDetailId());
if (source != null && Objects.equals(source.getFormalSettlementNo(), settlement.getFormalSettlementNo())) {
receivablePayableMapper.update(null, Wrappers.<ReceivablePayableDetail>lambdaUpdate()
.eq(ReceivablePayableDetail::getId, source.getId())
.set(ReceivablePayableDetail::getFormalSettlementNo, null)
.set(ReceivablePayableDetail::getSettlementStatus,
detail.getSourcePreSettlementId() == null ? "pending" : "pre_settled"));
}
}
}
private FormalSettlementVO toVO(FormalSettlement entity) {
FormalSettlementVO vo = FormalSettlementWrapper.build().entityVO(entity);
vo.setPreSettlementNos(sourceMapper.selectList(Wrappers.<FormalSettlementSource>lambdaQuery().eq(FormalSettlementSource::getFormalSettlementId, entity.getId())).stream().map(FormalSettlementSource::getPreSettlementNo).collect(Collectors.joining(",")));
return vo;
}
private PreSettlement availableSource(Long id) {
PreSettlement source = preSettlementMapper.selectById(id);
if (source == null || Objects.equals(source.getIsDeleted(), 1)) throw new ServiceException("预结算单不存在");
if (!APPROVED.equals(source.getApprovalStatus())) throw new ServiceException("仅审批通过的预结算单可生成正式结算");
if (Func.isNotEmpty(source.getFormalSettlementNo())) throw new ServiceException("预结算单" + source.getPreSettlementNo() + "已被正式结算占用");
return source;
}
private ReceivablePayableDetail availableDetail(Long id) {
ReceivablePayableDetail detail = receivablePayableMapper.selectById(id);
if (detail == null || Objects.equals(detail.getIsDeleted(), 1)) throw new ServiceException("应收应付明细不存在");
if (!"pending".equals(detail.getSettlementStatus()) || Func.isNotEmpty(detail.getPreSettlementNo()) || Func.isNotEmpty(detail.getFormalSettlementNo())) {
throw new ServiceException("单据" + detail.getDocumentNo() + "已被结算或关闭");
}
return detail;
}
private FormalSettlement existing(Long id) {
FormalSettlement entity = getById(id);
if (entity == null || Objects.equals(entity.getIsDeleted(), 1)) throw new ServiceException("正式结算单不存在");
return entity;
}
private FormalSettlement editable(Long id) {
FormalSettlement entity = existing(id);
if (!DRAFT.equals(entity.getApprovalStatus()) && !RETURNED.equals(entity.getApprovalStatus())) throw new ServiceException("仅草稿或已驳回的正式结算单允许编辑");
return entity;
}
private void changeStatus(Long id, String expected, String target, String node, String reason) {
FormalSettlement settlement = existing(id);
if (!expected.equals(settlement.getApprovalStatus()) && !(DRAFT.equals(expected) && RETURNED.equals(settlement.getApprovalStatus()))) throw new ServiceException("当前状态不允许该操作");
settlement.setApprovalStatus(target); settlement.setCurrentNode(node); settlement.setCurrentProcessor(AuthUtil.getUserName());
if (RETURNED.equals(target)) settlement.setVoidReason(limit(reason, 200));
updateById(settlement);
}
private void copyHeader(PreSettlement source, FormalSettlement target) {
target.setSettlementType(source.getSettlementType()); target.setProjectId(source.getProjectId()); target.setProjectName(source.getProjectName());
target.setDeptId(source.getDeptId()); target.setDeptName(source.getDeptName()); target.setContractId(source.getContractId()); target.setContractNo(source.getContractNo());
target.setContractName(source.getContractName()); target.setPayerName(source.getPayerName()); target.setPayeeName(source.getPayeeName());
target.setCurrency(source.getCurrency()); target.setLocalCurrency(source.getLocalCurrency());
}
private void copyHeader(ContractManage contract, String settlementType, ReceivablePayableDetail source, FormalSettlement target) {
target.setSettlementType(settlementType); target.setProjectId(contract.getProjectId()); target.setProjectName(contract.getProjectName());
target.setDeptId(contract.getOrganizationId()); target.setDeptName(contract.getOrganizationName()); target.setContractId(contract.getId());
target.setContractNo(contract.getContractNo()); target.setContractName(contract.getContractName());
if ("receivable".equals(settlementType)) { target.setPayerName(source.getCustomerName()); target.setPayeeName(contract.getPartyA()); }
else { target.setPayerName(contract.getPartyA()); target.setPayeeName(source.getCustomerName()); }
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()
.likeRight(FormalSettlementPayment::getPaymentNo, prefix));
return prefix + String.format("%04d", count + 1);
}
private BigDecimal money(BigDecimal value) { return value == null ? BigDecimal.ZERO : value; }
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; }
private String limit(String value, int max) { if (value != null && value.length() > max) throw new ServiceException("内容不能超过" + max + "个字"); return value; }
}
@@ -0,0 +1,45 @@
/**
* 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.wrapper;
import org.springblade.core.mp.support.BaseEntityWrapper;
import org.springblade.core.tool.utils.BeanUtil;
import org.springblade.system.cache.UserCache;
import org.springblade.transport.pojo.entity.FormalSettlement;
import org.springblade.transport.pojo.vo.FormalSettlementVO;
import java.util.Objects;
/**
* 正式结算单包装类
*
* @author Chill
*/
public class FormalSettlementWrapper extends BaseEntityWrapper<FormalSettlement, FormalSettlementVO> {
public static FormalSettlementWrapper build() {
return new FormalSettlementWrapper();
}
@Override
public FormalSettlementVO entityVO(FormalSettlement entity) {
FormalSettlementVO vo = Objects.requireNonNull(BeanUtil.copyProperties(entity, FormalSettlementVO.class));
vo.setCreateUserName(UserCache.getUserRealName(entity.getCreateUser()));
vo.setSettlementTypeName("receivable".equals(entity.getSettlementType()) ? "应收" : "应付");
vo.setApprovalStatusName(switch (entity.getApprovalStatus() == null ? "" : entity.getApprovalStatus()) {
case "draft" -> "草稿";
case "reviewing" -> "审批中";
case "approved" -> "审批通过";
case "returned" -> "已驳回";
case "voided" -> "已作废";
default -> entity.getApprovalStatus();
});
return vo;
}
}
@@ -0,0 +1,51 @@
/**
* 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.wrapper;
import org.springblade.core.mp.support.BaseEntityWrapper;
import org.springblade.core.tool.utils.BeanUtil;
import org.springblade.system.cache.UserCache;
import org.springblade.transport.pojo.entity.PreSettlement;
import org.springblade.transport.pojo.vo.PreSettlementVO;
import java.util.Objects;
/**
* 预结算单包装类
*
* @author Chill
*/
public class PreSettlementWrapper extends BaseEntityWrapper<PreSettlement, PreSettlementVO> {
public static PreSettlementWrapper build() {
return new PreSettlementWrapper();
}
@Override
public PreSettlementVO entityVO(PreSettlement entity) {
PreSettlementVO vo = Objects.requireNonNull(BeanUtil.copyProperties(entity, PreSettlementVO.class));
vo.setCreateUserName(UserCache.getUserRealName(entity.getCreateUser()));
vo.setUpdateUserName(UserCache.getUserRealName(entity.getUpdateUser()));
vo.setApprovalStatusName(approvalStatusName(entity.getApprovalStatus()));
vo.setSettlementTypeName("receivable".equals(entity.getSettlementType()) ? "应收" : "应付");
return vo;
}
private String approvalStatusName(String status) {
return switch (status == null ? "" : status) {
case "draft" -> "草稿";
case "reviewing" -> "审批中";
case "approved" -> "审批通过";
case "returned" -> "已驳回";
case "voided" -> "已作废";
default -> status;
};
}
}