# M3AccountServiceImpl.java

    package cloud.wconnect.finance.service.pl.impl;

    import cloud.wconnect.commonlib.component.BeanMapper;
    import cloud.wconnect.commonlib.cons.BaseErrorCodeEnum;
    import cloud.wconnect.commonlib.exception.BadRequestException;
    import cloud.wconnect.commonlib.pojo.dto.ListPagedDTO;
    import cloud.wconnect.commonlib.pojo.dto.m3Config.PropertyM3ConfigDTO;
    import cloud.wconnect.commonlib.pojo.dto.m3Config.TenantM3ConfigDTO;
    import cloud.wconnect.commonlib.service.M3ConfigInternalService;
    import cloud.wconnect.finance.cons.pl.AccountStatusEnum;
    import cloud.wconnect.finance.cons.pl.AccountTypeEnum;
    import cloud.wconnect.finance.cons.pl.PlErrorI18nConstant;
    import cloud.wconnect.finance.entity.pl.M3Account;
    import cloud.wconnect.finance.mapper.pl.M3AccountMapper;
    import cloud.wconnect.finance.pojo.dto.pl.m3api.M3AccountDTO;
    import cloud.wconnect.finance.pojo.query.pl.AccountQuery;
    import cloud.wconnect.finance.service.pl.IM3AccountService;
    import cloud.wconnect.finance.service.pl.IM3AccountSyncLogService;
    import cloud.wconnect.finance.service.pl.IM3RowService;
    import cloud.wconnect.finance.service.pl.M3ApiService;
    import com.baomidou.dynamic.datasource.annotation.DS;
    import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
    import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
    import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
    import org.apache.commons.collections.CollectionUtils;
    import org.apache.commons.lang3.StringUtils;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.context.annotation.Lazy;
    import org.springframework.stereotype.Service;
    import org.springframework.transaction.annotation.Transactional;

    import java.util.Arrays;
    import java.util.Collections;
    import java.util.List;
    import java.util.Objects;

    /**
     * <p>
     * P&L功能Account表 服务实现类
     * </p>
     *
     * @author lichen
     * @since 2025-09-25
     */
    @Service
    @DS("finance")
    public class M3AccountServiceImpl extends ServiceImpl<M3AccountMapper, M3Account> implements IM3AccountService {

        @Autowired
        private M3ApiService m3ApiService;
        @Autowired
        @Lazy
        private IM3RowService m3RowService;
        @Autowired
        private BeanMapper beanMapper;
        @Autowired
        private IM3AccountSyncLogService m3AccountSyncLogService;
        @Autowired
        private M3ConfigInternalService m3ConfigInternalService;

        /**
         * 同步资产M3 Account数据
         *
         * @param tenantM3ConfigDTO   租户的M3配置信息
         * @param propertyM3ConfigDTO 资产的M3配置信息
         * @return void
         * @author lichen
         * @date 2025/9/26
         */
        @Override
        @Transactional(rollbackFor = Exception.class)
        public void syncPropertyM3Account(TenantM3ConfigDTO tenantM3ConfigDTO, PropertyM3ConfigDTO propertyM3ConfigDTO) {
            //查询M3 Account数据
            List<M3AccountDTO> m3AccountDTOS = m3ApiService.listAccount(tenantM3ConfigDTO, propertyM3ConfigDTO);
            //M3 Account类型
            List<String> m3AccountTypeList = Arrays.stream(AccountTypeEnum.values()).map(AccountTypeEnum::getM3AccountType).toList();
            //筛选出有效的M3 Account数据
            List<M3AccountDTO> effectiveM3AccountDTOS = m3AccountDTOS.stream().filter(m3AccountDTO -> m3AccountTypeList.contains(m3AccountDTO.getAccountType())).toList();

            //查询资产下已经存在的Account数据
            List<M3Account> existM3Accounts = listByPropertyId(propertyM3ConfigDTO.getPropertyId());
            if (CollectionUtils.isNotEmpty(existM3Accounts)) {
                //筛选出删除的Account数据
                List<String> effectiveM3AccountNumber = effectiveM3AccountDTOS.stream().map(M3AccountDTO::getAccountNumber).toList();
                List<M3Account> deleteM3Accounts = existM3Accounts.stream()
                        .filter(existM3Account -> !effectiveM3AccountNumber.contains(existM3Account.getAccountNumber())).toList();
                //标记Item类型的Row Account不存在
                m3RowService.markItemRowAccountNotExist(propertyM3ConfigDTO.getPropertyId(), deleteM3Accounts);
            }

            //删除资产下所有Account数据
            remove(new LambdaQueryWrapper<M3Account>().eq(M3Account::getPropertyId, propertyM3ConfigDTO.getPropertyId()));

            //批量插入资产下Account数据
            List<M3Account> m3AccountList = effectiveM3AccountDTOS.stream().map(m3AccountDTO -> {
                M3Account m3Account = new M3Account();
                m3Account.setTenantId(tenantM3ConfigDTO.getTenantId());
                m3Account.setPropertyId(propertyM3ConfigDTO.getPropertyId());
                m3Account.setAccountNumber(m3AccountDTO.getAccountNumber());
                m3Account.setAccountName(m3AccountDTO.getAccountName());
                m3Account.setIsActive(AccountStatusEnum.getStatusByM3AccountStatus(m3AccountDTO.getActiveStatus()));
                m3Account.setAccountType(AccountTypeEnum.getTypeByM3AccountType(m3AccountDTO.getAccountType()));
                return m3Account;
            }).toList();

            if(CollectionUtils.isNotEmpty(m3AccountList)){
                // 分批处理，每300条记录一批
                int batchSize = 300;
                for (int i = 0; i < m3AccountList.size(); i += batchSize) {
                    int endIndex = Math.min(i + batchSize, m3AccountList.size());
                    List<M3Account> batch = m3AccountList.subList(i, endIndex);
                    baseMapper.insertBatch(batch);
                }
            }

            //更新Account log
            m3AccountSyncLogService.updateSyncTime(tenantM3ConfigDTO.getTenantId(), propertyM3ConfigDTO.getPropertyId());
        }

        /**
         * 查询资产下所有Account数据
         *
         * @param propertyId 资产ID
         * @return java.util.List<cloud.wconnect.finance.entity.pl.M3Account>
         * @author lichen
         * @date 2025/9/26
         */
        @Override
        public List<M3Account> listByPropertyId(Integer propertyId) {
            return list(new LambdaQueryWrapper<M3Account>().eq(M3Account::getPropertyId, propertyId));
        }

        /**
         * 分页查询
         *
         * @param propertyId 资产ID
         * @param query      查询参数
         * @return cloud.wconnect.commonlib.pojo.dto.ListPagedDTO<cloud.wconnect.finance.entity.pl.M3Account>
         * @author lichen
         * @date 2025/9/26
         */
        @Override
        public ListPagedDTO<M3Account> pageList(int propertyId, AccountQuery query) {
            LambdaQueryWrapper<M3Account> lambdaQueryWrapper = new LambdaQueryWrapper<M3Account>().eq(M3Account::getPropertyId, propertyId)
                    .eq(StringUtils.isNotBlank(query.getAccountNumber()), M3Account::getAccountNumber, query.getAccountNumber())
                    .like(StringUtils.isNotBlank(query.getAccountName()), M3Account::getAccountName, query.getAccountName())
                    .eq(Objects.nonNull(query.getAccountType()), M3Account::getAccountType, query.getAccountType())
                    .eq(Objects.nonNull(query.getIsActive()), M3Account::getIsActive, query.getIsActive())
                    .orderByDesc(M3Account::getId);
            Page<M3Account> page = page(new Page<>(query.getPage(), query.getSize()), lambdaQueryWrapper);
            if (page.getTotal() == 0) {
                return new ListPagedDTO<>();
            }
            return new ListPagedDTO<>(page.getTotal(), page.getRecords());
        }

        /**
         * 刷新资产下所有Account数据
         *
         * @param propertyId 资产ID
         * @return void
         * @author lichen
         * @date 2025/9/26
         */
        @Override
        @Transactional(rollbackFor = Exception.class)
        public void refreshAccount(int propertyId) {
            //获取资产的M3配置
            List<TenantM3ConfigDTO> tenantM3ConfigDTOS = m3ConfigInternalService.listPropertyM3Config(Collections.singletonList(propertyId));
            if (CollectionUtils.isEmpty(tenantM3ConfigDTOS)) {
                //租户的M3配置不存在
                throw new BadRequestException(PlErrorI18nConstant.TENANT_M3_CONFIG_NOT_EXIST,
                        BaseErrorCodeEnum.DATA_VALIDATION_ERROR.getCode(),
                        "tenant m3 config not exist");
            }

            TenantM3ConfigDTO tenantM3ConfigDTO = tenantM3ConfigDTOS.get(0);
            List<PropertyM3ConfigDTO> propertyM3ConfigDTOS = tenantM3ConfigDTO.getPropertyM3ConfigDTOS();
            if (CollectionUtils.isEmpty(propertyM3ConfigDTOS)) {
                //资产的M3配置不存在
                throw new BadRequestException(PlErrorI18nConstant.PROPERTY_M3_CONFIG_NOT_EXIST,
                        BaseErrorCodeEnum.DATA_VALIDATION_ERROR.getCode(),
                        "property m3 config not exist");
            }
            PropertyM3ConfigDTO propertyM3ConfigDTO = propertyM3ConfigDTOS.get(0);

            //同步Account数据
            syncPropertyM3Account(tenantM3ConfigDTO, propertyM3ConfigDTO);
        }

        /**
         * 根据账户编号查询账户信息
         *
         * @param propertyId    资产ID
         * @param accountNumber 账户编号
         * @return java.util.List<cloud.wconnect.finance.entity.pl.M3Account>
         * @author lichen
         * @date 2025/9/26
         */
        @Override
        public List<M3Account> listByAccountNumber(int propertyId, List<String> accountNumber) {
            if (CollectionUtils.isEmpty(accountNumber)) return Collections.emptyList();
            return list(new LambdaQueryWrapper<M3Account>().eq(M3Account::getPropertyId, propertyId)
                    .in(M3Account::getAccountNumber, accountNumber));
        }
    }