package com.seeyon.apps.assetstenant.bill; import cn.hutool.log.Log; import com.alibaba.fastjson.JSONObject; import com.seeyon.apps.assetstenant.assets.AssetsService; import com.seeyon.apps.assetstenant.assets.OaAssetsVo; import com.seeyon.apps.assetstenant.config.AssetsTenantConfigProvider; import com.seeyon.apps.assetstenant.constants.AssetsTenantConstants; import com.seeyon.apps.assetstenant.contract.ContractPayBaseInfo; import com.seeyon.apps.assetstenant.contract.ContractService; import com.seeyon.apps.assetstenant.contract.OaContractDetailVo; import com.seeyon.apps.assetstenant.flow.FlowCreateService; import com.seeyon.apps.assetstenant.po.PageQueryVo; import com.seeyon.cap4.form.api.FormApi4Cap4; import com.seeyon.cap4.form.bean.FormBean; import com.seeyon.cap4.form.bean.FormFieldBean; import com.seeyon.cap4.form.bean.FormTableBean; import com.seeyon.ctp.common.AppContext; import com.seeyon.ctp.common.exceptions.BusinessException; import com.seeyon.ctp.organization.bo.V3xOrgMember; import com.seeyon.ctp.organization.manager.OrgManager; import com.seeyon.utils.form.*; import org.apache.commons.lang3.StringUtils; import java.math.BigDecimal; import java.math.RoundingMode; import java.text.DateFormat; import java.text.SimpleDateFormat; import java.time.LocalDate; import java.time.format.DateTimeFormatter; import java.util.*; public class BillService { private static final Log log = Log.get(BillService.class); private AssetsTenantConfigProvider configProvider = (AssetsTenantConfigProvider) AppContext.getBean("assetsTenantConfigProvider"); private ContractService contractService = (ContractService) AppContext.getBean("contractService"); private AssetsService assetsService = (AssetsService) AppContext.getBean("assetsService"); private FlowCreateService flowCreateService = (FlowCreateService) AppContext.getBean("flowCreateService"); private OrgManager orgManager = (OrgManager) AppContext.getBean("orgManager"); private DateFormat df = new SimpleDateFormat("yyyy-MM-dd"); private String getFormNo() { return configProvider.getBizConfigByKey(AssetsTenantConstants.CONTRACTBILLFORMNO); } private TableContext getTableContext() throws BusinessException { TableContext tableContext = FormTableExecutor.master(getFormNo()); return tableContext; } private String getStringValue(Map fieldsMap, String key) { Object o = fieldsMap.get(key); if (o == null) { return null; } return o + ""; } private List buildConditions(JSONObject params, FormTableBean formTableBean) { List conditions = new ArrayList<>(); if (StringUtils.isNotBlank(params.getString("cusNo"))) { conditions.add(FormWhereCondition.build().display("承租方编号").value(params.getString("cusNo"))); } if (StringUtils.isNotBlank(params.getString("billNo"))) { conditions.add(FormWhereCondition.build().display("账单-账单明细编号").value(params.getString("billNo"))); } if(StringUtils.isNotBlank(params.getString("contractNo"))) { conditions.add(FormWhereCondition.build().display("合同编号").value(params.getString("contractNo"))); } if (StringUtils.isNotBlank(params.getString("billStatus"))) { if ("已缴费".equals(params.getString("billStatus"))) { conditions.add(FormWhereCondition.build().display("账单-收款结果反馈").clauseFactor(ClauseFactor.NOT_NULL)); } else { conditions.add(FormWhereCondition.build().display("账单-收款结果反馈").clauseFactor(ClauseFactor.NULL).startWithBracket(true).concatFactor(ClauseFactor.OR)); conditions.add(FormWhereCondition.build().display("账单-收款结果反馈").value(EnumMapUtils.getEnumItemValueByDisplayValue(formTableBean, "账单-收款结果反馈", "未收款")).endWithBracket(true)); } } return conditions; } public List queryAllContractBill(List conditions) throws Exception { TableContext tableContext = getTableContext(); List datas = FormTableExecutor.query(tableContext, null, conditions, true); List vos = new ArrayList<>(); if (datas.size() > 0) { for (FormColumn data : datas) { Map map = data.getFieldsMap(); BillVo billVo = new BillVo(); fillVo(map, billVo); vos.add(billVo); } } return vos; } public List queryContractPayBaseInfoList(String contractNo) throws BusinessException { List contractPayBaseInfoList = new ArrayList<>(); String formNo = configProvider.getBizConfigByKey(AssetsTenantConstants.BILLCREATEFORMNO); List conditions = new ArrayList<>(); conditions.add(FormWhereCondition.build().display("合同编号").value(contractNo)); TableContext master = FormTableExecutor.master(formNo); List formColumns = FormTableExecutor.query(master, null, conditions, true); if(formColumns == null || formColumns.size() <= 0){ return contractPayBaseInfoList; } for (FormColumn formColumn : formColumns) { Map fieldsMap = formColumn.getFieldsMap(); ContractPayBaseInfo baseInfo = new ContractPayBaseInfo(); baseInfo.setContractNo(contractNo); baseInfo.setAssetsName(getStringValue(fieldsMap, "资产名称")); baseInfo.setAssetsNo(getStringValue(fieldsMap,"资产编号")); baseInfo.setTotalRentFee(getStringValue(fieldsMap,"本账单金额")); Integer totalPeriod = contractService.countTotalPeriod(contractNo); baseInfo.setTotalTermNum(totalPeriod + ""); Integer countPaidTermNum = countPaidTermNum(baseInfo.getAssetsNo(), baseInfo.getContractNo()); baseInfo.setPaidTermNum(countPaidTermNum + ""); JSONObject param = new JSONObject(); param.put("contractNo", contractNo); try { OaContractDetailVo detailVo = contractService.queryContractDetail(param); baseInfo.setDeposit(detailVo.getDeposit()); }catch (Exception e) { } contractPayBaseInfoList.add(baseInfo); } return contractPayBaseInfoList; } public Integer countPaidTermNum(String assetsNo,String contractNo) throws BusinessException { TableContext tableContext = getTableContext(); List conditions = new ArrayList<>(); conditions.add(FormWhereCondition.build().display("资产编号").value(assetsNo)); conditions.add(FormWhereCondition.build().display("合同编号").value(contractNo)); conditions.add(FormWhereCondition.build().display("账单-收款结果反馈").value(EnumMapUtils.getEnumItemValueByDisplayValue(tableContext.getTableBean(),"收款结果反馈", "已结清"))); conditions.add(FormWhereCondition.build().display("账单类型").value(EnumMapUtils.getEnumItemValueByDisplayValue(tableContext.getTableBean(),"账单类型", "租金"))); Long count = FormTableExecutor.count(tableContext, null, conditions); return count.intValue(); } public Integer countUnpayRentBills(JSONObject params) throws Exception { TableContext tableContext = getTableContext(); List conditions = buildConditions(params, tableContext.getTableBean()); conditions.add(FormWhereCondition.build().display("账单-收款结果反馈").clauseFactor(ClauseFactor.NULL).startWithBracket(true).concatFactor(ClauseFactor.OR)); conditions.add(FormWhereCondition.build().display("账单-收款结果反馈").value(EnumMapUtils.getEnumItemValueByDisplayValue(tableContext.getTableBean(), "账单-收款结果反馈", "未收款")).endWithBracket(true)); Long count = FormTableExecutor.count(tableContext, null, conditions); return count.intValue(); } public PageQueryVo pageQueryContractBill(JSONObject params) throws Exception { TableContext tableContext = getTableContext(); List conditions = buildConditions(params, tableContext.getTableBean()); Integer pageNo = params.getInteger("pageNo") == null ? 1 : params.getInteger("pageNo"); Integer pageSize = params.getInteger("pageSize") == null ? 10 : params.getInteger("pageSize"); PageQueryVo pageQueryVo = new PageQueryVo(); List datas = FormTableExecutor.pageQuery(tableContext, null, conditions, pageNo, pageSize, true); List vos = new ArrayList<>(); Long count = FormTableExecutor.count(tableContext, null, conditions); if (datas.size() > 0) { for (FormColumn data : datas) { Map map = data.getFieldsMap(); BillVo billVo = new BillVo(); fillVo(map, billVo); vos.add(billVo); } pageQueryVo.setDatas(vos); pageQueryVo.setTotalCount(count); } return pageQueryVo; } public BillVo queryOne(JSONObject params) throws Exception { TableContext tableContext = getTableContext(); List conditions = buildConditions(params, tableContext.getTableBean()); FormColumn formColumn = FormTableExecutor.queryOne(tableContext, conditions, true); if (formColumn == null) { return null; } Map fieldsMap = formColumn.getFieldsMap(); BillVo billVo = new BillVo(); fillVo(fieldsMap, billVo); return billVo; } public void fillVo(Map fieldsMap, BillVo billVo) throws Exception { billVo.setBillType(getStringValue(fieldsMap, "账单类型")); billVo.setBillNo(getStringValue(fieldsMap, "账单-账单明细编号")); String payStatus = fieldsMap.get("账单-收款结果反馈") == null ? "待缴费" : getStringValue(fieldsMap, "账单-收款结果反馈"); billVo.setBillStatus(payStatus); billVo.setCusNo(getStringValue(fieldsMap, "承租方编号")); billVo.setBillStartDate(getStringValue(fieldsMap, "账单-开始日期")); billVo.setContractNo(getStringValue(fieldsMap, "合同编号")); billVo.setBillPayEndDate(getStringValue(fieldsMap, "账单-当前缴费时限")); billVo.setBillEndDate(getStringValue(fieldsMap, "账单-结束日期")); String billName = buildBillName(fieldsMap, billVo); billVo.setBillPayDate(getStringValue(fieldsMap, "账单-实际收款时间")); billVo.setBillName(billName); if(billVo.getBillTermNum() != null && 1 == billVo.getBillTermNum()) { billVo.setDeposit(getDeposit(getStringValue(fieldsMap, "合同编号"))); } if("租金".equals(billVo.getBillType())) { BigDecimal bigDecimal = (BigDecimal) fieldsMap.get("账单-租费"); billVo.setBillAmount(bigDecimal == null ? null : bigDecimal.toString()); }else if("履约保证金".equals(billVo.getBillType())){ BigDecimal bigDecimal = (BigDecimal) fieldsMap.get("约定履约保证金"); billVo.setBillAmount(bigDecimal == null ? null : bigDecimal.toString()); }else if("违约金".equals(billVo.getBillType())){ BigDecimal bigDecimal = (BigDecimal) fieldsMap.get("应收违约金"); billVo.setBillAmount(bigDecimal == null ? null : bigDecimal.toString()); }else if("滞纳金".equals(billVo.getBillType())){ BigDecimal bigDecimal = (BigDecimal) fieldsMap.get("应收滞纳金"); billVo.setBillAmount(bigDecimal == null ? null : bigDecimal.toString()); } } private String getDeposit(String contractNo) throws Exception { JSONObject params = new JSONObject(); params.put("contractNo", contractNo); OaContractDetailVo oaContractVo = contractService.queryContractDetail(params); return oaContractVo == null ? null : oaContractVo.getDeposit(); } private String buildBillName(Map fieldsMap, BillVo billVo) throws Exception { String contractNo = getStringValue(fieldsMap, "合同编号"); Integer termNum = contractService.queryContractPayPeriod(contractNo, getStringValue(fieldsMap, "账单-开始日期")); billVo.setBillTermNum(termNum); OaAssetsVo oaAssetsVo = assetsService.queryAssetsDetail(getStringValue(fieldsMap, "资产编号")); String asssetsName = null; if (oaAssetsVo != null) { asssetsName = oaAssetsVo.getAssetsName(); } String roomNo = fieldsMap.get("门牌号") == null ? "" : fieldsMap.get("门牌号") + "-"; return asssetsName + roomNo + termNum + "期"; } public void payCallBack(String billNo,String payDate) throws Exception { // 1. 获取Bean + 非空校验 FormApi4Cap4 formApi4Cap4 = (FormApi4Cap4) AppContext.getBean("formApi4Cap4"); if (formApi4Cap4 == null) { throw new Exception("Spring容器中未找到formApi4Cap4 Bean"); } // 2. 复用配置,避免重复查询 String templateCode = this.configProvider.getBizConfigByKey(AssetsTenantConstants.PAYMENT_REGISTRATION_TEMPLATECODE); String appName = this.configProvider.getBizConfigByKey(AssetsTenantConstants.FORMAPPNAME); // 3. 获取表单结构 FormBean cap4FormBean = formApi4Cap4.getFormByFormCode(templateCode); FormTableBean masterTableBean = cap4FormBean.getMasterTableBean(); String tableName = masterTableBean.getTableName(); List subTableBeanList = cap4FormBean.getSubTableBean(); FormTableBean subTableBean = null; // 4. 获取子表名 + 非空校验 String subDbTableName = null; for (FormTableBean tableBean : subTableBeanList) { if ("租金收款明细".equals(tableBean.getDisplay())) { subDbTableName = tableBean.getTableName(); subTableBean = tableBean; break; } } // 5. 构造数据结构(规范泛型) Map mainFormData = new HashMap<>(); Map> subFormDataMap = new HashMap<>(); List subFormDataList = new ArrayList<>(); Map mainData = new HashMap<>(); mainFormData.put(tableName, mainData); if (subDbTableName != null) { log.info("明细表表名为: " + subDbTableName); subFormDataMap.put(subDbTableName, subFormDataList); } // 6. 查询账单数据 List conditions = new ArrayList<>(); conditions.add(FormWhereCondition.build().display("账单-账单明细编号").value(billNo)); FormColumn formColumn = FormTableExecutor.queryOne(getTableContext(), conditions,false); // 7. 主数据非空判断 if (formColumn == null || formColumn.getFieldsMap() == null) { throw new Exception("根据账单编号:" + billNo + "未查询到账单数据"); } Map fieldsMap = formColumn.getFieldsMap(); BigDecimal accountsReceivable = BigDecimal.ZERO; // 初始化实际收款金额(避免null) BigDecimal actualReceipts = BigDecimal.ZERO; BigDecimal rate = new BigDecimal("0.994"); // 8. 组装子表数据 Map subTableRowData = new HashMap<>(); subTableRowData.put("账单-明细编号", fieldsMap.get("账单-账单明细编号")); subTableRowData.put("账单-开始日期", df.format((Date)fieldsMap.get("账单-开始日期"))); subTableRowData.put("账单-结束日期", df.format((Date)fieldsMap.get("账单-结束日期"))); subTableRowData.put("账单-当期缴费期限", fieldsMap.get("账单-当前缴费时限")); subTableRowData.put("账单-综合减免", fieldsMap.get("账单-减免金额") == null ? BigDecimal.ZERO : fieldsMap.get("账单-减免金额")); subTableRowData.put("账单-租费递增", fieldsMap.get("账单-租费递增") == null ? BigDecimal.ZERO : fieldsMap.get("账单-租费递增")); // 应收金额计算 BigDecimal receivable = (BigDecimal) fieldsMap.get("账单-应收租金"); if (receivable != null) { accountsReceivable = accountsReceivable.add(receivable); // 修复BigDecimal.setScale不生效问题 actualReceipts = accountsReceivable.multiply(rate).setScale(2, RoundingMode.HALF_UP); } subTableRowData.put("账单-应收租金", receivable); subTableRowData.put("账单-未收租金", fieldsMap.get("账单-未收租金")); subTableRowData.put("账单-本次收租金", receivable); subTableRowData.put("账单-本次收款日期", payDate); subTableRowData.put("账单-本次开票金额", receivable); subTableRowData.put("账单-未开票金额", receivable); subTableRowData.put("账单-资产编号", fieldsMap.get("资产编号")); subTableRowData.put("账单-资产名称", fieldsMap.get("资产名称")); FormFieldBean formFieldBean = subTableBean.getFieldBeanByDisplay("收款结果"); subTableRowData.put("收款结果", EnumMapUtils.getEnumItemValueByEnumId("已结清",formFieldBean.getEnumId())); subFormDataList.add(subTableRowData); // 9. 获取合同信息 + 非空校验 String contractNo = (String) fieldsMap.get("合同编号"); mainData.put("合同名称", fieldsMap.get("合同名称")); mainData.put("合同金额", fieldsMap.get("合同金额")); mainData.put("签订单位", fieldsMap.get("签订单位")); mainData.put("承租方类型", fieldsMap.get("承租方类型")); mainData.put("承租方名称", fieldsMap.get("承租方")); mainData.put("承租方编码", fieldsMap.get("承租方编号")); mainData.put("租金_费项_文本",fieldsMap.get("账单类型")); // 10. 经办人/部门信息(安全赋值) String assetNo = (String) fieldsMap.get("资产编号"); Map assetsManagerInfo = this.assetsService.getAssetsManagerInfo(assetNo); if (assetsManagerInfo != null && assetsManagerInfo.get("运营管理员") != null) { String managerId = String.valueOf(assetsManagerInfo.get("运营管理员")); try { V3xOrgMember member = this.orgManager.getMemberById(Long.parseLong(managerId)); if (member != null) { mainData.put("经办部门", member.getOrgDepartmentId()); mainData.put("经办单位", member.getOrgAccountId()); mainData.put("经办人员", managerId); } } catch (Exception e) { log.warn("获取经办人信息失败", e); } } // 11. 组装主表数据(线程安全日期) TableContext receivePayFlowTableContext = FormTableExecutor.master(templateCode); mainData.put("选择收款项", EnumMapUtils.getEnumItemValueByDisplayValue(receivePayFlowTableContext.getTableBean(), "选择收款项", "租金")); mainData.put("经办日期", LocalDate.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd"))); mainData.put("合同编号", contractNo); mainData.put("本次收款金额", actualReceipts); // 12. 启动流程 this.flowCreateService.flowStart("微信小程序支付完成收款登记", mainFormData, subFormDataMap, appName, templateCode); } }