chengf
2025-08-27 074caee550216dfd4bb676677ae33cbd837c5710
暂存0827
28个文件已修改
1个文件已添加
844 ■■■■ 已修改文件
java110-bean/src/main/java/com/java110/dto/fee/FeeConfigDto.java 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
java110-bean/src/main/java/com/java110/dto/fee/FeeDto.java 19 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
java110-bean/src/main/java/com/java110/dto/report/ReportExcelDto.java 65 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
java110-bean/src/main/java/com/java110/dto/wechat/SmallWeChatDto.java 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
java110-bean/src/main/java/com/java110/vo/api/fee/ApiFeeDataVo.java 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
java110-db/src/main/resources/mapper/fee/FeeConfigServiceDaoImplMapper.xml 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
java110-db/src/main/resources/mapper/fee/FeeServiceDaoImplMapper.xml 11 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
java110-db/src/main/resources/mapper/fee/PayFeeDetailNewV1ServiceDaoImplMapper.xml 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
java110-db/src/main/resources/mapper/fee/ReportFeeServiceDaoImplMapper.xml 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
java110-utils/src/main/java/com/java110/utils/util/DateUtil.java 32 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
service-acct/src/main/java/com/java110/acct/cmd/payment/CashierCmd.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
service-acct/src/main/java/com/java110/acct/cmd/payment/NativeQrcodePaymentCmd.java 132 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
service-acct/src/main/java/com/java110/acct/payment/adapt/fuiou/FuiouPaymentFactoryAdapt.java 90 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
service-fee/src/main/java/com/java110/fee/bmo/impl/QueryOweFeeImpl.java 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
service-fee/src/main/java/com/java110/fee/cmd/fee/ListFeeCmd.java 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
service-fee/src/main/java/com/java110/fee/cmd/fee/PayFeeCmd.java 97 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
service-fee/src/main/java/com/java110/fee/cmd/fee/ReportFeePropertyCmd.java 227 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
service-fee/src/main/java/com/java110/fee/cmd/fee/ReportFeeWriteOrderCmd.java 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
service-fee/src/main/java/com/java110/fee/cmd/feeConfig/DeleteFeeConfigCmd.java 10 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
service-fee/src/main/java/com/java110/fee/dao/impl/FeeServiceDaoImpl.java 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
service-fee/src/main/java/com/java110/fee/smo/impl/FeeDiscountInnerServiceSMOImpl.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
service-job/src/main/java/com/java110/job/importData/adapt/ImportCarHistoryFeeDetailQueueDataAdapt.java 33 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
service-job/src/main/java/com/java110/job/importData/adapt/ImportHistoryFeeDetailQueueDataAdapt.java 30 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
service-store/src/main/java/com/java110/store/api/ContractPartyaApi.java 10 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
springboot/src/main/resources/application-debug.yml 5 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
springboot/src/main/resources/application-debugg.yml 5 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
springboot/src/main/resources/application-dev.yml 5 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
springboot/src/main/resources/application-devlocal.yml 5 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
springboot/src/main/resources/application.yml 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
java110-bean/src/main/java/com/java110/dto/fee/FeeConfigDto.java
@@ -45,7 +45,17 @@
    private String feeTypeCd;
private String secondaryFeeTypeCd;
    private String[] feeTypeCds;
    public String[] getFeeTypeCds() {
        return feeTypeCds;
    }
    public void setFeeTypeCds(String[] feeTypeCds) {
        this.feeTypeCds = feeTypeCds;
    }
    private String secondaryFeeTypeCd;
private String secondaryFeeTypeCdName;
    private String computingFormula;
    private String computingFormulaName;
java110-bean/src/main/java/com/java110/dto/fee/FeeDto.java
@@ -44,6 +44,25 @@
    private Date startTime;
    @JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8")
    private Date endTime;
    private Date useStart;
    private Date useEnd;
    public Date getUseStart() {
        return useStart;
    }
    public void setUseStart(Date useStart) {
        this.useStart = useStart;
    }
    public Date getUseEnd() {
        return useEnd;
    }
    public void setUseEnd(Date useEnd) {
        this.useEnd = useEnd;
    }
    private String communityId;
    private String feeId;
    private String userId;
java110-bean/src/main/java/com/java110/dto/report/ReportExcelDto.java
New file
@@ -0,0 +1,65 @@
package com.java110.dto.report;
import com.java110.dto.room.RoomDto;
import java.util.ArrayList;
import java.util.List;
public class ReportExcelDto {
    private String test;
    private RoomDto roomDto;
    private int col;
    private int row;
    public RoomDto getRoomDto() {
        return roomDto;
    }
    public void setRoomDto(RoomDto roomDto) {
        this.roomDto = roomDto;
    }
    private List<List<ReportExcelDto>> header;
    private Object[] data;
    public List<List<ReportExcelDto>> getHeader() {
        return header;
    }
    public void setHeader(List<List<ReportExcelDto>> header) {
        this.header = header;
    }
    public Object[] getData() {
        return data;
    }
    public void setData(Object[] data) {
        this.data = data;
    }
    public String getTest() {
        return test;
    }
    public void setTest(String test) {
        this.test = test;
    }
    public int getCol() {
        return col;
    }
    public void setCol(int col) {
        this.col = col;
    }
    public int getRow() {
        return row;
    }
    public void setRow(int row) {
        this.row = row;
    }
}
java110-bean/src/main/java/com/java110/dto/wechat/SmallWeChatDto.java
@@ -38,6 +38,7 @@
    private String payPassword;
    private String objType;
    private String remarks;
    private String orderPre;
    private List<SmallWechatAttrDto> smallWechatAttrs;
@@ -46,6 +47,13 @@
    private String statusCd = "0";
    public String getOrderPre() {
        return orderPre;
    }
    public void setOrderPre(String orderPre) {
        this.orderPre = orderPre;
    }
    public String getMchId() {
        return mchId;
java110-bean/src/main/java/com/java110/vo/api/fee/ApiFeeDataVo.java
@@ -88,9 +88,17 @@
    private String scale;
    private String decimalPlace;
    private String units;
    private Date payStartDate;
    private Date payEndDate;
    private int monthCount;
    public int getMonthCount() {
        return monthCount;
    }
    public void setMonthCount(int monthCount) {
        this.monthCount = monthCount;
    }
    public Date getPayEndDate() {
        return payEndDate;
java110-db/src/main/resources/mapper/fee/FeeConfigServiceDaoImplMapper.xml
@@ -165,6 +165,12 @@
              </otherwise>
          </choose>
        </if>
        <if test="feeTypeCds !=null">
            and t.fee_type_cd in
            <foreach collection="feeTypeCds" item="item" open="(" close=")" separator=",">
                #{item}
            </foreach>
        </if>
        <if test="secondaryFeeTypeCd !=null and secondaryFeeTypeCd != ''">
            and t.secondary_fee_type_cd= #{secondaryFeeTypeCd}
        </if>
java110-db/src/main/resources/mapper/fee/FeeServiceDaoImplMapper.xml
@@ -241,7 +241,12 @@
        <if test="contractFee != null">
            and t.contract_fee = ${contractFee}
        </if>
        <if test="useStart != null">
            and t.start_time &lt;= #{useStart}
        </if>
        <if test="useEnd != null">
            and DATE_ADD(STR_TO_DATE(pfa1.`value`, '%Y-%m-%d 23:59:59.%f'), INTERVAL 2 DAY) >= #{useEnd}
        </if>
        order by t.create_time desc
        <if test="page != -1 and page != null ">
            limit #{page}, #{row}
@@ -955,7 +960,7 @@
          and t.community_id = #{communityId}
    </update>
    <select id="countValidPayFeeByConfigId" parameterType="Map" resultType="Integer">
        select count(1) from pay_fee where config_id = #{configId} and status_cd = 0
    <select id="countValidPayFeeByConfigId" parameterType="Map" resultType="Map">
        select count(1) count from pay_fee where config_id = #{configId} and status_cd = 0
    </select>
</mapper>
java110-db/src/main/resources/mapper/fee/PayFeeDetailNewV1ServiceDaoImplMapper.xml
@@ -648,5 +648,6 @@
        <if test="cashierName !=null and cashierName != ''">
            and t.cashier_name= #{cashierName}
        </if>
        order by pfa2.`value`
    </select>
</mapper>
java110-db/src/main/resources/mapper/fee/ReportFeeServiceDaoImplMapper.xml
@@ -259,7 +259,7 @@
        </if>
    </select>
    <select id="onceRoomFee">
    <select id="onceRoomFee" resultType="java.util.Map">
        WITH year_series AS (
            -- 生成2016-2025年完整年份序列
            SELECT 2016 + n AS year
@@ -569,12 +569,14 @@
            统计维度,
            应收月数,
            已收月数,
            (应收月数 - 已收月数) as 未收月数,
            应收区间,
            已收区间,
            未收区间,
            应收金额,
            实收金额,
            折扣金额
            折扣金额,
            (应收金额 - 实收金额 - 折扣金额) as 未收金额
        FROM grouped_data
        WHERE 应收金额 != 0
        ORDER BY
java110-utils/src/main/java/com/java110/utils/util/DateUtil.java
@@ -6,6 +6,9 @@
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.Duration;
import java.time.LocalDate;
import java.time.Period;
import java.time.format.DateTimeFormatter;
import java.util.*;
/**
@@ -36,6 +39,7 @@
    public static final String DATE_FORMATE_STRING_N = "HHmmss";
    public static final String DATE_FORMATE_STRING_O = "yyyyMMddHHmm";
    public static final String DATE_FORMATE_STRING_Q = "yyyy-MM";
    private static final DateTimeFormatter DEFAULT_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd");
    static {
@@ -1016,4 +1020,32 @@
        return result.toString();
    }
    /**
     * 计算两个字符串日期之间的月数(超过一个整月则+1)
     * @param startDateStr 开始日期字符串(格式:yyyy-MM-dd)
     * @param endDateStr 结束日期字符串(格式:yyyy-MM-dd)
     * @return 月数差
     */
    public static int calculateMonths(String startDateStr, String endDateStr) {
        // 1. 将字符串解析为LocalDate
        LocalDate startDate = LocalDate.parse(startDateStr, DEFAULT_FORMATTER);
        LocalDate endDate = LocalDate.parse(endDateStr, DEFAULT_FORMATTER);
        // 2. 确保开始日期在结束日期之前
        if (startDate.isAfter(endDate)) {
            LocalDate temp = startDate;
            startDate = endDate;
            endDate = temp;
        }
        // 3. 计算完整月数
        Period period = Period.between(startDate, endDate);
        int fullMonths = period.getYears() * 12 + period.getMonths();
        // 4. 若天数差>0,说明超过整月,额外加1
        if (period.getDays() > 0) {
            fullMonths++;
        }
        return fullMonths;
    }
}
service-acct/src/main/java/com/java110/acct/cmd/payment/CashierCmd.java
@@ -91,7 +91,7 @@
        PaymentOrderDto paymentOrderDto = paymentBusiness.unified(context, reqJson);
        paymentOrderDto.setAppId(appId);
        paymentOrderDto.setUserId(userId);
        paymentOrderDto.setMoney(1); //   TODO 测试数据
//        paymentOrderDto.setMoney(1); //   TODO 测试数据
        logger.debug(">>>>>>>>>>>>>>>>支付业务下单返回,{}", JSONObject.toJSONString(paymentOrderDto));
service-acct/src/main/java/com/java110/acct/cmd/payment/NativeQrcodePaymentCmd.java
@@ -7,23 +7,38 @@
import com.java110.core.context.ICmdDataFlowContext;
import com.java110.core.event.cmd.Cmd;
import com.java110.core.event.cmd.CmdEvent;
import com.java110.core.factory.CommunitySettingFactory;
import com.java110.core.factory.GenerateCodeFactory;
import com.java110.core.factory.WechatFactory;
import com.java110.core.log.LoggerFactory;
import com.java110.dto.payment.PaymentOrderDto;
import com.java110.dto.payment.*;
import com.java110.dto.wechat.SmallWeChatDto;
import com.java110.intf.acct.IPaymentKeyV1InnerServiceSMO;
import com.java110.intf.acct.IPaymentPoolConfigV1InnerServiceSMO;
import com.java110.intf.acct.IPaymentPoolV1InnerServiceSMO;
import com.java110.intf.acct.IPaymentPoolValueV1InnerServiceSMO;
import com.java110.intf.fee.IPayFeeV1InnerServiceSMO;
import com.java110.utils.cache.CommonCache;
import com.java110.utils.cache.MappingCache;
import com.java110.utils.cache.UrlCache;
import com.java110.utils.constant.MappingConstant;
import com.java110.utils.constant.WechatConstant;
import com.java110.utils.exception.CmdException;
import com.java110.utils.factory.ApplicationContextFactory;
import com.java110.utils.util.Assert;
import com.java110.utils.util.DateUtil;
import com.java110.utils.util.PayUtil;
import com.java110.vo.ResultVo;
import org.slf4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.*;
import org.springframework.web.client.RestTemplate;
import java.text.ParseException;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
/**
 * native qrcode 支付
@@ -36,6 +51,12 @@
    private static final Logger logger = LoggerFactory.getLogger(NativeQrcodePaymentCmd.class);
    protected static final String DEFAULT_PAYMENT_ADAPT = "wechatNativeQrcodePaymentFactory";// 默认微信通用支付
    @Autowired
    private IPaymentKeyV1InnerServiceSMO paymentKeyV1InnerServiceSMOImpl;
    @Autowired
    private IPaymentPoolValueV1InnerServiceSMO paymentPoolValueV1InnerServiceSMOImpl;
    @Autowired
    private IPaymentPoolConfigV1InnerServiceSMO paymentPoolConfigV1InnerServiceSMOImpl;
@@ -53,9 +74,48 @@
    }
    private static final String VERSION = "1.0";
    @Value("${fuiou.pay.unified-order-url}")
    public String PAY_UNIFIED_ORDER_URL;
    @Autowired
    private RestTemplate outRestTemplate;
    @Override
    public void doCmd(CmdEvent event, ICmdDataFlowContext context, JSONObject reqJson) throws CmdException, ParseException {
//        if (!(reqJson.containsKey("communityId"))){
//            reqJson.put("communityId","2025062600070012");
//        }
        PaymentPoolDto paymentPoolDto = new PaymentPoolDto();
        paymentPoolDto.setCommunityId(reqJson.getString("communityId"));
        paymentPoolDto.setPage(1);
        paymentPoolDto.setRow(10);
        List<PaymentPoolDto> paymentPoolDtos = paymentPoolV1InnerServiceSMOImpl.queryPaymentPools(paymentPoolDto);
        List<PaymentPoolDto> collect = paymentPoolDtos.stream().filter(e -> e.getPaymentType().equals("FUIOU")).collect(Collectors.toList());
        PaymentPoolValueDto paymentPoolValueDto = new PaymentPoolValueDto();
        paymentPoolValueDto.setPpId(collect.get(0).getPpId());
        paymentPoolValueDto.setCommunityId(reqJson.getString("communityId"));
        List<PaymentPoolValueDto> values =  paymentPoolValueV1InnerServiceSMOImpl.queryPaymentPoolValues(paymentPoolValueDto);
        Map<String, List<PaymentPoolValueDto>> payMap = values.stream().collect(Collectors.groupingBy(PaymentPoolValueDto::getColumnKey));
        SmallWeChatDto smallWeChatDto = new SmallWeChatDto();
        if(payMap.containsKey("FUIOU_APP_ID")){
            smallWeChatDto.setAppId(payMap.get("FUIOU_APP_ID").get(0).getColumnValue());
        }else{
            smallWeChatDto.setAppId(MappingCache.getValue(WechatConstant.WECHAT_DOMAIN, "appId"));
        }
        if(payMap.containsKey("FUIOU_MCHNT_KEY")){
            smallWeChatDto.setAppSecret(payMap.get("FUIOU_MCHNT_KEY").get(0).getColumnValue());
        }else{
            smallWeChatDto.setAppSecret(MappingCache.getValue(WechatConstant.WECHAT_DOMAIN, "appSecret"));
        }
        if(payMap.containsKey("FUIOU_ORDER_PRE")){
            smallWeChatDto.setOrderPre(payMap.get("FUIOU_ORDER_PRE").get(0).getColumnValue());
        }
        if(payMap.containsKey("FUIOU_MERCHANT_ID")){
            smallWeChatDto.setMchId(payMap.get("FUIOU_MERCHANT_ID").get(0).getColumnValue());
        }else{
            smallWeChatDto.setMchId(MappingCache.getValue(MappingConstant.WECHAT_STORE_DOMAIN, "mchId"));
        }
        logger.debug(">>>>>>>>>>>>>>>>支付参数报文,{}", reqJson.toJSONString());
        String appId = context.getReqHeaders().get("app-id");
        String userId = context.getReqHeaders().get("user-id");
@@ -81,15 +141,69 @@
        // redis 中 保存 请求参数
        CommonCache.setValue("nativeQrcodePayment_" + token, reqJson.toJSONString(), CommonCache.PAY_DEFAULT_EXPIRE_TIME);
        JSONObject result = new JSONObject();
//        result.put("codeUrl", UrlCache.getOwnerUrl() + "/#/pages/fee/qrCodeCashier?qrToken=" + token);
        result.put("codeUrl", "https://ccloud.fuioupay.com/decca/native?token=20250812201258114913");
//        result.put("codeUrl", UrlCache.getOwnerUrl() + "/#/pages/fee/qrCodeCashier");
        ResponseEntity<String> responseEntity = ResultVo.createResponseEntity(result);
//
//
//        List<PaymentKeyDto> paymentKeyDtos = null;
//
//        PaymentKeyDto paymentKeyDto = new  PaymentKeyDto();
//        paymentKeyDto.setPaymentType("FUIOU");
//        paymentKeyDtos = paymentKeyV1InnerServiceSMOImpl.queryPaymentKeys(paymentKeyDto);
//
        logger.debug("调用支付厂家返回,{}", responseEntity);
        context.setResponseEntity(responseEntity);
        String systemName = MappingCache.getValue(WechatConstant.WECHAT_DOMAIN, WechatConstant.PAY_GOOD_NAME);
        JSONObject paramMap = new JSONObject();
        paramMap.put("version", VERSION);
        paramMap.put("mchnt_cd", smallWeChatDto.getMchId()); // 富友分配给二级商户的商户号
        paramMap.put("random_str", PayUtil.makeUUID(32));
        paramMap.put("order_amt", "1");
        String generatorId = GenerateCodeFactory.getGeneratorId("81");
        paramMap.put("mchnt_order_no", smallWeChatDto.getOrderPre() + generatorId);
        paramMap.put("txn_begin_ts", DateUtil.getNow(DateUtil.DATE_FORMATE_STRING_DEFAULT));
        paramMap.put("goods_des", systemName + "测试");
        paramMap.put("term_id", "abcdefgh");
        paramMap.put("term_ip", PayUtil.getLocalIp());
        paramMap.put("notify_url", "?wId=" + WechatFactory.getWId(smallWeChatDto.getAppId()));
        paramMap.put("trade_type", "LETPAY");
        paramMap.put("order_type", "WECHAT");
//        paramMap.put("sub_openid", openid);
//        paramMap.put("sub_appid", smallWeChatDto.getAppId());
        paramMap.put("sign", createSign(paramMap, "f00dac5077ea11e754e14c9541bc0170"));
        logger.debug("调用支付统一下单接口" + paramMap.toJSONString());
        HttpHeaders headers = new HttpHeaders();
        headers.add("Content-Type", "application/json");
        HttpEntity httpEntity = new HttpEntity(paramMap.toJSONString(), headers);
        ResponseEntity<String> responseEntity = outRestTemplate.exchange(PAY_UNIFIED_ORDER_URL
                , HttpMethod.POST, httpEntity, String.class);
        if(result.containsKey("result_code") && result.get("result_code").equals("000000")){
            result.put("codeUrl", JSONObject.parseObject(responseEntity.getBody()).get("qr_code"));
            ResponseEntity<String> responseEntity2 = ResultVo.createResponseEntity(responseEntity);
            logger.debug("调用支付厂家返回,{}", responseEntity2);
            context.setResponseEntity(responseEntity2);
        }else{
            result.put("codeUrl", JSONObject.parseObject(responseEntity.getBody()).get("qr_code"));
            ResponseEntity<String> responseEntity2 = ResultVo.createResponseEntity(responseEntity);
            logger.debug("调用支付厂家返回,{}", responseEntity);
            context.setResponseEntity(responseEntity2);
        }
    }
    private String createSign(JSONObject paramMap, String payPassword) {
        String str = paramMap.getString("mchnt_cd") + "|"
                + paramMap.getString("order_type") + "|"
                + paramMap.getString("order_amt") + "|"
                + paramMap.getString("mchnt_order_no") + "|"
                + paramMap.getString("txn_begin_ts") + "|"
                + paramMap.getString("goods_des") + "|"
                + paramMap.getString("term_id") + "|"
                + paramMap.getString("term_ip") + "|"
                + paramMap.getString("notify_url") + "|"
                + paramMap.getString("random_str") + "|"
                + paramMap.getString("version") + "|"
                + payPassword;
        return PayUtil.md5(str);
    }
}
service-acct/src/main/java/com/java110/acct/payment/adapt/fuiou/FuiouPaymentFactoryAdapt.java
@@ -10,7 +10,11 @@
import com.java110.dto.owner.OwnerAppUserDto;
import com.java110.dto.payment.NotifyPaymentOrderDto;
import com.java110.dto.payment.PaymentOrderDto;
import com.java110.dto.payment.PaymentPoolDto;
import com.java110.dto.payment.PaymentPoolValueDto;
import com.java110.dto.wechat.SmallWeChatDto;
import com.java110.intf.acct.IPaymentPoolV1InnerServiceSMO;
import com.java110.intf.acct.IPaymentPoolValueV1InnerServiceSMO;
import com.java110.intf.store.ISmallWechatV1InnerServiceSMO;
import com.java110.intf.user.IOwnerAppUserInnerServiceSMO;
import com.java110.utils.cache.MappingCache;
@@ -28,6 +32,7 @@
import java.util.Map;
import java.util.SortedMap;
import java.util.TreeMap;
import java.util.stream.Collectors;
/**
 * 富友 支付
@@ -93,6 +98,11 @@
    @Autowired
    private RestTemplate outRestTemplate;
    @Autowired
    private IPaymentPoolV1InnerServiceSMO paymentPoolV1InnerServiceSMOImpl;
    @Autowired
    private IPaymentPoolValueV1InnerServiceSMO paymentPoolValueV1InnerServiceSMOImpl;
    @Override
@@ -109,15 +119,16 @@
        String openId = reqJson.getString("openId");
        if(StringUtil.isEmpty(openId)) {
            String appType = OwnerAppUserDto.APP_TYPE_WECHAT_MINA;
            if (AppDto.WECHAT_OWNER_APP_ID.equals(appId)) {
                appType = OwnerAppUserDto.APP_TYPE_WECHAT;
            } else if (AppDto.WECHAT_MINA_OWNER_APP_ID.equals(appId)) {
                appType = OwnerAppUserDto.APP_TYPE_WECHAT_MINA;
            } else {
                appType = OwnerAppUserDto.APP_TYPE_APP;
            }
            //由于现在只有006,所以写死WECHAT,后续如果有多种支付方式则重新设计
//            String appType = OwnerAppUserDto.APP_TYPE_WECHAT_MINA;
//            if (AppDto.WECHAT_OWNER_APP_ID.equals(appId)) {
//                appType = OwnerAppUserDto.APP_TYPE_WECHAT;
//            } else if (AppDto.WECHAT_MINA_OWNER_APP_ID.equals(appId)) {
//                appType = OwnerAppUserDto.APP_TYPE_WECHAT_MINA;
//            } else {
//                appType = OwnerAppUserDto.APP_TYPE_APP;
//            }
            String appType = OwnerAppUserDto.APP_TYPE_WECHAT;
            OwnerAppUserDto ownerAppUserDto = new OwnerAppUserDto();
            ownerAppUserDto.setUserId(userId);
            ownerAppUserDto.setAppType(appType);
@@ -181,8 +192,8 @@
        if (feeName.length() > 127) {
            feeName = feeName.substring(0, 126);
        }
        String orderPre = CommunitySettingFactory.getValue(smallWeChatDto.getObjId(), "FUIOU_ORDER_PRE");
//        String orderPre = CommunitySettingFactory.getValue(smallWeChatDto.getObjId(), "FUIOU_ORDER_PRE");
        String orderPre = smallWeChatDto.getOrderPre();
        JSONObject paramMap = new JSONObject();
        paramMap.put("mchnt_cd", smallWeChatDto.getMchId()); // 富友分配给二级商户的商户号
        paramMap.put("order_type", "WECHAT");
@@ -285,24 +296,53 @@
    private SmallWeChatDto getSmallWechat(JSONObject paramIn) {
//        SmallWeChatDto smallWeChatDto = new SmallWeChatDto();
//        smallWeChatDto.setObjId(paramIn.getString("communityId"));
//        smallWeChatDto.setAppId(paramIn.getString("appId"));
//        smallWeChatDto.setPage(1);
//        smallWeChatDto.setRow(1);
//        List<SmallWeChatDto> smallWeChatDtos = smallWechatV1InnerServiceSMOImpl.querySmallWechats(smallWeChatDto);
//        if (smallWeChatDtos == null || smallWeChatDtos.size() < 1) {
        SmallWeChatDto smallWeChatDto = new SmallWeChatDto();
        smallWeChatDto.setObjId(paramIn.getString("communityId"));
        smallWeChatDto.setAppId(paramIn.getString("appId"));
        smallWeChatDto.setPage(1);
        smallWeChatDto.setRow(1);
        List<SmallWeChatDto> smallWeChatDtos = smallWechatV1InnerServiceSMOImpl.querySmallWechats(smallWeChatDto);
        if (smallWeChatDtos == null || smallWeChatDtos.size() < 1) {
            smallWeChatDto = new SmallWeChatDto();
        //由于富有支付方式要从数据库里面取值,所以此处要查询
        PaymentPoolDto paymentPoolDto = new PaymentPoolDto();
        paymentPoolDto.setCommunityId(paramIn.getString("communityId"));
        paymentPoolDto.setPage(1);
        paymentPoolDto.setRow(10);
        List<PaymentPoolDto> paymentPoolDtos = paymentPoolV1InnerServiceSMOImpl.queryPaymentPools(paymentPoolDto);
        List<PaymentPoolDto> collect = paymentPoolDtos.stream().filter(e -> e.getPaymentType().equals("FUIOU")).collect(Collectors.toList());
        PaymentPoolValueDto paymentPoolValueDto = new PaymentPoolValueDto();
        paymentPoolValueDto.setPpId(collect.get(0).getPpId());
        paymentPoolValueDto.setCommunityId(paramIn.getString("communityId"));
        List<PaymentPoolValueDto> values =  paymentPoolValueV1InnerServiceSMOImpl.queryPaymentPoolValues(paymentPoolValueDto);
        Map<String, List<PaymentPoolValueDto>> payMap = values.stream().collect(Collectors.groupingBy(PaymentPoolValueDto::getColumnKey));
        if(payMap.containsKey("FUIOU_APP_ID")){
            smallWeChatDto.setAppId(payMap.get("FUIOU_APP_ID").get(0).getColumnValue());
        }else{
            smallWeChatDto.setAppId(MappingCache.getValue(WechatConstant.WECHAT_DOMAIN, "appId"));
            smallWeChatDto.setAppSecret(MappingCache.getValue(WechatConstant.WECHAT_DOMAIN, "appSecret"));
            smallWeChatDto.setMchId(MappingCache.getValue(MappingConstant.WECHAT_STORE_DOMAIN, "mchId"));
            smallWeChatDto.setPayPassword(MappingCache.getValue(MappingConstant.WECHAT_STORE_DOMAIN, "key"));
            smallWeChatDto.setObjId(paramIn.getString("communityId"));
            return smallWeChatDto;
        }
        if(payMap.containsKey("FUIOU_MCHNT_KEY")){
            smallWeChatDto.setAppSecret(payMap.get("FUIOU_MCHNT_KEY").get(0).getColumnValue());
        }else{
            smallWeChatDto.setAppSecret(MappingCache.getValue(WechatConstant.WECHAT_DOMAIN, "appSecret"));
        }
        if(payMap.containsKey("FUIOU_MERCHANT_ID")){
            smallWeChatDto.setMchId(payMap.get("FUIOU_MERCHANT_ID").get(0).getColumnValue());
        }else{
            smallWeChatDto.setMchId(MappingCache.getValue(MappingConstant.WECHAT_STORE_DOMAIN, "mchId"));
        }
        if(payMap.containsKey("FUIOU_ORDER_PRE")){
            smallWeChatDto.setOrderPre(payMap.get("FUIOU_ORDER_PRE").get(0).getColumnValue());
        }else{
            smallWeChatDto.setOrderPre("1066");
        }
        smallWeChatDto.setPayPassword(MappingCache.getValue(MappingConstant.WECHAT_STORE_DOMAIN, "key"));
        smallWeChatDto.setObjId(paramIn.getString("communityId"));
        return smallWeChatDto;
//        }
        return BeanConvertUtil.covertBean(smallWeChatDtos.get(0), SmallWeChatDto.class);
//        return BeanConvertUtil.covertBean(smallWeChatDtos.get(0), SmallWeChatDto.class);
    }
    /**
service-fee/src/main/java/com/java110/fee/bmo/impl/QueryOweFeeImpl.java
@@ -314,6 +314,9 @@
                apiFeeDataVo.setPayEndDate(dateMinusOneDay);
            }
        }
        //计算MaxEndTime和payStartDate之间的月数
        int monthCount = DateUtil.calculateMonths(DateUtil.getFormatTimeStringB(apiFeeDataVo.getPayStartDate()), apiFeeDataVo.getMaxEndTime());
        apiFeeDataVo.setMonthCount(monthCount);
        return ResultVo.createResponseEntity(apiFeeDataVo);
    }
service-fee/src/main/java/com/java110/fee/cmd/fee/ListFeeCmd.java
@@ -142,6 +142,10 @@
                apiFeeDataVo.setEndTime(apiFeeDataVo.getEndTime() == null ? null : apiFeeDataVo.getEndTime().split(" ")[0]);
                apiFeeDataVo.setMaxEndTime(apiFeeDataVo.getMaxEndTime() == null ? null : apiFeeDataVo.getMaxEndTime().split(" ")[0]);
                apiFeeDataVo.setDeadlineTime(apiFeeDataVo.getDeadlineTime() == null ? null : apiFeeDataVo.getDeadlineTime().split(" ")[0]);
                //计算monthCount
                //计算MaxEndTime和endTime之间的月数
                int monthCount = DateUtil.calculateMonths(apiFeeDataVo.getEndTime(), apiFeeDataVo.getMaxEndTime());
                apiFeeDataVo.setMonthCount(monthCount);
                //获取付费对象类型
                String payerObjType = apiFeeDataVo.getPayerObjType();
                if (FeeDto.PAYER_OBJ_TYPE_CAR.equals(payerObjType)) {
service-fee/src/main/java/com/java110/fee/cmd/fee/PayFeeCmd.java
@@ -8,6 +8,7 @@
import com.java110.core.context.ICmdDataFlowContext;
import com.java110.core.event.cmd.Cmd;
import com.java110.core.event.cmd.CmdEvent;
import com.java110.core.factory.CommunitySettingFactory;
import com.java110.core.factory.GenerateCodeFactory;
import com.java110.core.factory.Java110TransactionalFactory;
import com.java110.core.log.LoggerFactory;
@@ -39,6 +40,7 @@
import com.java110.po.owner.RepairUserPo;
import com.java110.po.payFee.PayFeeDetailDiscountPo;
import com.java110.utils.cache.CommonCache;
import com.java110.utils.cache.MappingCache;
import com.java110.utils.constant.FeeFlagTypeConstant;
import com.java110.utils.exception.CmdException;
import com.java110.utils.lock.DistributedLock;
@@ -127,6 +129,18 @@
    @Autowired
    private IFinishFeeNotify finishFeeNotifyImpl;
    //域
    public static final String DOMAIN_COMMON = "DOMAIN.COMMON";
    //键
    public static final String TOTAL_FEE_PRICE = "TOTAL_FEE_PRICE";
    //键
    public static final String RECEIVED_AMOUNT_SWITCH = "RECEIVED_AMOUNT_SWITCH";
    //禁用电脑端提交收费按钮
    public static final String OFFLINE_PAY_FEE_SWITCH = "OFFLINE_PAY_FEE_SWITCH";
    @Override
    public void validate(CmdEvent event, ICmdDataFlowContext cmdDataFlowContext, JSONObject reqJson) throws CmdException {
        Assert.jsonObjectHaveKey(reqJson, "communityId", "请求报文中未包含communityId节点");
@@ -203,6 +217,13 @@
                Assert.hasKeyAndValue(param, "discountId", "未包含优惠ID");
                Assert.hasKeyAndValue(param, "discountPrice", "未包含优惠金额");
            }
        }
        //校验实付金额不能大于欠款金额
        computeFeePrice(feeDtos);
        BigDecimal amountOwed = new BigDecimal(feeDtos.get(0).getAmountOwed()); //应收款
        BigDecimal receivedAmount = new BigDecimal(reqJson.getString("receivedAmount"));
        if(receivedAmount.compareTo(amountOwed) >= 1){
            throw new IllegalArgumentException("实付金额不能大于欠费金额");
        }
    }
@@ -325,6 +346,82 @@
        cmdDataFlowContext.setResponseEntity(ResultVo.createResponseEntity(feeReceiptDetailDto));
    }
    private void computeFeePrice(List<FeeDto> feeDtos) {
        if (ListUtil.isNull(feeDtos)) {
            return;
        }
        String val = CommunitySettingFactory.getValue(feeDtos.get(0).getCommunityId(), TOTAL_FEE_PRICE);
        if (StringUtil.isEmpty(val)) {
            val = MappingCache.getValue(DOMAIN_COMMON, TOTAL_FEE_PRICE);
        }
        //先取单小区的如果没有配置 取 全局的
        String received_amount_switch = CommunitySettingFactory.getValue(feeDtos.get(0).getCommunityId(), RECEIVED_AMOUNT_SWITCH);
        if (StringUtil.isEmpty(received_amount_switch)) {
            received_amount_switch = MappingCache.getValue(DOMAIN_COMMON, RECEIVED_AMOUNT_SWITCH);
        }
        //先取单小区的如果没有配置 取 全局的
        String offlinePayFeeSwitch = CommunitySettingFactory.getValue(feeDtos.get(0).getCommunityId(), OFFLINE_PAY_FEE_SWITCH);
        if (StringUtil.isEmpty(offlinePayFeeSwitch)) {
            offlinePayFeeSwitch = MappingCache.getValue(DOMAIN_COMMON, OFFLINE_PAY_FEE_SWITCH);
        }
        for (FeeDto feeDto : feeDtos) {
            try {
                // 轮数 * 周期 * 30 + 开始时间 = 目标 到期时间
                Map<String, Object> targetEndDateAndOweMonth = computeFeeSMOImpl.getTargetEndDateAndOweMonth(feeDto);
                Date targetEndDate = (Date) targetEndDateAndOweMonth.get("targetEndDate");
                double oweMonth = (double) targetEndDateAndOweMonth.get("oweMonth");
                feeDto.setCycle(feeDto.getPaymentCycle());
                //todo 这里考虑 账单模式的场景
                if (FeeDto.FEE_FLAG_ONCE.equals(feeDto.getFeeFlag())) {
                    feeDto.setCycle(oweMonth + "");
                }
                feeDto.setDeadlineTime(targetEndDate);
                //todo 算费
                doComputeFeePrice(feeDto, oweMonth);
                feeDto.setVal(val);
                //关闭 线下收银功能
                if (StringUtil.isEmpty(received_amount_switch)) {
                    feeDto.setReceivedAmountSwitch("1");//默认启用实收款输入框
                } else {
                    feeDto.setReceivedAmountSwitch(received_amount_switch);
                }
                feeDto.setOfflinePayFeeSwitch(offlinePayFeeSwitch);
            } catch (Exception e) {
                logger.error("查询费用信息 ,费用信息错误", e);
            }
            //去掉多余0
            feeDto.setSquarePrice(Double.parseDouble(feeDto.getSquarePrice()) + "");
            feeDto.setAdditionalAmount(Double.parseDouble(feeDto.getAdditionalAmount()) + "");
        }
    }
    /**
     * 根据房屋来算单价
     *
     * @param feeDto
     */
    private void doComputeFeePrice(FeeDto feeDto, double oweMonth) {
        String computingFormula = feeDto.getComputingFormula();
        Map feePriceAll = computeFeeSMOImpl.getFeePrice(feeDto);
        feeDto.setFeePrice(Double.parseDouble(feePriceAll.get("feePrice").toString()));
        //BigDecimal feeTotalPrice = new BigDecimal(Double.parseDouble(feePriceAll.get("feeTotalPrice").toString()));
        feeDto.setFeeTotalPrice(MoneyUtil.computePriceScale(Double.parseDouble(feePriceAll.get("feeTotalPrice").toString()),
                feeDto.getScale(),
                Integer.parseInt(feeDto.getDecimalPlace())));
        BigDecimal curFeePrice = new BigDecimal(feeDto.getFeePrice());
        curFeePrice = curFeePrice.multiply(new BigDecimal(oweMonth));
        feeDto.setAmountOwed(MoneyUtil.computePriceScale(curFeePrice.doubleValue(), feeDto.getScale(), Integer.parseInt(feeDto.getDecimalPlace())) + "");
        //动态费用
        if ("4004".equals(computingFormula)
                && FeeDto.FEE_FLAG_ONCE.equals(feeDto.getFeeFlag())
                && !FeeDto.STATE_FINISH.equals(feeDto.getState())
                && feeDto.getDeadlineTime() == null) {
            feeDto.setDeadlineTime(DateUtil.getCurrentDate());
        }
        //考虑租金递增
        computeFeeSMOImpl.dealRentRate(feeDto);
    }
    private void dealUserAccount(JSONObject paramObj, PayFeeDetailPo payFeeDetailPo) {
        //判断选择的账号
service-fee/src/main/java/com/java110/fee/cmd/fee/ReportFeePropertyCmd.java
@@ -9,6 +9,7 @@
import com.java110.dto.dict.DictDto;
import com.java110.dto.fee.FeeConfigDto;
import com.java110.dto.fee.FeeDto;
import com.java110.dto.report.ReportExcelDto;
import com.java110.dto.report.ReportQueryRecord;
import com.java110.dto.room.RoomDto;
import com.java110.intf.community.ICommunityInnerServiceSMO;
@@ -19,14 +20,17 @@
import com.java110.utils.exception.CmdException;
import com.java110.utils.util.Assert;
import com.java110.utils.util.BeanConvertUtil;
import com.java110.utils.util.DateUtil;
import com.java110.vo.FeeQueryParams;
import com.java110.vo.ResultVo;
import com.sun.org.apache.regexp.internal.RE;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import java.math.BigDecimal;
import java.text.ParseException;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
@@ -79,7 +83,12 @@
        reportQueryRecord.setOperator("白单流水物业表");
        List<ReportQueryRecord> reportQueryRecords = reportFeeInnerServiceSMOImpl.queryReport(BeanConvertUtil.beanCovertMap(reportQueryRecord));
        if(reportQueryRecords.size()>0 && !reqJson.containsKey("reload")){
        if (reqJson.containsKey("roomId")){
            ReportExcelDto reportExcelDto = new ReportExcelDto();
//            reportExcelDto.setRoomDto(roomInnerServiceSMOImpl.queryRooms());
        }
        else if(reportQueryRecords.size()>0 && !reqJson.containsKey("reload")){
            ResultVo resultVo = new ResultVo(JSONObject.parse(reportQueryRecords.get(reportQueryRecords.size()-1).getReportContent()));
            ResponseEntity<String> responseEntity = new ResponseEntity<String>(resultVo.toString(), HttpStatus.OK);
@@ -97,64 +106,208 @@
            roomDto.setCommunityId(reqJson.getString("communityId"));
            roomDto.setRow(row);
            roomDto.setPage(page);
            int count = roomInnerServiceSMOImpl.queryRoomsCount(roomDto);
            List<Map> rooms = roomInnerServiceSMOImpl.queryRoomsAsReport(roomDto);
            FeeConfigDto feeConfigDto = new FeeConfigDto();
            feeConfigDto.setCommunityId(reqJson.getString("communityId"));
            feeConfigDto.setConfigIds(new String[]{"630000001","630000002"});
            feeConfigDto.setFeeTypeCds(new String[]{"630000001","630000002"});
            feeConfigDto.setRow(2);
            feeConfigDto.setPage(1);
            List<FeeConfigDto> feeConfigDtos = feeConfigInnerServiceSMOImpl.queryFeeConfigs(feeConfigDto);
            int arrLength = 11 + (2 * feeConfigDtos.size()) + 8 + ((endYear - startYear + 1) * 3);
            String[] header = new String[arrLength];
            headerDoing(header,feeConfigDtos,startYear,endYear);
            for(Map room : rooms){
            int arrLength = 11 + (2 * feeConfigDtos.size()) + 8 + ((endYear - startYear + 1) * 3 + 10) - 9;
            ReportExcelDto[] header = new ReportExcelDto[arrLength];
            List<List<ReportExcelDto>> lists = headerDoing(feeConfigDtos, startYear, endYear, arrLength);
            test[0] = header;
            for (int i = 1; i <= rooms.size(); i++) {
                Map map = rooms.get(i - 1);
                String[] strings = new String[arrLength];
                strings[0] = String.valueOf(row * (page - 1) + i);
                strings[1] = String.valueOf(rooms.get(i - 1).get("property_type"));
                strings[2] = rooms.get(i - 1).get("floor_num").toString();
                strings[3] = rooms.get(i - 1).get("unit_num").toString();
                strings[4] = rooms.get(i - 1).get("room_num").toString();
                strings[5] = strings[3] + "-" +  strings[4];
                strings[6] = rooms.get(i - 1).get("property_address").toString();
                strings[7] = rooms.get(i - 1).get("room_area").toString();
                strings[8] = rooms.get(i - 1).get("name").toString();
                for (int j = 1; j <= feeConfigDtos.size(); j++) {
                    strings[8 + j] = feeConfigDtos.get(j - 1).getSquarePrice();
                }
                strings[8 + feeConfigDtos.size() + 1] = "";
                for (int j = 1; j <= feeConfigDtos.size(); j++) {
                    strings[8 + feeConfigDtos.size() + 1 + j] = (doublequ2(Double.parseDouble(feeConfigDtos.get(j - 1).getSquarePrice()) * Double.parseDouble(String.valueOf((BigDecimal) rooms.get(i - 1).get("room_area")))))+"";
                }
                strings[8 + (2 * feeConfigDtos.size()) + 2] = (doublequ2(Double.parseDouble(feeConfigDtos.get(feeConfigDtos.size() - 1).getSquarePrice()) * Double.parseDouble(String.valueOf((BigDecimal) rooms.get(i - 1).get("room_area")))))+"";
                HashMap<Object, Object> objectObjectHashMap = new HashMap<>();
                objectObjectHashMap.put("payObjId", map.get("room_id"));
                List<Map> fee = reportFeeInnerServiceSMOImpl.onceRoomFee(objectObjectHashMap);
                double allMoney = 0;
                double allPayMoney = 0;
                int monthCount = 0;
                int noPayMoney = 0;
                int year1 = 0;
                int year2 = 0;
                double discountMoney = 0;
                String noPayDate = "";
                currentYear = DateUtil.getYear();
                for (Map map1 : fee){
                    if(map1.containsKey("统计维度") && !(map1.get("统计维度").toString().contains("总计"))){
                        allMoney += ((BigDecimal) map1.get("应收金额")).doubleValue();
                        allPayMoney += ((BigDecimal) map1.get("实收金额")).doubleValue();
                        monthCount += ((BigDecimal)map1.get("未收月数")).intValue();
                        noPayMoney += ((BigDecimal)map1.get("未收金额")).intValue();
                        noPayDate = noPayDate + map1.get("未收区间");
                        discountMoney += ((BigDecimal)map1.get("折扣金额")).doubleValue();
                        if(map1.get("统计维度").equals("2026")){
                            year1 += ((BigDecimal) map1.get("应收金额")).doubleValue();
                        }
                        if(map1.get("统计维度").equals("2027")){
                            year2 += ((BigDecimal) map1.get("应收金额")).doubleValue();
                        }
                    }
                }
                for (int x = endYear ; x >= startYear ; x --){
                    strings[8 + (2 * feeConfigDtos.size()) + 10 + (3 * (endYear - x)) + 1] = "0";
                    strings[8 + (2 * feeConfigDtos.size()) + 10 + (3 * (endYear - x)) + 2] = "";
                    strings[8 + (2 * feeConfigDtos.size()) + 10 + (3 * (endYear - x)) + 3] = "";
                    for (Map map1 : fee){
                        if(map1.get("统计维度").equals((endYear - x + startYear)+"年")) {
                            strings[8 + (2 * feeConfigDtos.size()) + 10 + (3 * (endYear - x)) + 1] = Integer.parseInt(strings[8 + (2 * feeConfigDtos.size()) + 10 + (3 * (endYear - x)) + 1]) + ((BigDecimal) map1.get("已收月数")).intValue() + "";
                            if(map1.containsKey("已收区间")){
                                strings[8 + (2 * feeConfigDtos.size()) + 10 + (3 * (endYear - x)) + 2] = strings[8 + (2 * feeConfigDtos.size()) + 10 + (3 * (endYear - x)) + 2] + "  " + map1.get("已收区间");
                            }
                            if(map1.containsKey("未收区间")){
                                strings[8 + (2 * feeConfigDtos.size()) + 10 + (3 * (endYear - x)) + 3] = strings[8 + (2 * feeConfigDtos.size()) + 10 + (3 * (endYear - x)) + 3] + "  " + map1.get("未收区间");
                            }
                        }
                    }
                }
                strings[8 + (2 * feeConfigDtos.size()) + 3] = allMoney+"";
                strings[8 + (2 * feeConfigDtos.size()) + 4] = allPayMoney+"";
                strings[8 + (2 * feeConfigDtos.size()) + 5] = "";
                strings[8 + (2 * feeConfigDtos.size()) + 6] = year1+"";//2026
                strings[8 + (2 * feeConfigDtos.size()) + 7] = year2+"";//2027
                strings[8 + (2 * feeConfigDtos.size()) + 8] = monthCount+"";
                strings[8 + (2 * feeConfigDtos.size()) + 9] = noPayMoney+"";
                strings[8 + (2 * feeConfigDtos.size()) + 10] = "";//22
                strings[8 + (2 * feeConfigDtos.size()) + 11] = "";//23历年待收
                strings[8 + (2 * feeConfigDtos.size()) + 10 + (3 * (endYear - startYear)) + 3 + 1] = discountMoney+"";
                test[i - 1] = strings;
            }
            reportQueryRecord.setCommunityId(reqJson.getString("communityId"));
            reportQueryRecord.setQueryStatus("0");
            reportQueryRecord.setEndYear(currentYear+"");
//            reportQueryRecord.setReportContent(JSONObject.toJSONString());
            ReportExcelDto reportExcelDto = new ReportExcelDto();
            reportExcelDto.setHeader(lists);
            reportExcelDto.setData(test);
            reportQueryRecord.setReportContent(JSONObject.toJSONString(reportExcelDto));
            reportQueryRecord.setOperator("白单流水物业表");
//            int i = reportFeeInnerServiceSMOImpl.saveReport(BeanConvertUtil.beanCovertMap(reportQueryRecord));
            String[][] strings = new String[10][57];
            ResultVo resultVo = new ResultVo(strings);
            ResultVo resultVo = new ResultVo(reportExcelDto);
            resultVo.setTotal(count);
            resultVo.setRecords(count / row);
            ResponseEntity<String> responseEntity = new ResponseEntity<String>(resultVo.toString(), HttpStatus.OK);
            context.setResponseEntity(responseEntity);
        }
    }
    private void headerDoing(String[] header,List<FeeConfigDto> feeConfigDtos,int startYear, int endYear) {
    private List<List<ReportExcelDto>> headerDoing(List<FeeConfigDto> feeConfigDtos, int startYear, int endYear, int arrLength) {
        LinkedList<List<ReportExcelDto>> reportExcelDtos = new LinkedList<>();
        int feeRow = feeConfigDtos.size();
        header[0] = "序号";
        header[1] = "物业类型";
        header[2] = "楼栋号/弄";
        header[3] = "门号";
        header[4] = "室号";
        header[5] = "门室号";
        header[6] = "产证地址";
        header[7] = "收费面积(m²)";
        header[8] = "购房人姓名";
        header[9] = "门室号";
        for (int i=0;i<feeRow;i++){
            header[9 + i + 1] = feeConfigDtos.get(0).getFeeName();
        LinkedList<ReportExcelDto> header = new LinkedList<>();
// 1. 固定表头项:严格按原代码col值设置
        header.add(createHeaderRow("序号", 1, 3));          // 原row.setCol(1)
        header.add(createHeaderRow("物业类型", 1, 3));      // 原未改col,沿用前一个1
        header.add(createHeaderRow("楼栋号/弄", 1, 3));    // 原未改col,沿用1
        header.add(createHeaderRow("门号", 1, 3));          // 原未改col,沿用1
        header.add(createHeaderRow("室号", 1, 3));          // 原未改col,沿用1
        header.add(createHeaderRow("门室号", 1, 3));        // 原未改col,沿用1
        header.add(createHeaderRow("产证地址", 1, 3));      // 原未改col,沿用1
        header.add(createHeaderRow("收费面积(m²)", 1, 3));// 原未改col,沿用1
        header.add(createHeaderRow("购房人姓名", 1, 3));    // 原未改col,沿用1
// 2. 第一个feeRow循环:原未显式改col,沿用前一个1(按原逻辑保持col=1)
        for (int i = 0; i < feeRow; i++) {
            header.add(createHeaderRow(feeConfigDtos.get(0).getFeeName(), 1, 3));
        }
        header[9 + feeRow + 1] = "年应收款";
        header[9 + feeRow + 2] = "合计(2020年1月-至今)-应收";
        header[9 + feeRow + 3] = "合计(2020年1月-至今)-实收";
        header[9 + feeRow + 4] = "合计(2020年1月-至今)-代收";
        header[9 + feeRow + 5] = "合计(2020年1月-至今)-2026年";
        header[9 + feeRow + 6] = "合计(2020年1月-至今)-2027年";
        header[9 + feeRow + 7] = "合计(2020年1月-至今)-待收月数";
        header[9 + feeRow + 8] = "合计(2020年1月-至今)-待收金额";
        header[9 + feeRow + 9] = "代收区间";
// 3. 设备运作费:原未改col,沿用前一个1
        header.add(createHeaderRow("设备运作费", 1, 3));
// 4. 第二个feeRow循环:原未显式改col,沿用前一个1(按原逻辑保持col=1)
        for (int i = 0; i < feeRow; i++) {
            header.add(createHeaderRow(feeConfigDtos.get(0).getFeeName(), 1, 3));
        }
// 5. 年应收款:原显式setCol(1),保持col=1
        header.add(createHeaderRow("年应收款", 1, 3));
// 6. 合计(2020年1月-至今):原显式setCol(8),保持col=8;原setRow(1),保持row=1
        header.add(createHeaderRow("合计(2020年1月-至今)", 8, 1));
// 7. 历年实收:原显式setCol((endYear - startYear + 1) * 3),保持该计算逻辑
        int yearCol = (endYear - startYear + 1) * 3;
        header.add(createHeaderRow("历年实收", yearCol+1, 1));
        header.add(createHeaderRow("操作", 1, 3));    // 原未改col,沿用1
// 最终添加表头到报表列表
        reportExcelDtos.add(header);
        // 初始化 LinkedList(而非数组,支持顺序添加)
        LinkedList<ReportExcelDto> header2 = new LinkedList<>();
// 1. 应收、实收、代收等固定项:按顺序add,对应原数组0-7下标
        header2.add(createHeaderRow("应收", 1, 2));          // 对应原header[0]
        header2.add(createHeaderRow("实收", 1, 2));          // 对应原header[1]
        header2.add(createHeaderRow("代收", 1, 2));          // 对应原header[2]
        header2.add(createHeaderRow("2026年", 1, 2));        // 对应原header[3]
        header2.add(createHeaderRow("2027年", 1, 2));        // 对应原header[4]
        header2.add(createHeaderRow("待收月数", 1, 2));      // 对应原header[5]
        header2.add(createHeaderRow("待收金额", 1, 2));      // 对应原header[6]
        header2.add(createHeaderRow("代收区间", 1, 2));      // 对应原header[7]
// 2. 年份循环:按原下标逻辑计算顺序,继续add(原header[8]及以后)
        for (int i = startYear; i <= endYear; i++) {
            // 原逻辑:index = 7 + (i - startYear + 1) → 首次循环i=startYear时,index=8
            // LinkedList无需关心下标,直接add即可保持顺序(与原数组下标顺序一致)
            header2.add(createHeaderRow(String.valueOf(i), 3, 1));
        }
// 3. 打折金额汇总:原逻辑中"年份循环后"的下一个位置,继续add
        header2.add(createHeaderRow("打折金额汇总", 1, 2));
// 4. 最终添加到报表列表
        reportExcelDtos.add(header2);
        LinkedList<ReportExcelDto> header3 = new LinkedList<>();
        for (int i = startYear ; i <= endYear ; i++){
            header[9 + feeRow + 9 + ((i - startYear) * 3) + 1] = "历年实收"+i+"-已收月数";
            header[9 + feeRow + 9 + ((i - startYear) * 3) + 2] = "历年实收"+i+"-已收区间";
            header[9 + feeRow + 9 + ((i - startYear) * 3) + 3] = "历年实收"+i+"-未收区间";
            header3.add(createHeaderRow("已收月数", 1, 1));
            header3.add(createHeaderRow("已收区间", 1, 1));
            header3.add(createHeaderRow("未收区间", 1, 1));
        }
        header[9 + feeRow + 9 + ((endYear - startYear) * 3) + 4] = "打折金额汇总";
        reportExcelDtos.add(header3);
        return reportExcelDtos;
    }
    private ReportExcelDto createHeaderRow(String text, int col, int row) {
        ReportExcelDto reportExcelDto = new ReportExcelDto();
        reportExcelDto.setTest(text); // 注意:可能是setText()的笔误
        reportExcelDto.setCol(col);
        reportExcelDto.setRow(row);
        return reportExcelDto;
    }
    public double doublequ2(double num){
        return (int)(num * 100) / 100.0;
    }
}
service-fee/src/main/java/com/java110/fee/cmd/fee/ReportFeeWriteOrderCmd.java
@@ -88,7 +88,9 @@
                Map map = result.get(i);
                String[] strings = new String[29];
                for (int j = 1; j <= 27; j++) {
                    strings[j-1] = map.get("row"+j).toString();
                    if(map.containsKey("row"+j)){
                        strings[j-1] = map.get("row"+j).toString();
                    }
                }
                reportList[i] = strings;
            }
@@ -101,9 +103,9 @@
            int i = reportFeeInnerServiceSMOImpl.saveReport(BeanConvertUtil.beanCovertMap(reportQueryRecord));
            ResultVo resultVo = new ResultVo(reportList);
//            resultVo.setTotal(count);
            ResponseEntity<String> responseEntity = new ResponseEntity<String>(resultVo.toString(), HttpStatus.OK);
            context.setResponseEntity(responseEntity);
service-fee/src/main/java/com/java110/fee/cmd/feeConfig/DeleteFeeConfigCmd.java
@@ -8,6 +8,7 @@
import com.java110.core.event.cmd.CmdEvent;
import com.java110.dto.fee.FeeConfigDto;
import com.java110.intf.fee.IFeeConfigInnerServiceSMO;
import com.java110.intf.fee.IFeeInnerServiceSMO;
import com.java110.intf.fee.IPayFeeConfigV1InnerServiceSMO;
import com.java110.po.fee.PayFeeConfigPo;
import com.java110.utils.exception.CmdException;
@@ -25,6 +26,9 @@
    @Autowired
    private IFeeConfigInnerServiceSMO feeConfigInnerServiceSMOImpl;
    @Autowired
    private IFeeInnerServiceSMO feeInnerServiceSMO;
    @Override
    public void validate(CmdEvent event, ICmdDataFlowContext cmdDataFlowContext, JSONObject reqJson) throws CmdException {
@@ -38,8 +42,10 @@
        if (feeCount > 0) {
            throw new IllegalArgumentException("该费用项目不能删除");
        }
        int validCount = feeInnerServiceSMO.countValidPayFeeByConfigId(reqJson.getString("configId"));
        if (validCount > 0) {
            throw new CmdException("关联生效中费用,无法修改,请撤销关联费用后重试!");
        }
    }
    @Override
service-fee/src/main/java/com/java110/fee/dao/impl/FeeServiceDaoImpl.java
@@ -292,7 +292,11 @@
     */
    @Override
    public int countValidPayFeeByConfigId(Map info) {
        return sqlSessionTemplate.insert("feeServiceDaoImpl.countValidPayFeeByConfigId", info);
        List<Map> infos =  sqlSessionTemplate.selectList("feeServiceDaoImpl.countValidPayFeeByConfigId", info);
        if (infos.size() < 1) {
            return 0;
        }
        return Integer.parseInt(infos.get(0).get("count").toString());
    }
    @Override
service-fee/src/main/java/com/java110/fee/smo/impl/FeeDiscountInnerServiceSMOImpl.java
@@ -368,7 +368,7 @@
                tmpPayFeeConfigDiscountDto.setPayMaxStarTime(startTime);
            }
            if (tmpPayFeeConfigDiscountDto.getPayMaxEndTime() == null || finishTime.getTime() < tmpPayFeeConfigDiscountDto.getPayMaxEndTime().getTime()) {
                tmpPayFeeConfigDiscountDto.setPayMaxEndTime(finishTime);
                tmpPayFeeConfigDiscountDto.setPayMaxEndTime(DateUtil.getDateFromStringA(DateUtil.getAddHoursStringA(finishTime,12).split(" ")[0] + " 12:59:59"));
            }
            cycle =DateUtil.dayCompare(
                    tmpPayFeeConfigDiscountDto.getPayMaxStarTime(),
service-job/src/main/java/com/java110/job/importData/adapt/ImportCarHistoryFeeDetailQueueDataAdapt.java
@@ -119,6 +119,24 @@
        }
    }
    public void importCarFeeDetails2(String storeId, String userId, List<ImportRoomFee> importCarFees, String batchId) {
        importCarFees = ownerCarInnerServiceSMOImpl.freshCarIds(importCarFees);
        for (ImportRoomFee importCarFee : importCarFees) {
            try {
                if (StringUtil.isEmpty(importCarFee.getCarNum())) {
                    continue;
                }
                importCarFeeDetail(importCarFee, storeId, userId, batchId);
                updateImportLogDetailState(importCarFee.getDetailId());
            } catch (Exception e) {
                updateImportLogDetailState(importCarFee.getDetailId(), e);
                throw new IllegalArgumentException(e);
            }
        }
    }
    /**
     * 导入 费用历史
     *
@@ -141,7 +159,7 @@
        }
        List<RoomDto> roomDtos = iRoomInnerServiceSMOImpl.queryRooms(roomDto);
        try {
            if (importRoomFee.getPayObjId().equals("7777")){
            if (importRoomFee.getPayObjId() != null && importRoomFee.getPayObjId().equals("7777")){
                ContractPartyaDto contractPartyaDto = new ContractPartyaDto();
                contractPartyaDto.setPartyA(importRoomFee.getDoorRoomNum());
                List<ContractPartyaDto> contractPartyaDtos = contractPartyaInnerServiceSMOImpl.queryContractPartyas(contractPartyaDto);
@@ -154,8 +172,13 @@
                importRoomFee.setRoomId(roomDtos.get(0).getRoomId());
            }
        }catch (Exception e){
            updateImportLogDetailState(importRoomFee.getDetailId(),new IllegalArgumentException("费用项"+importRoomFee.getFeeName()+"不存在"));
            throw new IllegalArgumentException("门室号/合同主体:"+importRoomFee.getDoorRoomNum()+"未查询到");
            if (importRoomFee.getPayObjId() != null &&importRoomFee.getPayObjId().equals("7777")){
                updateImportLogDetailState(importRoomFee.getDetailId(),new IllegalArgumentException("合同主体:"+importRoomFee.getDoorRoomNum()+"未查询到"));
                throw new IllegalArgumentException("合同主体:"+importRoomFee.getDoorRoomNum()+"未查询到");
            }else {
                updateImportLogDetailState(importRoomFee.getDetailId(), new IllegalArgumentException("门室号:" + importRoomFee.getDoorRoomNum() + "未查询到"));
                throw new IllegalArgumentException("门室号:" + importRoomFee.getDoorRoomNum() + "未查询到");
            }
        }
        PayFeeDetailPo payFeeDetailPo = new PayFeeDetailPo();
        payFeeDetailPo.setPayOrderId(importRoomFee.getRoomId());
@@ -278,7 +301,7 @@
        ResponseEntity<String> resultVo = null;
        try {
            resultVo = feeDiscountApi.computeFeeDiscount(tmpFeeDto.getFeeId(), tmpFeeDto.getCommunityId(), 105, importRoomFee.getPayObjId(),
                    tmpFeeDto.getPayerObjType(), importRoomFee.getEndTime(), importRoomFee.getEndTime(), importRoomFee.getStartTime(), 1, 20);
                    tmpFeeDto.getPayerObjType(), importRoomFee.getEndTime(), importRoomFee.getStartTime(), importRoomFee.getEndTime(), 1, 20);
        } catch (ParseException e) {
            throw new RuntimeException(e);
        }
@@ -314,9 +337,9 @@
            payFeeDetailDiscount.setCommunityId(feeDtos.get(0).getCommunityId());
            payFeeDetailDiscount.setFeeId(feeDtos.get(0).getFeeId());
            payFeeDetailDiscount.setDetailDiscountId(GenerateCodeFactory.getGeneratorId(GenerateCodeFactory.CODE_PREFIX_discountId));
            payFeeDetailDiscountNewV1InnerServiceSMOImpl.savePayFeeDetailDiscountNew(payFeeDetailDiscount);
        }
        payFeeDetailDiscountNewV1InnerServiceSMOImpl.savePayFeeDetailDiscountNew(payFeeDetailDiscount);
        if (saved < 1) {
            return;
service-job/src/main/java/com/java110/job/importData/adapt/ImportHistoryFeeDetailQueueDataAdapt.java
@@ -124,7 +124,12 @@
//            List<String> roomTypes = Arrays.asList("住宅物业费","商铺物业费","维修收入","维修基金收入","电费及管理费","代收水费","各类押金","租金收入");
            List<String> carTypes = Arrays.asList("临时停车费", "业主产权过道停车费", "小业主产权车辆管理费","地下停车费","地面停车费");
            List<String> contractTypes = Arrays.asList("垃圾清运费","其他收入","补贴费用","场地使用费","电梯广告(业委会)","快递柜","电梯广告(联讯)","房产中介","非机动车管理费","其他广告");
            if(importRoomFee.getSecondaryFeeTypeCd()!= null && importRoomFee.getSecondaryFeeTypeCd().equals("临时停车费-其他")){
        FeeConfigDto feeConfigDto = new FeeConfigDto();
        feeConfigDto.setFeeName(importRoomFee.getSecondaryFeeTypeCdName());
        feeConfigDto.setFeeTypeCds(new String[]{"630000007","630000017"});
        List<FeeConfigDto> feeConfigDtos = feeConfigInnerServiceSMOImpl.queryFeeConfigs(feeConfigDto);
        if(importRoomFee.getSecondaryFeeTypeCd()!= null && importRoomFee.getSecondaryFeeTypeCd().equals("临时停车费-其他")){
                CarInoutPo carInout = new CarInoutPo();
                carInout.setCommunityId(communityId);
                carInout.setCarNum("A888888");
@@ -165,7 +170,7 @@
                }
            }
            else if(contractTypes.contains(importRoomFee.getSecondaryFeeTypeCd())){
            else if(contractTypes.contains(JSONObject.parseObject(assetImportLogDetailDto.getContent()).get("category22"))){
                importRoomFee.setFeeName(data.getString("secondaryFeeTypeCd"));
                importRoomFee.setCommunityId(communityId);
@@ -228,7 +233,7 @@
            importFeeDetails(importRoomFees.get(0).getStoreId(), importRoomFees.get(0).getUserId(), importRoomFees, importRoomFees.get(0).getBatchId());
        }
        if(!(ListUtil.isNull(importCarFees))){
            importCarHistoryFeeDetailQueueDataAdapt.importCarFeeDetails(importCarFees.get(0).getStoreId(), importCarFees.get(0).getUserId(), importCarFees, importCarFees.get(0).getBatchId());
            importCarHistoryFeeDetailQueueDataAdapt.importCarFeeDetails2(importCarFees.get(0).getStoreId(), importCarFees.get(0).getUserId(), importCarFees, importCarFees.get(0).getBatchId());
        }
    }
@@ -292,8 +297,8 @@
        roomDto.setCommunityId(importRoomFee.getCommunityId());
        if(importRoomFee.getDoorRoomNum()!=null){
            String[] split = importRoomFee.getDoorRoomNum().split("-");
            if(split.length==2){
                roomDto.setDoorRoomNum(importRoomFee.getDoorRoomNum());
            if(split.length < 2){
                throw new IllegalArgumentException("门室号"+importRoomFee.getDoorRoomNum()+"未遵循x-x-x");
            }else if(split.length > 2){
                roomDto.setFloorNum(split[0]);
                roomDto.setUnitNum(split[1]);
@@ -310,6 +315,9 @@
        feeDto2.setFeeName(importRoomFee.getFeeName());
        feeDto2.setPayerObjId(importRoomFee.getRoomId());
        feeDto2.setCommunityId(importRoomFee.getCommunityId());
        feeDto2.setStatusCd("0");
        feeDto2.setUseStart(DateUtil.getDateFromStringA(importRoomFee.getStartTime()));
        feeDto2.setUseEnd(DateUtil.getDateFromStringA(importRoomFee.getEndTime()));
        List<FeeDto> feeDtos = feeInnerServiceSMOImpl.queryFees(feeDto2);
        if(feeDtos.size() == 0){
            updateImportLogDetailState(importRoomFee.getDetailId(),new IllegalArgumentException("费用项"+importRoomFee.getFeeName()+"不存在"));
@@ -363,7 +371,7 @@
//            feeDtos = feeInnerServiceSMOImpl.queryFees(feeDto);
        }
        if(feeDtos.size()>1){
            throw new IllegalArgumentException("该初始化缴费记录信息中包含多个费用记录"+importRoomFee.getFeeName());
            throw new IllegalArgumentException(importRoomFee.getDoorRoomNum() +importRoomFee.getFeeName() + "+" + importRoomFee.getStartTime() + "-" + importRoomFee.getEndTime() + "未匹配到收费项");
        }
        for (FeeDto tmpFeeDto : feeDtos) {
            if(DateUtil.getDateFromStringB(importRoomFee.getEndTime()).getTime() > tmpFeeDto.getMaxEndTime().getTime()){
@@ -475,7 +483,7 @@
//        int i = feeInnerServiceSMOImpl.updateFee(feeInfo);
        if (tmpFeeDto.getEndTime().getTime() >= DateUtil.getDateFromStringB(importRoomFee.getEndTime()).getTime()) {
        if (tmpFeeDto.getEndTime().getTime() >= DateUtil.getDateFromStringA(importRoomFee.getEndTime()).getTime()  + 2000) {
            return;
        }
@@ -485,13 +493,7 @@
        payFeePo.setCommunityId(importRoomFee.getCommunityId());
        payFeePo.setStatusCd(StatusConstant.STATUS_CD_VALID);
        payFeePo.setFeeId(tmpFeeDto.getFeeId());
        String[] arr = importRoomFee.getEndTime().split(" ");
        if (arr.length >= 2 &&arr[1].equals("23:59:59")){
            payFeePo.setEndTime(DateUtil.getNextSecTime(importRoomFee.getEndTime()));
        }
        if (FeeDto.FEE_FLAG_ONCE.equals(tmpFeeDto.getFeeFlag())) {
            payFeePo.setState(FeeDto.STATE_FINISH);
        }
        payFeePo.setState(FeeDto.STATE_FINISH);
        feeInnerServiceSMOImpl.updateFee(payFeePo);
        feeInfo = feeInnerServiceSMOImpl.queryFees(fee).get(0);
        if (DateUtil.getFormatTimeStringB(feeInfo.getEndTime()).equals(DateUtil.getFormatTimeStringB(feeInfo.getMaxEndTime()))) {
service-store/src/main/java/com/java110/store/api/ContractPartyaApi.java
@@ -78,6 +78,8 @@
        ContractPartyaPo contractPartyaPo = BeanConvertUtil.covertBean(reqJson, ContractPartyaPo.class);
        //判断该活动主体是否被使用
        checkUseContract(contractPartyaPo);
        contractPartyaPo.setStoreId(storeId);
        return updateContractPartyaBMOImpl.update(contractPartyaPo);
@@ -101,6 +103,12 @@
        ContractPartyaPo contractPartyaPo = BeanConvertUtil.covertBean(reqJson, ContractPartyaPo.class);
        //判断该活动主体是否被使用
        checkUseContract(contractPartyaPo);
        contractPartyaPo.setStoreId(storeId);
        return deleteContractPartyaBMOImpl.delete(contractPartyaPo);
    }
    private void checkUseContract(ContractPartyaPo contractPartyaPo){
        ContractDto contractDto = new ContractDto();
        if(contractPartyaPo.getTypeId().equals("1")){
            contractDto.setaPartyaId(contractPartyaPo.getPartyaId());
@@ -113,8 +121,6 @@
        if(!CollectionUtils.isEmpty(contractDtos)){
            throw new IllegalArgumentException("该合同主体已经被使用,不能删除");
        }
        contractPartyaPo.setStoreId(storeId);
        return deleteContractPartyaBMOImpl.delete(contractPartyaPo);
    }
    /**
springboot/src/main/resources/application-debug.yml
@@ -3,7 +3,10 @@
  tomcat:
    uri-encoding: UTF-8
fuiou:
  pay:
    unified-order-url: https://aipaytest.fuioupay.com/aggregatePay/preCreate
    env: test
spring:
  servlet:
springboot/src/main/resources/application-debugg.yml
@@ -3,7 +3,10 @@
  tomcat:
    uri-encoding: UTF-8
fuiou:
  pay:
    unified-order-url: https://aipaytest.fuioupay.com/aggregatePay/preCreate
    env: test
spring:
  servlet:
springboot/src/main/resources/application-dev.yml
@@ -3,7 +3,10 @@
  tomcat:
    uri-encoding: UTF-8
fuiou:
  pay:
    unified-order-url: https://aipay-cloud.fuioupay.com/aggregatePay/preCreate
    env: dev
spring:
  servlet:
springboot/src/main/resources/application-devlocal.yml
@@ -3,7 +3,10 @@
  tomcat:
    uri-encoding: UTF-8
fuiou:
  pay:
    unified-order-url: https://aipaytest.fuioupay.com/aggregatePay/preCreate
    env: test
spring:
  jackson:
springboot/src/main/resources/application.yml
@@ -1,6 +1,6 @@
spring:
  profiles:
    active:  devlocal
    active:  debug
#  docker build -t lx .