package com.ruoyi.account.service.impl; import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.core.toolkit.CollectionUtils; import com.baomidou.mybatisplus.core.toolkit.Wrappers; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.ruoyi.account.bean.dto.StatementAccountDto; import com.ruoyi.account.bean.dto.purchase.PurchaseInboundDto; import com.ruoyi.account.bean.dto.purchase.PurchaseReturnDto; import com.ruoyi.account.bean.dto.sales.SalesOutboundDto; import com.ruoyi.account.bean.dto.sales.SalesReturnDto; import com.ruoyi.account.bean.vo.StatementAccountVo; import com.ruoyi.account.bean.vo.purchase.PurchaseInboundVo; import com.ruoyi.account.bean.vo.purchase.PurchaseReturnVo; import com.ruoyi.account.bean.vo.sales.SalesOutboundVo; import com.ruoyi.account.bean.vo.sales.SalesReturnVo; import com.ruoyi.account.mapper.AccountStatementDetailsMapper; import com.ruoyi.account.mapper.AccountStatementMapper; import com.ruoyi.account.mapper.purchase.AccountPurchasePaymentMapper; import com.ruoyi.account.mapper.sales.AccountSalesCollectionMapper; import com.ruoyi.account.pojo.AccountStatement; import com.ruoyi.account.pojo.AccountStatementDetails; import com.ruoyi.account.pojo.purchase.AccountPurchasePayment; import com.ruoyi.account.pojo.sales.AccountSalesCollection; import com.ruoyi.account.service.AccountStatementService; import com.ruoyi.common.exception.ServiceException; import com.ruoyi.common.utils.bean.BeanUtils; import com.ruoyi.common.utils.poi.ExcelUtil; import com.ruoyi.procurementrecord.mapper.ReturnManagementMapper; import com.ruoyi.purchase.mapper.PurchaseReturnOrdersMapper; import com.ruoyi.stock.mapper.StockInRecordMapper; import com.ruoyi.stock.mapper.StockOutRecordMapper; import jakarta.servlet.http.HttpServletResponse; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import java.math.BigDecimal; import java.time.LocalDateTime; import java.time.YearMonth; import java.time.format.DateTimeFormatter; import java.util.ArrayList; import java.util.List; import java.util.Random; /** *

* 服务实现类 *

* * @author 芯导软件(江苏)有限公司 * @since 2026-05-19 09:42:47 */ @Service @RequiredArgsConstructor @Transactional(rollbackFor = Exception.class) public class AccountStatementServiceImpl extends ServiceImpl implements AccountStatementService { private final AccountStatementMapper accountStatementMapper; private final AccountSalesCollectionMapper accountSalesCollectionMapper; private final StockOutRecordMapper stockOutRecordMapper; private final StockInRecordMapper stockInRecordMapper; private final ReturnManagementMapper returnManagementMapper; private final AccountStatementDetailsMapper accountStatementDetailsMapper; private final AccountPurchasePaymentMapper accountPurchasePaymentMapper; private final PurchaseReturnOrdersMapper purchaseReturnOrdersMapper; private static final DateTimeFormatter CODE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyMMdd"); @Override public StatementAccountVo getAccountStatementDetailsByMonth(StatementAccountDto statementAccountDto) { //对账月份转换成开始日期和结束日期区间 DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM"); YearMonth yearMonth = YearMonth.parse(statementAccountDto.getStatementMonth(), formatter); statementAccountDto.setStartDate(yearMonth.atDay(1)); statementAccountDto.setEndDate(yearMonth.atEndOfMonth()); if (statementAccountDto.getAccountType() == 1){ //应收对账--Customer return getAccountStatementDetailsByCustomerAndMonth(statementAccountDto); }else { //应付对账--SupplierManage return getAccountStatementDetailsBySupplierAndMonth(statementAccountDto); } } @Override public boolean addAccountStatement(StatementAccountVo statementAccountVo) { //同一客户或者同一供应商,一个月份只能有一个对账单 List accountStatements = accountStatementMapper.selectList(Wrappers.lambdaQuery() .eq(AccountStatement::getStatementMonth, statementAccountVo.getStatementMonth()) .eq(AccountStatement::getAccountType, statementAccountVo.getAccountType()) .eq(AccountStatement::getCustomerId, statementAccountVo.getCustomerId())); if (CollectionUtils.isNotEmpty(accountStatements)){ throw new ServiceException("同一客户或者同一供应商,一个月份只能有一个对账单"); } AccountStatement accountStatement = new AccountStatement(); BeanUtils.copyProperties(statementAccountVo, accountStatement); accountStatement.setStatementNumber(genStatementAccountNo()); boolean save = save(accountStatement); statementAccountVo.getAccountStatementDetails().stream().forEach(accountStatementDetails -> { accountStatementDetails.setAccountStatementId(accountStatement.getId()); //添加对账单明细 accountStatementDetailsMapper.insert(accountStatementDetails); }); return save; } @Override public boolean deleteAccountStatement(List ids) { //删除对账单明细 accountStatementDetailsMapper.delete(Wrappers.lambdaQuery().in(AccountStatementDetails::getAccountStatementId, ids)); return removeByIds(ids); } @Override public IPage listPageAccountStatement(Page page, StatementAccountDto statementAccountDto) { return accountStatementMapper.listPageAccountStatement(page, statementAccountDto); } @Override public void exportAccountStatement(HttpServletResponse response, StatementAccountDto statementAccountDto) { List list = accountStatementMapper.listPageAccountStatement(new Page(1,-1),statementAccountDto).getRecords(); ExcelUtil util = new ExcelUtil<>(StatementAccountVo.class); util.exportExcel(response, list , "对账单"); } //根据客户和月份获取对账详情(销售) private StatementAccountVo getAccountStatementDetailsByCustomerAndMonth(StatementAccountDto statementAccountDto) { StatementAccountVo statementAccountVo = new StatementAccountVo(); statementAccountVo.setAccountType(1);//应收对账 List accountStatementDetailsList = new ArrayList<>(); /*查询出库明细*/ SalesOutboundDto salesOutboundDto = new SalesOutboundDto(); salesOutboundDto.setCustomerId(statementAccountDto.getCustomerId()); salesOutboundDto.setStartDate(statementAccountDto.getStartDate()); salesOutboundDto.setEndDate(statementAccountDto.getEndDate()); List salesOutboundVos = stockOutRecordMapper.listPageAccountSales(new Page(1, -1), salesOutboundDto).getRecords(); salesOutboundVos.stream().forEach(salesOutboundVo -> { AccountStatementDetails accountStatementDetails = new AccountStatementDetails(); //数据日期=出库日期 accountStatementDetails.setOccurrenceDate(salesOutboundVo.getShippingDate()); //单据编号=出库单号 accountStatementDetails.setReceiptNumber(salesOutboundVo.getOutboundBatches()); //类型=出库 accountStatementDetails.setType(1); //金额=出库金额 accountStatementDetails.setAmount(salesOutboundVo.getOutboundAmount()); //备注 accountStatementDetails.setRemark("产品销售出库,产品:"+salesOutboundVo.getProductName()); accountStatementDetailsList.add(accountStatementDetails); }); /*查询收款明细*/ List accountSalesCollections = accountSalesCollectionMapper.selectList(Wrappers.lambdaQuery() .eq(AccountSalesCollection::getCustomerId, statementAccountDto.getCustomerId()) .between(AccountSalesCollection::getCollectionDate, statementAccountDto.getStartDate(), statementAccountDto.getEndDate())); accountSalesCollections.stream().forEach(accountSalesCollection -> { AccountStatementDetails accountStatementDetails = new AccountStatementDetails(); //数据日期=收款日期 accountStatementDetails.setOccurrenceDate(accountSalesCollection.getCollectionDate()); //单据编号=收款单号 accountStatementDetails.setReceiptNumber(accountSalesCollection.getCollectionNumber()); //类型=收款 accountStatementDetails.setType(3); //金额=收款金额 accountStatementDetails.setAmount(accountSalesCollection.getCollectionAmount()); //备注 accountStatementDetails.setRemark("客户回款,备注:"+accountSalesCollection.getRemark()); accountStatementDetailsList.add(accountStatementDetails); }); /*查询退货明细*/ SalesReturnDto salesReturnDto = new SalesReturnDto(); salesReturnDto.setCustomerId(statementAccountDto.getCustomerId()); salesReturnDto.setStartDate(statementAccountDto.getStartDate()); salesReturnDto.setEndDate(statementAccountDto.getEndDate()); List salesReturnVos = returnManagementMapper.listPageAccountSalesReturn(new Page(1, -1), salesReturnDto).getRecords(); salesReturnVos.stream().forEach(salesReturnVo -> { AccountStatementDetails accountStatementDetails = new AccountStatementDetails(); //数据日期=退货日期 accountStatementDetails.setOccurrenceDate(salesReturnVo.getMakeTime().toLocalDate()); //单据编号=退货单号 accountStatementDetails.setReceiptNumber(salesReturnVo.getReturnNo()); //类型=退货 accountStatementDetails.setType(5); //金额=退款金额 accountStatementDetails.setAmount(salesReturnVo.getRefundAmount()); //备注 accountStatementDetails.setRemark("产品退货,原因:"+salesReturnVo.getReturnReason()); accountStatementDetailsList.add(accountStatementDetails); }); //期初余额=上个月的期末余额 statementAccountVo.setOpeningBalance(BigDecimal.ZERO); List accountStatements = accountStatementMapper.selectList(Wrappers.lambdaQuery() .eq(AccountStatement::getAccountType, 1) .eq(AccountStatement::getCustomerId, statementAccountDto.getCustomerId()) .eq(AccountStatement::getStatementMonth, YearMonth.parse(statementAccountDto.getStatementMonth()).minusMonths(1).toString())); if (CollectionUtils.isNotEmpty(accountStatements)){ statementAccountVo.setOpeningBalance(accountStatements.get(accountStatements.size() - 1).getClosingBalance()); } //本期应收=出库-退货金额累计 statementAccountVo.setCurrentPlan(salesOutboundVos.stream().map(SalesOutboundVo::getOutboundAmount).reduce(BigDecimal.ZERO, BigDecimal::add) .subtract(salesReturnVos.stream().map(SalesReturnVo::getRefundAmount).reduce(BigDecimal.ZERO, BigDecimal::add))); //本期收款=收款金额累计 statementAccountVo.setCurrentActually(accountSalesCollections.stream().map(AccountSalesCollection::getCollectionAmount).reduce(BigDecimal.ZERO, BigDecimal::add)); //期末余额=期初+应收-收款 statementAccountVo.setClosingBalance(statementAccountVo.getOpeningBalance().add(statementAccountVo.getCurrentPlan()).subtract(statementAccountVo.getCurrentActually())); statementAccountVo.setAccountStatementDetails(accountStatementDetailsList); return statementAccountVo; } //根据供应商和月份获取对账详情(采购) private StatementAccountVo getAccountStatementDetailsBySupplierAndMonth(StatementAccountDto statementAccountDto) { StatementAccountVo statementAccountVo = new StatementAccountVo(); statementAccountVo.setAccountType(2);//应付对账 List accountStatementDetailsList = new ArrayList<>(); /*查询入库明细*/ PurchaseInboundDto purchaseInboundDto = new PurchaseInboundDto(); purchaseInboundDto.setSupplierId(statementAccountDto.getCustomerId()); purchaseInboundDto.setStartDate(statementAccountDto.getStartDate()); purchaseInboundDto.setEndDate(statementAccountDto.getEndDate()); List purchaseInboundVos = stockInRecordMapper.listPageAccountPurchase(new Page(1, -1), purchaseInboundDto).getRecords(); purchaseInboundVos.stream().forEach(purchaseInboundVo -> { AccountStatementDetails accountStatementDetails = new AccountStatementDetails(); //数据日期=入库日期 accountStatementDetails.setOccurrenceDate(purchaseInboundVo.getInboundDate()); //单据编号=入库单号 accountStatementDetails.setReceiptNumber(purchaseInboundVo.getInboundBatches()); //类型=入库 accountStatementDetails.setType(2); //金额=入库金额 accountStatementDetails.setAmount(purchaseInboundVo.getInboundAmount()); //备注 accountStatementDetails.setRemark("产品采购入库,产品:"+purchaseInboundVo.getProductName()); accountStatementDetailsList.add(accountStatementDetails); }); /*查询付款明细*/ List accountPurchasePayments = accountPurchasePaymentMapper.selectList(Wrappers.lambdaQuery() .eq(AccountPurchasePayment::getSupplierId, statementAccountDto.getCustomerId()) .between(AccountPurchasePayment::getPaymentDate, statementAccountDto.getStartDate(), statementAccountDto.getEndDate())); accountPurchasePayments.stream().forEach(accountPurchasePayment -> { AccountStatementDetails accountStatementDetails = new AccountStatementDetails(); //数据日期=付款日期 accountStatementDetails.setOccurrenceDate(accountPurchasePayment.getPaymentDate()); //单据编号=付款单号 accountStatementDetails.setReceiptNumber(accountPurchasePayment.getPaymentNumber()); //类型=付款 accountStatementDetails.setType(4); //金额=付款金额 accountStatementDetails.setAmount(accountPurchasePayment.getPaymentAmount()); //备注 accountStatementDetails.setRemark("支付货款,备注:"+accountPurchasePayment.getRemark()); accountStatementDetailsList.add(accountStatementDetails); }); /*查询退货明细*/ PurchaseReturnDto purchaseReturnDto = new PurchaseReturnDto(); purchaseReturnDto.setSupplierId(statementAccountDto.getCustomerId()); purchaseReturnDto.setStartDate(statementAccountDto.getStartDate()); purchaseReturnDto.setEndDate(statementAccountDto.getEndDate()); List purchaseReturnVos = purchaseReturnOrdersMapper.listPageAccountPurchaseReturn(new Page(1, -1), purchaseReturnDto).getRecords(); purchaseReturnVos.stream().forEach(purchaseReturnVo -> { AccountStatementDetails accountStatementDetails = new AccountStatementDetails(); //数据日期=退货日期 accountStatementDetails.setOccurrenceDate(purchaseReturnVo.getPreparedAt().toLocalDate()); //单据编号=退货单号 accountStatementDetails.setReceiptNumber(purchaseReturnVo.getReturnNo()); //类型=退货 accountStatementDetails.setType(5); //金额=退款金额 accountStatementDetails.setAmount(purchaseReturnVo.getTotalAmount()); //备注 accountStatementDetails.setRemark("产品退货,退货方式:"+purchaseReturnVo.getReturnType()); accountStatementDetailsList.add(accountStatementDetails); }); //期初余额=上个月的期末余额 statementAccountVo.setOpeningBalance(BigDecimal.ZERO); List accountStatements = accountStatementMapper.selectList(Wrappers.lambdaQuery() .eq(AccountStatement::getAccountType, 2) .eq(AccountStatement::getCustomerId, statementAccountDto.getCustomerId()) .eq(AccountStatement::getStatementMonth, YearMonth.parse(statementAccountDto.getStatementMonth()).minusMonths(1).toString())); if (CollectionUtils.isNotEmpty(accountStatements)){ statementAccountVo.setOpeningBalance(accountStatements.get(accountStatements.size() - 1).getClosingBalance()); } //本期应付=入库-退货金额累计 statementAccountVo.setCurrentPlan(purchaseInboundVos.stream().map(PurchaseInboundVo::getInboundAmount).reduce(BigDecimal.ZERO, BigDecimal::add) .subtract(purchaseReturnVos.stream().map(PurchaseReturnVo::getTotalAmount).reduce(BigDecimal.ZERO, BigDecimal::add))); //本期付款=付款金额累计 statementAccountVo.setCurrentActually(accountPurchasePayments.stream().map(AccountPurchasePayment::getPaymentAmount).reduce(BigDecimal.ZERO, BigDecimal::add)); //期末余额=期初+应收-收款 statementAccountVo.setClosingBalance(statementAccountVo.getOpeningBalance().add(statementAccountVo.getCurrentPlan()).subtract(statementAccountVo.getCurrentActually())); statementAccountVo.setAccountStatementDetails(accountStatementDetailsList); return statementAccountVo; } private String genStatementAccountNo() { return "DZ" + LocalDateTime.now().format(CODE_TIME_FORMATTER) + new Random().nextInt(10); } }