package com.java110.job.importData.adapt;
|
|
import com.alibaba.fastjson.JSONArray;
|
import com.alibaba.fastjson.JSONObject;
|
import com.java110.core.factory.GenerateCodeFactory;
|
import com.java110.dto.log.AssetImportLogDetailDto;
|
import com.java110.dto.msg.MaintenancePaymentPo;
|
import com.java110.dto.msg.MpFifthPaymentRecordPo;
|
import com.java110.dto.msg.MpPaymentRecordPo;
|
import com.java110.job.dao.IMaintenancePaymentService;
|
import com.java110.job.dao.IMpFifthPaymentRecordService;
|
import com.java110.job.dao.IMpPaymentRecordService;
|
import com.java110.job.importData.DefaultImportData;
|
import com.java110.job.importData.IImportDataAdapt;
|
import com.java110.utils.util.BeanConvertUtil;
|
import com.java110.utils.util.DateUtil;
|
import com.java110.utils.util.NumberUtil;
|
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.stereotype.Service;
|
import org.springframework.transaction.annotation.Transactional;
|
|
import java.math.BigDecimal;
|
import java.text.ParseException;
|
import java.text.SimpleDateFormat;
|
import java.util.*;
|
|
/**
|
* 签报收支款数据导入适配器(适配"Z三、模版签报收支款情况-V5-20251127.xlsx"的"荣顺苑签报单"sheet)
|
* 前端请求需传入:param.append('importAdapt', "importReportMainV2QueueData")
|
*/
|
@Service("importReportMainV2QueueData")
|
public class ImportReportMainV2QueueDataAdapt extends DefaultImportData implements IImportDataAdapt {
|
|
// 日期格式化器(处理Excel中的多种日期格式:2025/6/11、8/11/25、2025.5.13等)
|
private static final SimpleDateFormat[] DATE_FORMATS = {
|
new SimpleDateFormat("yyyy/MM/dd"),
|
new SimpleDateFormat("MM/dd/yy"),
|
new SimpleDateFormat("yyyy.MM.dd"),
|
new SimpleDateFormat("yyyy-MM-dd")
|
};
|
|
// 注入数据库服务(SqlSessionTemplate版Service)
|
@Autowired
|
private IMaintenancePaymentService maintenancePaymentService;
|
@Autowired
|
private IMpPaymentRecordService mpPaymentRecordService;
|
@Autowired
|
private IMpFifthPaymentRecordService mpFifthPaymentRecordService;
|
|
@Override
|
@Transactional(rollbackFor = Exception.class) // 事务控制,确保3张表数据一致性
|
public void importData(List<AssetImportLogDetailDto> assetImportLogDetailDtos) {
|
for (AssetImportLogDetailDto logDetailDto : assetImportLogDetailDtos) {
|
try {
|
// 1. 解析Excel行数据(JSONArray对应每行的单元格列表,顺序与"荣顺苑签报单"表头一致)
|
JSONArray cellArray = JSONObject.parseArray(logDetailDto.getContent());
|
// if (cellArray.size() < 132) { // 荣顺苑签报单表头共132列,过滤无效行
|
// throw new RuntimeException("行数据列数不足(需132列),当前列数:" + cellArray.size());
|
// }
|
|
// 2. 校验核心必填字段(流转编号、项目名称、业委会金额等)
|
String flowNumber = getCellValue(cellArray, 1); // 第2列:流转编号
|
String projectName = getCellValue(cellArray, 4); // 第5列:项目名称
|
String ownersCommitteeAmountStr = getCellValue(cellArray, 12); // 第13列:业委会金额
|
if (isBlank(flowNumber) || isBlank(projectName) || isBlank(ownersCommitteeAmountStr)) {
|
throw new RuntimeException(
|
String.format("核心字段缺失:流转编号[%s]、项目名称[%s]、业委会金额[%s]",
|
flowNumber, projectName, ownersCommitteeAmountStr)
|
);
|
}
|
|
// 3. 构建3张表的PO对象(字段映射+业务计算)
|
MaintenancePaymentPo mainPo = buildMaintenancePaymentPo(cellArray);
|
List<MpPaymentRecordPo> paymentRecordPos = buildMpPaymentRecordPos(cellArray, mainPo.getFlowNumber(),mainPo.getId());
|
MpFifthPaymentRecordPo fifthPo = buildMpFifthPaymentRecordPo(cellArray, mainPo.getFlowNumber(),mainPo.getId());
|
|
// 4. 批量保存到数据库
|
saveToDatabase(mainPo, paymentRecordPos, fifthPo);
|
|
// 5. 更新导入日志状态(成功)- 调用父类方法
|
super.updateImportLogDetailState(logDetailDto.getDetailId());
|
|
} catch (Exception e) {
|
e.printStackTrace();
|
// 6. 更新导入日志状态(失败)- 调用父类异常重载方法
|
super.updateImportLogDetailState(logDetailDto.getDetailId(), e);
|
}
|
}
|
}
|
|
/**
|
* 构建 MaintenancePaymentPo(维修资金支取信息表)
|
* 字段映射对应"荣顺苑签报单"表头顺序,包含17个自动计算字段
|
*/
|
private MaintenancePaymentPo buildMaintenancePaymentPo(JSONArray cellArray) throws ParseException {
|
MaintenancePaymentPo po = new MaintenancePaymentPo();
|
// 基础字段(直接映射Excel单元格)
|
long longId = UUID.randomUUID().getMostSignificantBits() & Long.MAX_VALUE; // 避免负数
|
po.setId(longId+""); // 主键ID
|
po.setAuxiliaryColumn(getCellValue(cellArray, 0)); // 第1列:辅助列
|
po.setFlowNumber(getCellValue(cellArray, 1)); // 第2列:流转编号
|
po.setSerialNumber(parseInteger(getCellValue(cellArray, 2))); // 第3列:序号
|
po.setProjectCode(getCellValue(cellArray, 3)); // 第4列:项目编码
|
po.setProjectName(getCellValue(cellArray, 4)); // 第5列:项目名称
|
po.setYear(parseInteger(getCellValue(cellArray, 5))); // 第6列:年份
|
po.setMonth(parseInteger(getCellValue(cellArray, 6))); // 第7列:月份
|
po.setDay(parseInteger(getCellValue(cellArray, 7))); // 第8列:日
|
po.setDate(parseDate(getCellValue(cellArray, 8))); // 第9列:日期
|
po.setProjectContent(getCellValue(cellArray, 9)); // 第10列:工程内容
|
po.setManagementOfficeAmount(parseBigDecimal(getCellValue(cellArray, 10))); // 第11列:管理处金额
|
po.setManagementOfficeSeal(convertSealStatus(getCellValue(cellArray, 11))); // 第12列:管理处是否已盖章(√转"是",否则"否")
|
po.setOwnersCommitteeAmount(parseBigDecimal(getCellValue(cellArray, 12))); // 第13列:业委会金额
|
po.setAuditAmount(parseBigDecimal(getCellValue(cellArray, 13))); // 第14列:审价金额
|
po.setOwnersCommitteeSeal(convertSealStatus(getCellValue(cellArray, 14))); // 第15列:业委会是否已盖章
|
po.setReportDepartment(getCellValue(cellArray, 15)); // 第16列:签报部门
|
po.setFundTypeLevel1(getCellValue(cellArray, 16)); // 第17列:基金类型-一级分类
|
po.setFundTypeLevel2(getCellValue(cellArray, 17)); // 第18列:基金类型-二级分类
|
po.setBuildingOrAll(getCellValue(cellArray, 18)); // 第19列:幢/全体
|
po.setMaintenanceType(getCellValue(cellArray, 19)); // 第20列:维修类型
|
po.setQualityGuaranteePeriod1(getCellValue(cellArray, 20)); // 第21列:质保期(第一个)
|
po.setPublicIncomeAnnouncement(getCellValue(cellArray, 21)); // 第22列:公共收益金公布情况
|
// 公共收益金公布子字段(第23-26列)
|
po.setPlannedAnnouncementStart(getCellValue(cellArray, 21)); // 拟公布-起始(年月)
|
po.setPlannedAnnouncementEnd(getCellValue(cellArray, 22)); // 拟公布-止(年月)
|
po.setPublishedAnnouncementStart(getCellValue(cellArray, 23)); // 已公布-起始(年月)
|
po.setPublishedAnnouncementEnd(getCellValue(cellArray, 24)); // 已公布-止(年月)
|
po.setQuota(parseBigDecimal(getCellValue(cellArray, 25))); // 第27列:额度
|
po.setOwnersCommitteeResolution(convertYesNo(getCellValue(cellArray, 26))); // 第28列:业委会大会决议(是/否)
|
po.setOwnersCommitteeConsultation(convertYesNo(getCellValue(cellArray, 27))); // 第29列:业委会征询表(是否)
|
po.setWithdrawalEncounteredProblem(getCellValue(cellArray, 28)); // 第30列:支取遇到的问题
|
po.setShortageOrArrears(parseBigDecimal(getCellValue(cellArray, 29))); // 第31列:缺支/欠款(元)
|
// 业主地址子字段(第32-37列)
|
po.setRoadName(getCellValue(cellArray, 30)); // 路名
|
po.setLane(getCellValue(cellArray, 31)); // 弄
|
po.setDoor(getCellValue(cellArray, 32)); // 门
|
po.setRoom(getCellValue(cellArray, 33)); // 室
|
po.setDoorRoomNumber(getCellValue(cellArray, 34)); // 门室号
|
po.setOwnerAddress(getCellValue(cellArray, 35)); // 业主地址
|
// po.setWithdrawalProblem(getCellValue(cellArray, 36)); // 第38列:支取存在问题
|
po.setProblemDifficulty(getCellValue(cellArray, 36)); // 第39列:问题难度
|
po.setAvailableWithdrawalDate(parseDate(getCellValue(cellArray, 37))); // 第40列:可启动支取日期(年月日)
|
po.setQualityGuaranteePeriod2(getCellValue(cellArray, 39) + "~" + getCellValue(cellArray, 40)); // 第41列:质保期(第二个)
|
po.setQualityGuaranteeRatio(parseBigDecimal(getCellValue(cellArray, 40))); // 第42列:质保金占比
|
po.setQualityGuaranteeAmount(parseBigDecimal(getCellValue(cellArray, 41))); // 第43列:质保金金额(元)
|
po.setReceivedQualityGuarantee(parseBigDecimal(getCellValue(cellArray, 42))); // 第44列:已到账质保金
|
// po.setStartDate(parseDate(getCellValue(cellArray, 44))); // 第45列:起始(年月日)
|
// po.setEndDate(parseDate(getCellValue(cellArray, 45))); // 第46列:终止(年月日)
|
|
// -------------------------- 17个自动计算字段(核心业务逻辑)--------------------------
|
// 1. 打印合计 = 第一次~第五次打印金额之和(第47列打印金额+第54列+第61列+第68列+第75列)
|
BigDecimal print1 = parseBigDecimal(getCellValue(cellArray, 45)); // 第一次打印金额(第50列)
|
BigDecimal print2 = parseBigDecimal(getCellValue(cellArray, 57)); // 第二次打印金额(第57列)
|
BigDecimal print3 = parseBigDecimal(getCellValue(cellArray, 69)); // 第三次打印金额(第64列)
|
BigDecimal print4 = parseBigDecimal(getCellValue(cellArray, 81)); // 第四次打印金额(第71列)
|
BigDecimal print5 = parseBigDecimal(getCellValue(cellArray, 93)); // 第五次打印金额(第78列)
|
// BigDecimal printTotal = add(print1, print2, print3, print4, print5);
|
// po.setPrintTotal(printTotal); // 自定义字段:打印合计
|
|
// 2. 到账合计 = 第一次~第五次到账金额之和(第51列+第58列+第65列+第72列+第79列)
|
BigDecimal arrival1 = parseBigDecimal(getCellValue(cellArray, 48)); // 第一次到账金额(第52列)
|
BigDecimal arrival2 = parseBigDecimal(getCellValue(cellArray, 60)); // 第二次到账金额(第59列)
|
BigDecimal arrival3 = parseBigDecimal(getCellValue(cellArray, 72)); // 第三次到账金额(第66列)
|
BigDecimal arrival4 = parseBigDecimal(getCellValue(cellArray, 84)); // 第四次到账金额(第73列)
|
BigDecimal arrival5 = parseBigDecimal(getCellValue(cellArray, 96)); // 第五次到账金额(第80列)
|
// BigDecimal arrivalTotal = add(arrival1, arrival2, arrival3, arrival4, arrival5);
|
// po.setArrivalTotal(arrivalTotal); // 自定义字段:到账合计
|
|
// 3. 维修基金到账率 = IF(到账合计<>0, 到账合计/业委会金额, 0)
|
BigDecimal ownersAmount = po.getOwnersCommitteeAmount();
|
// BigDecimal fundArrivalRate = (arrivalTotal.compareTo(BigDecimal.ZERO) != 0 && ownersAmount.compareTo(BigDecimal.ZERO) != 0)
|
// ? arrivalTotal.divide(ownersAmount, 4, BigDecimal.ROUND_HALF_UP) // 保留4位小数
|
// : BigDecimal.ZERO;
|
// po.setFundArrivalRate(fundArrivalRate); // 自定义字段:维修基金到账率
|
|
// 4. 尚缺金额 = IF(基金类型<>"维修基金", 0, 业委会金额-到账合计)
|
String fundType = po.getFundTypeLevel1();
|
// BigDecimal shortageAmount = ("维修基金".equals(fundType))
|
// ? subtract(ownersAmount, arrivalTotal)
|
// : BigDecimal.ZERO;
|
// po.setFundShortageAmount(shortageAmount); // 自定义字段:尚缺金额
|
|
// 5. 管理费 = 管理处金额 * 管理费占比(百分比转小数)
|
BigDecimal managementFeeRatio = po.getManagementFeeRatio() == null ? BigDecimal.ZERO : po.getManagementFeeRatio().divide(new BigDecimal(100));
|
BigDecimal managementFee = multiply(po.getManagementOfficeAmount(), managementFeeRatio);
|
// po.setManagementFee(managementFee); // 自定义字段:管理费
|
|
// 6. 应付金额A = IF(审计金额为空, 业委会金额-管理费, 审计金额-管理费)
|
BigDecimal auditAmount = po.getAuditAmount() == null ? BigDecimal.ZERO : po.getAuditAmount();
|
BigDecimal payableA = (auditAmount.compareTo(BigDecimal.ZERO) == 0)
|
? subtract(ownersAmount, managementFee)
|
: subtract(auditAmount, managementFee);
|
// po.setPayableAmountA(payableA); // 自定义字段:应付金额A
|
|
// 7. 应付金额B = 业委会金额-管理费-质保金金额
|
BigDecimal qualityGuaranteeAmount = po.getQualityGuaranteeAmount() == null ? BigDecimal.ZERO : po.getQualityGuaranteeAmount();
|
BigDecimal payableB = subtract(ownersAmount, managementFee, qualityGuaranteeAmount);
|
// po.setPayableAmountB(payableB); // 自定义字段:应付金额B
|
|
// 8. 应付金额C = 实收金额-实收金额×管理费比例(实收金额取到账合计)
|
// BigDecimal payableC = multiply(arrivalTotal, BigDecimal.ONE.subtract(managementFeeRatio));
|
// po.setPayableAmountC(payableC); // 自定义字段:应付金额C
|
|
// 9. 拟付合计 = 第一次~第五次拟付金额之和(第82列+第88列+第94列+第100列+第106列)
|
BigDecimal plannedPay1 = parseBigDecimal(getCellValue(cellArray, 113)); // 第一次拟付金额(第83列)
|
BigDecimal plannedPay2 = parseBigDecimal(getCellValue(cellArray, 119)); // 第二次拟付金额(第89列)
|
BigDecimal plannedPay3 = parseBigDecimal(getCellValue(cellArray, 125)); // 第三次拟付金额(第95列)
|
BigDecimal plannedPay4 = parseBigDecimal(getCellValue(cellArray, 131)); // 第四次拟付金额(第101列)
|
BigDecimal plannedPay5 = parseBigDecimal(getCellValue(cellArray, 137)); // 第五次拟付金额(第107列)
|
BigDecimal plannedPayTotal = add(plannedPay1, plannedPay2, plannedPay3, plannedPay4, plannedPay5);
|
// po.setPlannedPayTotal(plannedPayTotal); // 自定义字段:拟付合计
|
|
// 10. 实付合计 = 第一次~第五次实付金额之和(第85列+第91列+第97列+第103列+第109列)
|
BigDecimal actualPay1 = parseBigDecimal(getCellValue(cellArray, 117)); // 第一次实付金额(第86列)
|
BigDecimal actualPay2 = parseBigDecimal(getCellValue(cellArray, 123)); // 第二次实付金额(第92列)
|
BigDecimal actualPay3 = parseBigDecimal(getCellValue(cellArray, 130)); // 第三次实付金额(第98列)
|
BigDecimal actualPay4 = parseBigDecimal(getCellValue(cellArray, 135)); // 第四次实付金额(第104列)
|
BigDecimal actualPay5 = parseBigDecimal(getCellValue(cellArray, 141)); // 第五次实付金额(第110列)
|
BigDecimal actualPayTotal = add(actualPay1, actualPay2, actualPay3, actualPay4, actualPay5);
|
// po.setActualPayTotal(actualPayTotal); // 自定义字段:实付合计
|
|
// 11. 未付合计 = 审定金额-实付合计(审定金额取审计金额,无则取业委会金额)
|
BigDecimal approvedAmount = (auditAmount.compareTo(BigDecimal.ZERO) == 0) ? ownersAmount : auditAmount;
|
BigDecimal unpaidTotal = subtract(approvedAmount, actualPayTotal);
|
// po.setUnpaidTotal(unpaidTotal); // 自定义字段:未付合计
|
|
// 12. 垫付金额 = 复杂条件判断(基金类型、到账合计、公布情况)
|
// BigDecimal advanceAmount = calculateAdvanceAmount(fundType, arrivalTotal, actualPayTotal, po.getPublicIncomeAnnouncement());
|
// po.setAdvanceAmount(advanceAmount); // 自定义字段:垫付金额
|
|
// 13. 未付合计(到账口径) = 按公布情况分支计算
|
// BigDecimal unpaidByArrival = calculateUnpaidByArrival(po.getPublicIncomeAnnouncement(), ownersAmount, managementFee, actualPayTotal, arrivalTotal);
|
// po.setUnpaidByArrival(unpaidByArrival); // 自定义字段:未付合计(到账口径)
|
|
// 14-16. 待付金额A/B/C
|
// po.setPendingPayA(subtract(auditAmount, managementFee)); // 待付金额A = 审价金额 - 管理费
|
// po.setPendingPayB(subtract(auditAmount, qualityGuaranteeAmount, managementFee)); // 待付金额B = 审价金额 - 质保金 - 管理费
|
// po.setPendingPayC(multiply(arrivalTotal, BigDecimal.ONE.subtract(managementFeeRatio))); // 待付金额C = 到账合计*(1-管理费占比)
|
|
// 支付信息(第111-116列)
|
po.setPayeeName(getCellValue(cellArray, 143)); // 支付公司名称/个人名字
|
po.setIdCardNumber(getCellValue(cellArray, 144)); // 个人身份证号码
|
po.setBankName(getCellValue(cellArray, 145)); // 开户银行
|
po.setBankAccount(getCellValue(cellArray, 146)); // 开户账号
|
po.setRemarks(getCellValue(cellArray, 155)); // 备注
|
po.setAcceptanceDate(parseDate(getCellValue(cellArray, 156))); // 验收日期
|
po.setAuditDate(getCellValue(cellArray, 157)); // 审计情况:年/月
|
|
return po;
|
}
|
|
/**
|
* 构建 MpPaymentRecordPo 列表(5次打印数据)
|
*/
|
private List<MpPaymentRecordPo> buildMpPaymentRecordPos(JSONArray cellArray, String flowNumber,String mainPo) throws ParseException {
|
List<MpPaymentRecordPo> pos = new ArrayList<>();
|
// 第一次打印数据(第47-53列)
|
pos.add(buildSinglePaymentRecord(mainPo, cellArray, flowNumber, 1, 43, 44, 45, 46, 47, 48, 49));
|
// 第二次打印数据(第54-60列)
|
pos.add(buildSinglePaymentRecord(mainPo, cellArray, flowNumber, 2, 55, 56, 57, 58, 59, 60, 61));
|
// 第三次打印数据(第61-67列)
|
pos.add(buildSinglePaymentRecord(mainPo, cellArray, flowNumber, 3, 67, 68, 69, 70, 71, 72, 73));
|
// 第四次打印数据(第68-74列)
|
pos.add(buildSinglePaymentRecord(mainPo, cellArray, flowNumber, 4, 79, 80, 81, 82, 83, 84, 85));
|
// 第五次打印数据(第75-81列)
|
pos.add(buildSinglePaymentRecord(mainPo, cellArray, flowNumber, 5, 91, 92, 93, 94, 95, 96, 97));
|
return pos;
|
}
|
|
/**
|
* 构建单次打印的 MpPaymentRecordPo
|
*/
|
private MpPaymentRecordPo buildSinglePaymentRecord(String mpId, JSONArray cellArray, String flowNumber, int printTimes,
|
int dateCol, int resolutionCol, int amountCol,
|
int arrivalDateCol, int arrivalAmountCol,
|
int withdrawerCol, int shortageCol) throws ParseException {
|
MpPaymentRecordPo po = new MpPaymentRecordPo();
|
|
long longId = UUID.randomUUID().getMostSignificantBits() & Long.MAX_VALUE; // 避免负数
|
po.setId(longId+"");
|
po.setMpId(mpId); // mp_id = 流转编号_打印次数(确保唯一)
|
po.setFirstPrintDate(parseDate(getCellValue(cellArray, dateCol)));
|
po.setResolutionNumber(getCellValue(cellArray, resolutionCol));
|
po.setPrintAmount(parseBigDecimal(getCellValue(cellArray, amountCol)));
|
po.setArrivalDate(parseDate(getCellValue(cellArray, arrivalDateCol)));
|
po.setArrivalAmount(parseBigDecimal(getCellValue(cellArray, arrivalAmountCol)));
|
po.setWithdrawer(getCellValue(cellArray, withdrawerCol));
|
po.setShortageOrArrears(parseBigDecimal(getCellValue(cellArray, shortageCol)));
|
// 业主地址信息(复用main表的地址)
|
po.setRoadName(getCellValue(cellArray, 31));
|
po.setLane(getCellValue(cellArray, 32));
|
po.setDoor(getCellValue(cellArray, 33));
|
po.setRoom(getCellValue(cellArray, 34));
|
po.setOwnerAddress(getCellValue(cellArray, 36));
|
return po;
|
}
|
|
/**
|
* 构建 MpFifthPaymentRecordPo(第五次拟付实付)
|
*/
|
private MpFifthPaymentRecordPo buildMpFifthPaymentRecordPo(JSONArray cellArray, String flowNumber,String mainPo) throws ParseException {
|
MpFifthPaymentRecordPo po = new MpFifthPaymentRecordPo();
|
long longId = UUID.randomUUID().getMostSignificantBits() & Long.MAX_VALUE; // 避免负数
|
po.setId(longId+"");
|
po.setMpId(mainPo); // mp_id = 流转编号_FIFTH
|
// 第五次拟付实付数据(第106-111列)
|
po.setFifthPlannedPaymentAmount(parseBigDecimal(getCellValue(cellArray, 137))); // 第五次拟付金额
|
po.setPlannedPaymentDate(parseDate(getCellValue(cellArray, 138))); // 第五次拟付日期
|
po.setCategory(getCellValue(cellArray, 139)); // 类别
|
po.setReimburser(getCellValue(cellArray, 140)); // 报销人
|
po.setActualPaymentAmount(parseBigDecimal(getCellValue(cellArray, 141))); // 第五次实付金额
|
po.setActualPaymentDate(parseDate(getCellValue(cellArray, 142))); // 第五次实付日期
|
return po;
|
}
|
|
/**
|
* 计算垫付金额(文档第十三条逻辑)
|
*/
|
private BigDecimal calculateAdvanceAmount(String fundType, BigDecimal arrivalTotal,
|
BigDecimal actualPayTotal, String publicIncomeAnnouncement) {
|
// 条件1:基金类型是"公共收益金"或"维修基金"
|
if ("公共收益金".equals(fundType) || "维修基金".equals(fundType)) {
|
if (arrivalTotal.compareTo(BigDecimal.ZERO) != 0) {
|
// 到账合计≠0:实付>到账则垫付=实付-到账,否则0
|
return (actualPayTotal.compareTo(arrivalTotal) > 0)
|
? subtract(actualPayTotal, arrivalTotal)
|
: BigDecimal.ZERO;
|
} else {
|
// 到账合计=0:判断"公共收益金公布情况"是否含"公布"且不含"拟"
|
boolean hasPublish = !isBlank(publicIncomeAnnouncement) && publicIncomeAnnouncement.contains("公布");
|
boolean hasPlanned = !isBlank(publicIncomeAnnouncement) && publicIncomeAnnouncement.contains("拟");
|
return (hasPublish && !hasPlanned) ? BigDecimal.ZERO : actualPayTotal;
|
}
|
}
|
// 其他基金类型:垫付金额=0
|
return BigDecimal.ZERO;
|
}
|
|
/**
|
* 计算未付合计(到账口径)(文档第十四条逻辑)
|
*/
|
private BigDecimal calculateUnpaidByArrival(String publicIncomeAnnouncement, BigDecimal ownersAmount,
|
BigDecimal managementFee, BigDecimal actualPayTotal, BigDecimal arrivalTotal) {
|
// 含"公布":未付=业委会金额-管理费-实付合计
|
if (!isBlank(publicIncomeAnnouncement) && publicIncomeAnnouncement.contains("公布")) {
|
return subtract(ownersAmount, managementFee, actualPayTotal);
|
} else {
|
// 不含"公布":到账合计=0则0,否则=到账合计-管理费-实付合计
|
return (arrivalTotal.compareTo(BigDecimal.ZERO) == 0)
|
? BigDecimal.ZERO
|
: subtract(arrivalTotal, managementFee, actualPayTotal);
|
}
|
}
|
|
/**
|
* 数据库保存(调用SqlSessionTemplate版Service)
|
*/
|
private void saveToDatabase(MaintenancePaymentPo mainPo,
|
List<MpPaymentRecordPo> paymentRecordPos,
|
MpFifthPaymentRecordPo fifthPo) {
|
// 1. 保存主表(单条)
|
int mainFlag = maintenancePaymentService.saveMaintenancePayment(mainPo);
|
if (mainFlag <= 0) {
|
throw new RuntimeException("维修资金支取主表插入失败,流转编号:" + mainPo.getFlowNumber());
|
}
|
|
// 2. 批量保存5次打印记录
|
int batchFlag = mpPaymentRecordService.batchSaveMpPaymentRecord(paymentRecordPos);
|
if (batchFlag <= 0) {
|
throw new RuntimeException("打印支取到账记录批量插入失败,流转编号:" + mainPo.getFlowNumber());
|
}
|
|
// 3. 保存第五次拟付实付记录
|
int fifthFlag = mpFifthPaymentRecordService.saveMpFifthPaymentRecord(fifthPo);
|
if (fifthFlag <= 0) {
|
throw new RuntimeException("第五次拟付实付记录插入失败,流转编号:" + mainPo.getFlowNumber());
|
}
|
}
|
|
// -------------------------- 工具方法 --------------------------
|
/**
|
* 获取单元格值(处理null/空字符串)
|
*/
|
private String getCellValue(JSONArray cellArray, int index) {
|
if (index < 0 || index >= cellArray.size()) {
|
return "";
|
}
|
Object value = cellArray.get(index);
|
return value == null ? "" : value.toString().trim();
|
}
|
|
/**
|
* 判断字符串是否为空
|
*/
|
private boolean isBlank(String str) {
|
return str == null || str.isEmpty() || "null".equalsIgnoreCase(str) || "#REF!".equals(str);
|
}
|
|
/**
|
* 解析Integer(空值返回null)
|
*/
|
private Integer parseInteger(String str) {
|
if (isBlank(str)) {
|
return null;
|
}
|
try {
|
return Integer.parseInt(str);
|
} catch (NumberFormatException e) {
|
return null;
|
}
|
}
|
|
/**
|
* 解析BigDecimal(空值返回0,处理千分位逗号)
|
*/
|
private BigDecimal parseBigDecimal(String str) {
|
if (isBlank(str)) {
|
return BigDecimal.ZERO;
|
}
|
try {
|
// 处理Excel中的千分位格式(如133,900.57)
|
String cleanStr = str.replace(",", "").trim();
|
return new BigDecimal(cleanStr);
|
} catch (NumberFormatException e) {
|
return BigDecimal.ZERO;
|
}
|
}
|
|
/**
|
* 解析日期(支持多种格式,空值返回null)
|
*/
|
private Date parseDate(String str) throws ParseException {
|
if (isBlank(str)) {
|
return null;
|
}
|
|
// 手动解析Excel日期序列号(1900-01-01为基准,注意Excel的1900闰年bug)
|
try {
|
double excelDateNum = Double.parseDouble(str.trim());
|
// Excel 1900日期系统:序列号1=1900-01-01,且错误认为1900是闰年(多算1天)
|
Calendar cal = Calendar.getInstance();
|
cal.set(1900, 0, 1); // 1900-01-01
|
cal.add(Calendar.DAY_OF_YEAR, (int) excelDateNum - 2); // 修正闰年bug(减2)
|
return cal.getTime();
|
} catch (NumberFormatException e) {
|
// 不是数字,继续解析文本格式
|
}
|
|
// 文本格式解析(同之前逻辑)
|
for (SimpleDateFormat format : DATE_FORMATS) {
|
try {
|
format.setLenient(false);
|
return format.parse(str.trim());
|
} catch (ParseException e) {
|
continue;
|
}
|
}
|
|
throw new ParseException("不支持的日期格式:" + str, 0);
|
}
|
|
/**
|
* 转换盖章状态(√→是,其他→否)
|
*/
|
private String convertSealStatus(String str) {
|
return "√".equals(str) || "是".equals(str) ? "是" : "否";
|
}
|
|
/**
|
* 转换是/否(空值返回null)
|
*/
|
private String convertYesNo(String str) {
|
if (isBlank(str)) {
|
return null;
|
}
|
return "是".equals(str) || "√".equals(str) ? "是" : "否";
|
}
|
|
/**
|
* 多个BigDecimal相加(处理null,null视为0)
|
*/
|
private BigDecimal add(BigDecimal... decimals) {
|
BigDecimal result = BigDecimal.ZERO;
|
for (BigDecimal decimal : decimals) {
|
result = result.add(decimal == null ? BigDecimal.ZERO : decimal);
|
}
|
return result;
|
}
|
|
/**
|
* 多个BigDecimal相减(处理null,null视为0)
|
*/
|
private BigDecimal subtract(BigDecimal... decimals) {
|
if (decimals == null || decimals.length == 0) {
|
return BigDecimal.ZERO;
|
}
|
BigDecimal result = decimals[0] == null ? BigDecimal.ZERO : decimals[0];
|
for (int i = 1; i < decimals.length; i++) {
|
result = result.subtract(decimals[i] == null ? BigDecimal.ZERO : decimals[i]);
|
}
|
// 避免出现负数(业务中金额不能为负时启用)
|
return result.compareTo(BigDecimal.ZERO) < 0 ? BigDecimal.ZERO : result;
|
}
|
|
/**
|
* 两个BigDecimal相乘(处理null,null视为0)
|
*/
|
private BigDecimal multiply(BigDecimal a, BigDecimal b) {
|
if (a == null || b == null) {
|
return BigDecimal.ZERO;
|
}
|
return a.multiply(b).setScale(2, BigDecimal.ROUND_HALF_UP); // 保留2位小数
|
}
|
}
|