/**
 * @filename:PurchaseOrderServiceImpl 2024-09-10
 * @project KJT v1.0.0 Copyright(c) 2024 wanglang Co. Ltd. All right reserved.
 */
package com.trade.service.trade.purchaseorder.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.io.IoUtil;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.deepoove.poi.config.Configure;
import com.deepoove.poi.plugin.table.LoopRowTableRenderPolicy;
import com.trade.common.utils.ConstantUtil;
import com.trade.common.utils.DateUtils;
import com.trade.common.utils.LoggerUtil;
import com.trade.common.utils.StringUtils;
import com.trade.common.utils.bean.BeanCopyUtils;
import com.trade.common.utils.bean.Builder;
import com.trade.common.utils.uuid.BizNoUtil;
import com.trade.service.DictConstants;
import com.trade.service.filestorage.enums.FileTypeEnum;
import com.trade.service.TransStruct;
import com.trade.service.enterprise.companyrelated.domain.VendorEntity;
import com.trade.service.enterprise.companyrelated.service.IVendorEntityService;
import com.trade.service.contract.dto.ContractGenInputItem;
import com.trade.service.contract.dto.ContractGenOutputItem;
import com.trade.service.contract.service.ContractService;
import com.trade.service.contract.service.ISFileTemplateService;
import com.trade.service.enterprise.customer.domain.Enterprise;
import com.trade.service.enterprise.customer.domain.EnterpriseRelatedPerson;
import com.trade.service.enterprise.customer.service.EnterpriseBaseService;
import com.trade.service.enterprise.customer.service.EnterpriseRelatedPersonBaseService;
import com.trade.service.filestorage.entity.BusinessRelateFile;
import com.trade.service.filestorage.entity.TFileStorage;
import com.trade.service.filestorage.service.BusinessRelateFileBaseService;
import com.trade.service.filestorage.service.TFileStorageService;
import com.trade.service.filestorage.util.oss.OSSUtil;
import com.trade.service.message.EmailConstant;
import com.trade.service.message.EmailTemplate;
import com.trade.service.system.service.ISysDictDataService;
import com.trade.service.thirdparty.xiaotu.dto.InvoiceQueryResponse;
import com.trade.service.trade.purchasecontract.domain.PurchaseCommodity;
import com.trade.service.trade.purchasecontract.service.PurchaseContractBaseService;
import com.trade.service.trade.purchaseorder.domain.*;
import com.trade.service.trade.purchaseorder.dto.*;
import com.trade.service.trade.purchaseorder.service.*;
import com.trade.service.trade.purchaseorder.vo.*;
import com.trade.service.trade.purchaseorder.mapper.PurchaseOrderMapper;
import com.trade.service.trade.purchasecontract.domain.PurchaseContract;
import com.trade.service.trade.purchasecontract.service.PurchaseCommodityBaseService;
import com.trade.service.trade.salescontract.domain.ContractTerms;

import com.trade.service.trade.salescontract.domain.SalesContract;
import com.trade.service.trade.salescontract.service.ContractTermsService;
import com.trade.service.trade.salescontract.service.SalesContractService;
import com.trade.service.trade.salesorder.constant.SaleOrderConstant;
import com.trade.service.trade.salesorder.domain.SalesOrder;

import com.trade.service.trade.salesorder.domain.SalesOrderGoods;
import com.trade.service.trade.salesorder.service.ISalesOrderGoodsService;
import com.trade.service.trade.salesorder.service.ISalesOrderService;
import com.trade.service.serialNum.service.SerialNumberGenerator;
import com.trade.service.tradingplatform.domain.TradingPlatform;
import com.trade.service.tradingplatform.service.TradingPlatformBaseService;
import org.slf4j.Logger;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.io.InputStream;
import java.math.BigDecimal;

import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;

/**
 * @Description: 订单信息服务层实现类
 * @version: v1.0.0
 * @author: wanglang
 */
@Service
public class PurchaseOrderServiceImpl extends ServiceImpl<PurchaseOrderMapper, PurchaseOrder> implements PurchaseOrderService {

    private static final Logger log = LoggerUtil.logger(LoggerUtil.LogFileNameEnum.SERVICES_LOG);
    @Resource
    private PurchaseOrderLogisticsService purchaseOrderLogisticsService;
    @Resource
    private ISalesOrderService salesOrderService;
    @Resource
    private SalesContractService salesContractService;
    @Resource
    private PurchaseContractBaseService purchaseContractBaseService;
    @Resource
    private PurchaseOrderCommodityService purchaseOrderCommodityService;
    @Resource
    private BusinessRelateFileBaseService businessRelateFileBaseService;
    @Resource
    private SerialNumberGenerator serialNumberGenerator;
    @Resource
    private ContractTermsService contractTermsService;
    @Resource
    private PurchaseCommodityBaseService purchaseCommodityBaseService;
    @Resource
    private ISFileTemplateService fileTemplateService;
    @Resource
    private EnterpriseBaseService enterpriseBaseService;
    @Resource
    private TradingPlatformBaseService tradingPlatformBaseService;
    @Resource
    private EnterpriseRelatedPersonBaseService relatedPersonBaseService;
    @Resource
    private TransStruct transStruct;
    @Resource
    private ContractService contractService;
    @Resource
    private PurchaseOrderInvoiceService purchaseOrderInvoiceService;
    @Resource
    private EmailTemplate emailTemplate;
    @Resource
    private IVendorEntityService vendorEntityService;
    @Resource
    private OSSUtil ossUtil;
    @Resource
    private TFileStorageService tFileStorageService;
    @Resource
    private PurchaseOrderInvoiceCommodityService purchaseOrderInvoiceCommodityService;
    @Resource
    private ISalesOrderGoodsService salesOrderGoodsService;
    @Resource
    private ISysDictDataService iSysDictDataService;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean saveOrderLogistics(PurchaseOrderLogisticsDto purchaseOrderLogisticsDto) {
        PurchaseOrderLogistics purchaseOrderLogistics = BeanCopyUtils.copy(purchaseOrderLogisticsDto,
                PurchaseOrderLogistics.class);
        PurchaseOrderLogisticsVo purchaseOrderLogisticsVo = purchaseOrderLogisticsService
                .queryByPurchaseOrderId(purchaseOrderLogisticsDto.getPurchaseOrderId());
        if (purchaseOrderLogisticsVo != null) {
            purchaseOrderLogistics.setId(purchaseOrderLogisticsVo.getId());
            purchaseOrderLogisticsService.updateById(purchaseOrderLogistics);
        } else {
            purchaseOrderLogisticsService.save(purchaseOrderLogistics);
        }
        BusinessRelateFile businessRelateFile = Builder.of(BusinessRelateFile.class)
                .with(BusinessRelateFile::setBelongId, purchaseOrderLogistics.getId())
                .with(BusinessRelateFile::setBelongType, ConstantUtil.PURCHASE_ORDER)
                .with(BusinessRelateFile::setFileType, FileTypeEnum.PURCHASE_ORDER_TRANS_PROVE.getCode())
                .with(BusinessRelateFile::setFileId, purchaseOrderLogisticsDto.getTransportCertificateFileId()).build();
        businessRelateFileBaseService.upsertBusinessRelateFiles(businessRelateFile);
        return true;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean saveOrder(List<PurchaseOrderDto> purchaseOrderDtos, PurchaseContract purchaseContract) {
        if (CollectionUtil.isEmpty(purchaseOrderDtos)) {
            return false;
        }
        List<PurchaseOrder> purchaseOrders = this.lambdaQuery()
                .eq(PurchaseOrder::getSalesOrderId, purchaseOrderDtos.get(0).getSalesOrderId()).list();
        if (CollectionUtil.isNotEmpty(purchaseOrders)) {
            this.removeBatchByIds(purchaseOrders);
            for (PurchaseOrder purchaseOrder : purchaseOrders) {
                List<PurchaseOrderCommodity> purchaseOrderCommoditys = purchaseOrderCommodityService.lambdaQuery()
                        .eq(PurchaseOrderCommodity::getPurchaseOrderId, purchaseOrder.getId()).list();
                if (CollectionUtil.isNotEmpty(purchaseOrderCommoditys)) {
                    purchaseOrderCommodityService.removeBatchByIds(purchaseOrderCommoditys);
                }
            }
        }
        for (PurchaseOrderDto purchaseOrderDto : purchaseOrderDtos) {
            PurchaseOrder purchaseOrder = new PurchaseOrder();
            purchaseOrder.setSalesOrderId(purchaseOrderDto.getSalesOrderId());
            purchaseOrder.setCustomerUserId(purchaseOrderDto.getCustomerUserId());
            purchaseOrder.setSalesOrderId(purchaseOrderDto.getSalesOrderId());
            purchaseOrder.setEntityNo(purchaseOrderDto.getVendorEntityNo());
            purchaseOrder.setDeleted(0);
            List<PurchaseOrderCommodity> commodities = purchaseOrderDto.getCommodities();
            BigDecimal amount = commodities.stream().map(PurchaseOrderCommodity::getAmount).reduce(BigDecimal::add)
                    .orElse(BigDecimal.ZERO);
            BigDecimal taxRefundRate = commodities.stream()
                    .map(s -> s.getAmount().multiply(s.getTaxRefundRate()).multiply(s.getNumber()))
                    .reduce(BigDecimal::add).orElse(BigDecimal.ZERO);
            purchaseOrder.setAmountTotal(amount);
            purchaseOrder.setTaxAmountTotal(taxRefundRate);
            SalesOrder salesOrder = salesOrderService.getById(purchaseOrderDto.getSalesOrderId());
            SalesContract salesContract = salesContractService.getById(salesOrder.getSaleContractId());
            purchaseOrder.setAgencyCertNo(salesContract.getAgencyCertNo());
            if (purchaseContract == null) {
                if (StringUtils.isNotEmpty(purchaseOrder.getEntityNo())) {
                    purchaseContract = purchaseContractBaseService.lambdaQuery()
                            .eq(PurchaseContract::getSalesContractNo, salesContract.getContractNo())
                            .eq(PurchaseContract::getVendorEntityNo, purchaseOrder.getEntityNo())
                            .eq(PurchaseContract::getDeleted, 0)
                            .eq(PurchaseContract::getStatus, DictConstants.PURCHASE_CONTRACT_STATUS_DONE).one();
                } else {
                    purchaseContract = purchaseContractBaseService.lambdaQuery()
                            .eq(PurchaseContract::getSalesContractNo, salesContract.getContractNo())
                            .eq(PurchaseContract::getDeleted, 0)
                            .eq(PurchaseContract::getStatus, DictConstants.PURCHASE_CONTRACT_STATUS_DONE).one();
                }
            }
            if (purchaseContract == null) {
                return false;
            }
            purchaseOrder.setPurchaseContractNo(purchaseContract.getContractNo());
            ContractTerms contractTerms = contractTermsService.getByContractIdAndType(purchaseContract.getId(),
                    ConstantUtil.PURCHASE_CONTRACT_CODE);
            purchaseOrder.setInvoiceType(contractTerms.getInvoiceType());
            purchaseOrder.setSettlementCycle(contractTerms.getSettlementCycle());
            purchaseOrder.setOrderNo(serialNumberGenerator.nextValue(ConstantUtil.PURCHASE_ORDER_NO_PREFIX,
                    salesOrder.getOrderNo().replace(BizNoUtil.SALE_ORDER_NO_PREFIX, "")));
            List<PurchaseCommodity> purchaseCommodities = purchaseCommodityBaseService.lambdaQuery()
                    .eq(PurchaseCommodity::getPurchaseContractId, purchaseContract.getId())
                    .eq(PurchaseCommodity::getSalesContractId, 0).eq(PurchaseCommodity::getDeleted, 0).list();
            for (PurchaseOrderCommodity commodity : commodities) {
                purchaseCommodities.stream()
                        .filter(p -> p.getSalesCommodityId().equals(commodity.getSalesCommodityId())).findAny()
                        .ifPresent(purchaseCommodity -> commodity.setPriceUnit(purchaseCommodity.getPriceUnit()));
            }
            this.baseMapper.insert(purchaseOrder);
            commodities.forEach(commodity -> commodity.setPurchaseOrderId(purchaseOrder.getId()));
            purchaseOrderCommodityService.saveBatch(commodities);
            PurchaseContract finalPurchaseContract = purchaseContract;
            CompletableFuture
                    .runAsync(
                            () -> handleInvoiceNotice(purchaseOrder, commodities, contractTerms, finalPurchaseContract))
                    .exceptionally(e -> {
                        log.error("customerUserId={}orderNo={},处理开票通知书失败:{}", purchaseOrder.getCustomerUserId(),
                                purchaseOrder.getOrderNo(), e);
                        return null;
                    });
        }
        return true;
    }

    @Override
    public List<PurchaseOrderVo> selectByCondition(PurchaseSearchDto purchaseSearch) {
        List<PurchaseOrderVo> purchaseOrderVos = this.baseMapper.selectByCondition(purchaseSearch);
        for (PurchaseOrderVo purchaseOrderVo : purchaseOrderVos) {
            PurchaseOrderLogisticsVo purchaseOrderLogisticsVo = purchaseOrderLogisticsService
                    .queryByPurchaseOrderId(purchaseOrderVo.getId());
            if (purchaseOrderLogisticsVo != null) {
                purchaseOrderVo.setLogisticsStatus("1");
            } else {
                purchaseOrderVo.setLogisticsStatus("0");
            }
        }
        return purchaseOrderVos;
    }

    @Override
    public PurchaseOrderDetailsVo getDetailsById(Long id) {
        PurchaseOrderDetailsVo purchaseOrderDetailsVo = this.baseMapper.selectDetailsById(id);
        if (purchaseOrderDetailsVo == null) {
            return purchaseOrderDetailsVo;
        }
        List<PurchaseOrderCommodity> commodities = purchaseOrderCommodityService.lambdaQuery()
                .eq(PurchaseOrderCommodity::getPurchaseOrderId, id).list();
        purchaseOrderDetailsVo.setCommodityList(commodities);
        PurchaseOrderLogisticsVo purchaseOrderLogisticsVo = purchaseOrderLogisticsService.queryByPurchaseOrderId(id);
        if (purchaseOrderLogisticsVo != null) {
            // BusinessRelateFile businessRelateFile = businessRelateFileBaseService.getByCondition(
            // purchaseOrderLogisticsVo.getId(), ConstantUtil.PURCHASE_ORDER,
            // FileTypeEnum.PURCHASE_ORDER_TRANS_PROVE.getCode());
            businessRelateFileBaseService.fillBizObjFiles(purchaseOrderLogisticsVo, purchaseOrderLogisticsVo.getId(),
                    ConstantUtil.PURCHASE_ORDER, FileTypeEnum.PURCHASE_ORDER_TRANS_PROVE.getCode());
            purchaseOrderDetailsVo.setLogisticsVo(purchaseOrderLogisticsVo);
            // if (businessRelateFile != null) {
            // purchaseOrderLogisticsVo.setId(businessRelateFile.getId());
            // }
        }
        PurchaseContract purchaseContract = purchaseContractBaseService.lambdaQuery()
                .eq(PurchaseContract::getContractNo, purchaseOrderDetailsVo.getPurchaseContractNo())
                .eq(PurchaseContract::getCustomerUserId, purchaseOrderDetailsVo.getCustomerUserId())
                .eq(PurchaseContract::getDeleted, 0).one();
        ContractTerms contractTerms = contractTermsService.getByContractIdAndType(purchaseContract.getId(),
                ConstantUtil.PURCHASE_CONTRACT_CODE);
        PurchaseAcountVo purchaseAcountVo = new PurchaseAcountVo();
        purchaseAcountVo.setAccountName(contractTerms.getAccountName());
        purchaseAcountVo.setAccountNumber(contractTerms.getAccountNumber());
        purchaseAcountVo.setOpeningBank(contractTerms.getOpeningBank());
        purchaseOrderDetailsVo.setPurchaseAcountVo(purchaseAcountVo);
        List<PurchaseOrderInvoice> purchaseOrderInvoices = purchaseOrderInvoiceService.getByOrderId(id);
        if (CollectionUtil.isNotEmpty(purchaseOrderInvoices)) {
            List<OrderInvoiceVo> invoiceVos = new ArrayList<>();
            for (PurchaseOrderInvoice purchaseOrderInvoice : purchaseOrderInvoices) {
                OrderInvoiceVo invoiceVo = BeanCopyUtils.copy(purchaseOrderInvoice, OrderInvoiceVo.class);
                businessRelateFileBaseService.fillBizObjFiles(invoiceVo, purchaseOrderInvoice.getId(),
                        ConstantUtil.PURCHASE_ORDER, FileTypeEnum.PURCHASE_ORDER_INVOICE.getCode());
                invoiceVo.setAmount(purchaseOrderInvoice.getAmount().add(purchaseOrderInvoice.getTaxAmount()));
                List<InvoiceCommodityDto> commodityDtos = purchaseOrderInvoiceCommodityService
                        .getByInvoiceId(purchaseOrderInvoice.getId());
                if (CollectionUtil.isNotEmpty(commodityDtos)) {
                    BigDecimal allNumber = commodityDtos.stream()
                            .filter(commodityDto -> commodityDto.getNumber() != null)
                            .map(InvoiceCommodityDto::getNumber).reduce(BigDecimal.ZERO, BigDecimal::add);
                    invoiceVo.setNumber(allNumber);
                    InvoiceCommodityDto invoiceCommodityDto = commodityDtos.get(0);
                    if (invoiceCommodityDto != null) {
                        invoiceVo.setTaxRate(invoiceCommodityDto.getTaxRate());
                    }
                }
                invoiceVos.add(invoiceVo);
            }
            purchaseOrderDetailsVo.setInvoiceList(invoiceVos);
        }
        return purchaseOrderDetailsVo;
    }

    @Override
    public List<TradingPlatformInvoiceVo> queryAgencyTaxNum(List<Long> ids, String invoicePullStatus) {
        return this.baseMapper.selectAgencyTaxNum(ids, invoicePullStatus);
    }

    @Override
    public List<TradingPlatformInvoiceVo> queryCustTaxNum(List<Long> ids, String invoicePullStatus) {
        return this.baseMapper.selectCustTaxNum(ids, invoicePullStatus);
    }

    @Override
    public List<TradingPlatformInvoiceVo> queryClientTaxNum(List<Long> ids, String invoicePullStatus) {
        return this.baseMapper.selectClientTaxNum(ids, invoicePullStatus);
    }

    @Override
    public boolean updateInvoicePullStatus(Long id, String status) {
        return this.baseMapper.updateInvoicePullStatus(id, status) > 0;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void handleOrderInvoice(List<InvoiceQueryResponse> invoiceQueryResponses, Long orderId,
            BigDecimal amountTotal, int source) {
        // Map<String, List<InvoiceQueryResponse>> groupBy = invoiceQueryResponses.stream()
        // .collect(Collectors.groupingBy(i -> i.getFpDm() + "_" + i.getFphm()));
        Map<String, List<InvoiceQueryResponse>> groupBy = invoiceQueryResponses.stream()
                .collect(Collectors.groupingBy(i -> i.getJhpzh()));
        BigDecimal invoiceAmountTotal = BigDecimal.ZERO;
        for (Map.Entry<String, List<InvoiceQueryResponse>> entry : groupBy.entrySet()) {
            InvoiceQueryResponse invoiceQueryResponse = entry.getValue().get(0);
            invoiceQueryResponse.setZje(entry.getValue().stream().map(InvoiceQueryResponse::getJe)
                    .reduce(BigDecimal.ZERO, BigDecimal::add));
            invoiceQueryResponse.setZse(entry.getValue().stream().map(InvoiceQueryResponse::getSe)
                    .reduce(BigDecimal.ZERO, BigDecimal::add));
            invoiceAmountTotal = invoiceAmountTotal.add(invoiceQueryResponse.getZje());
            // PurchaseOrderInvoice purchaseOrderInvoice = purchaseOrderInvoiceService
            // .getByCodeAndNumber(entry.getKey().split("_")[0], entry.getKey().split("_")[1]);
            PurchaseOrderInvoice purchaseOrderInvoice = purchaseOrderInvoiceService
                    .getByPurchaseVoucherNo(entry.getKey());
            PurchaseOrderInvoice invoice = new PurchaseOrderInvoice();
            invoice.setInvoiceCode(invoiceQueryResponse.getFpDm());
            invoice.setInvoiceNumber(invoiceQueryResponse.getFphm());
            invoice.setInvoiceStatus(invoiceQueryResponse.getRzxfzzszyfpbz());
            invoice.setDigitalInvoiceNumber(invoiceQueryResponse.getSdfphm());
            invoice.setInvoiceType(invoiceQueryResponse.getFplxDm());
            invoice.setTaxAmount(invoiceQueryResponse.getZse());
            invoice.setAmount(invoiceQueryResponse.getZje());
            invoice.setInvoicingDate(DateUtils.longToLocalDate(invoiceQueryResponse.getKprq()));
            invoice.setOrderId(orderId);
            invoice.setPurchaseVoucherNo(invoiceQueryResponse.getJhpzh());
            invoice.setSource(source);
            if (invoiceQueryResponse.getRzrq() != null) {
                invoice.setCertificationDate(DateUtils.longToLocalDate(invoiceQueryResponse.getRzrq()));
            }
            if (purchaseOrderInvoice != null) {
                purchaseOrderInvoice.setInvoiceStatus(invoiceQueryResponse.getRzxfzzszyfpbz());
                purchaseOrderInvoiceService.updateById(purchaseOrderInvoice);
            } else {
                purchaseOrderInvoiceService.save(invoice);
            }
            handleOrderInvoiceCommodity(entry.getValue(), invoice.getId());
        }
        BigDecimal threshold = new BigDecimal("0.1");
        if (amountTotal.subtract(invoiceAmountTotal).abs().compareTo(threshold) < 0) {
            updateInvoicePullStatus(orderId, "1");
        }
    }

    @Override
    public boolean handleOrder(Long purchaseContractId) {
        PurchaseContract purchaseContract = purchaseContractBaseService.getById(purchaseContractId);
        Enterprise enterprise = enterpriseBaseService.getEnterpriseByCustomerId(purchaseContract.getCustomerUserId());
        if (enterprise == null) {
            log.error("创建采购合同:用户未完成认证（用户id：" + purchaseContract.getCustomerUserId() + "）");
            return false;
        }
        // “自营出口”的“生产企业”,不生成采购订单
        if (DictConstants.EXPORT_TYPE_SELF.equals(enterprise.getExportType())
                && (DictConstants.ENTERPRISE_TYPE_PRODUCE.equals(enterprise.getEnterpriseType())
                        || DictConstants.ENTERPRISE_TYPE_PRODUCE_EXTERNAL.equals(enterprise.getEnterpriseType()))) {
            return false;
        }
        SalesContract salesContract = salesContractService.lambdaQuery()
                .eq(SalesContract::getContractNo, purchaseContract.getSalesContractNo())
                .eq(SalesContract::getDeleted, 0).one();
        if (salesContract == null) {
            return false;
        }
        List<SalesOrder> salesOrders = salesOrderService.lambdaQuery()
                .eq(SalesOrder::getSaleContractId, salesContract.getId()).eq(SalesOrder::getDeleted, 0).list();
        if (CollectionUtil.isEmpty(salesOrders)) {
            return false;
        }
        for (SalesOrder salesOrder : salesOrders) {
            Long orderId = salesOrder.getId();
            List<SalesOrderGoods> salesOrderGoods = salesOrderGoodsService.lambdaQuery()
                    .eq(SalesOrderGoods::getSaleOrderId, orderId).eq(SalesOrderGoods::getDeleted, 0).list();
            // 保存采购订单
            List<PurchaseOrderDto> purchaseOrderDtos = new ArrayList<>();
            Map<String, List<SalesOrderGoods>> entityNoNotEmp = salesOrderGoods.stream()
                    .filter(s -> StringUtils.isNotEmpty(s.getVendorEntityNo())).collect(Collectors
                            .groupingBy(SalesOrderGoods::getVendorEntityNo, HashMap::new, Collectors.toList()));
            List<SalesOrderGoods> entityNoEmps = salesOrderGoods.stream()
                    .filter(s -> StringUtils.isEmpty(s.getVendorEntityNo())).collect(Collectors.toList());
            entityNoNotEmp.forEach((k, v) -> {
                createPurchaseOrder(v, orderId, salesOrder, k, purchaseOrderDtos);
            });
            if (CollectionUtil.isNotEmpty(entityNoEmps)) {
                createPurchaseOrder(entityNoEmps, orderId, salesOrder, null, purchaseOrderDtos);
            }
            saveOrder(purchaseOrderDtos, purchaseContract);
        }
        return true;
    }

    @Override
    public void createPurchaseOrder(List<SalesOrderGoods> salesOrderGoods, Long finalOrderId, SalesOrder salesOrder,
            String entityNo, List<PurchaseOrderDto> purchaseOrderDtos) {
        PurchaseOrderDto purchaseOrderDto = new PurchaseOrderDto();
        purchaseOrderDto.setSalesOrderId(finalOrderId);
        purchaseOrderDto.setSalesOrderNo(salesOrder.getOrderNo());
        purchaseOrderDto.setVendorEntityNo(entityNo);
        purchaseOrderDto.setCustomerUserId(salesOrder.getCustomerUserId());
        purchaseOrderDto.setSaleContractId(salesOrder.getSaleContractId());
        List<PurchaseOrderCommodity> commodities = new ArrayList<>();
        for (SalesOrderGoods orderGoods : salesOrderGoods) {
            PurchaseOrderCommodity commodity = new PurchaseOrderCommodity();
            commodity.setPriceUnit(orderGoods.getPrice());
            commodity.setAmount(orderGoods.getPriceTotal());
            commodity.setHsCode(orderGoods.getHsCode());
            commodity.setMeasurementUnit(orderGoods.getUnit());
            commodity.setModel(orderGoods.getModel());
            commodity.setName(orderGoods.getName());
            commodity.setPackSpec(orderGoods.getPackingSpecifications());
            commodity.setNumber(orderGoods.getCount());
            commodity.setSalesCommodityId(orderGoods.getSalesCommodityId());
            commodity.setTaxRefundRate(orderGoods.getTaxRefundRate());
            commodity.setDeclarationName(orderGoods.getDeclarationName());
            commodities.add(commodity);
        }
        purchaseOrderDto.setCommodities(commodities);
        purchaseOrderDtos.add(purchaseOrderDto);
    }

    @Override
    public List<PurchaseOrder> listBySaleOrderId(Long salesOrderId) {
        return this.lambdaQuery().eq(PurchaseOrder::getSalesOrderId, salesOrderId).list();
    }

    public void handleOrderInvoiceCommodity(List<InvoiceQueryResponse> invoiceQueryResponses, Long invoiceId) {
        List<PurchaseOrderInvoiceCommodity> purchaseOrderInvoiceCommodities = new ArrayList<>();
        for (InvoiceQueryResponse invoiceQueryRespons : invoiceQueryResponses) {
            PurchaseOrderInvoiceCommodity purchaseOrderInvoiceCommodity = new PurchaseOrderInvoiceCommodity();
            purchaseOrderInvoiceCommodity.setInvoiceId(invoiceId);
            purchaseOrderInvoiceCommodity.setCommodityCode(invoiceQueryRespons.getSphfwssflhbbm());
            purchaseOrderInvoiceCommodity.setName(invoiceQueryRespons.getHwhyslwmc());
            purchaseOrderInvoiceCommodity.setModel(invoiceQueryRespons.getGgxh());
            purchaseOrderInvoiceCommodity.setMeasurementUnit(invoiceQueryRespons.getJldwmc());
            purchaseOrderInvoiceCommodity.setNumber(invoiceQueryRespons.getSl());
            purchaseOrderInvoiceCommodity.setAmount(invoiceQueryRespons.getJe());
            purchaseOrderInvoiceCommodity.setTaxAmount(invoiceQueryRespons.getSe());
            purchaseOrderInvoiceCommodity.setTaxRate(invoiceQueryRespons.getSl1());
            purchaseOrderInvoiceCommodity.setLineNumber(String.valueOf(invoiceQueryRespons.getHh()));
            purchaseOrderInvoiceCommodities.add(purchaseOrderInvoiceCommodity);
        }
        // List<String> commodityCodes = purchaseOrderInvoiceCommodities.stream().map(p -> p.getCommodityCode())
        // .collect(Collectors.toList());
        // List<PurchaseOrderInvoiceCommodity> invoiceCommodities = purchaseOrderInvoiceCommodityService
        // .getInvoiceCommodityByInvoiceId(invoiceId, commodityCodes);
        List<String> lineNumbers = purchaseOrderInvoiceCommodities.stream().map(p -> p.getLineNumber())
                .collect(Collectors.toList());
        List<PurchaseOrderInvoiceCommodity> invoiceCommodities = purchaseOrderInvoiceCommodityService
                .getInvoiceCommodityByLineNumbers(invoiceId, lineNumbers);
        if (CollectionUtil.isNotEmpty(invoiceCommodities)) {
            purchaseOrderInvoiceCommodityService.removeBatchByIds(invoiceCommodities);
        }
        purchaseOrderInvoiceCommodityService.saveBatch(purchaseOrderInvoiceCommodities);
    }

    private void handleInvoiceNotice(PurchaseOrder purchaseOrder, List<PurchaseOrderCommodity> commodities,
            ContractTerms contractTerms, PurchaseContract purchaseContract) {
        ContractGenInputItem contractGenInputItem = new ContractGenInputItem();
        String templateCode = fileTemplateService.selectByFileType(FileTypeEnum.PURCHASE_ORDER_INVOICE_NOTICE.getCode())
                .getTemplateCode();
        contractGenInputItem.setTemplateCode(templateCode);
        Enterprise enterprise = enterpriseBaseService.getEnterpriseByCustomerId(purchaseOrder.getCustomerUserId());
        EnterpriseRelatedPerson contact = relatedPersonBaseService
                .getContactByChangeRecordId(enterprise.getChangeRecordId());
        String customerName = enterprise.getName();
        String customerAddress = enterprise.getBusinessAddress();
        String contractTel = contact.getMobile();
        String certNo = enterprise.getCertNo();
        String entityName = enterprise.getName();
        String contactPerson = contact.getName();
        String phone = contact.getMobile();
        String address = contact.getLiveAddress();
        String email = contact.getEmail();
        String receiver;
        if (DictConstants.EXPORT_TYPE_PROXY.equals(enterprise.getExportType())) {
            TradingPlatform tradingPlatform = tradingPlatformBaseService.lambdaQuery()
                    .eq(TradingPlatform::getCertNo, purchaseOrder.getAgencyCertNo()).one();
            customerName = tradingPlatform.getPlatformName();
            customerAddress = tradingPlatform.getBusinessAddress();
            contractTel = tradingPlatform.getContactMobile();
            certNo = tradingPlatform.getCertNo();
            receiver = contact.getEmail();
            contactPerson = tradingPlatform.getContactName();
            phone = tradingPlatform.getContactMobile();
            address = tradingPlatform.getBusinessAddress();
            email = tradingPlatform.getContactEmail();
        } else {
            VendorEntity entity = vendorEntityService.getByEntityNo(purchaseOrder.getEntityNo());
            receiver = entity.getContactEmail();
            entityName = entity.getEntityName();
        }
        String bankAndAccount = contractTerms.getOpeningBank() + "、" + contractTerms.getAccountNumber();
        Map<String, Object> params = new HashMap<>();
        String invoiceType = iSysDictDataService.selectDictLabel("invoice_type", purchaseOrder.getInvoiceType());
        params.put("invoiceType", invoiceType);
        params.put("enterpriseName", customerName);
        params.put("certNo", certNo);
        params.put("addressPhone", customerAddress + "、" + contractTel);
        params.put("bankAndAccount", bankAndAccount);
        params.put("total", purchaseOrder.getAmountTotal());
        params.put("taxTotal", purchaseOrder.getTaxAmountTotal());
        params.put("purchaseOrderNo", purchaseOrder.getOrderNo());
        List<PurchaseOrderCommodityTL> commoditys = transStruct.transPurchaseOrderCommodityForTLList(commodities);
        params.put(SaleOrderConstant.ORDER_INVOICE_GOODS_LIST_KEY, commoditys);
        contractGenInputItem.setParams(params);
        LoopRowTableRenderPolicy policy = new LoopRowTableRenderPolicy();
        contractGenInputItem
                .setConfig(Configure.builder().bind(SaleOrderConstant.ORDER_INVOICE_GOODS_LIST_KEY, policy).build());
        ContractGenOutputItem outputItem = contractService.generateSingleContract(contractGenInputItem,
                purchaseOrder.getCustomerUserId());
        // PurchaseOrderInvoice purchaseOrderInvoice = new PurchaseOrderInvoice();
        // purchaseOrderInvoice.setOrderId(purchaseOrder.getId());
        // purchaseOrderInvoice.setFileId(outputItem.getFileId());
        // purchaseOrderInvoice.setAmount(purchaseOrder.getAmountTotal());
        // purchaseOrderInvoiceService.save(purchaseOrderInvoice);
        BusinessRelateFile businessRelateFile = new BusinessRelateFile();
        businessRelateFile.setFileId(outputItem.getFileId());
        businessRelateFile.setBelongId(purchaseOrder.getId());
        businessRelateFile.setBelongType(ConstantUtil.PURCHASE_ORDER);
        businessRelateFile.setFileType(FileTypeEnum.PURCHASE_ORDER_INVOICE_NOTICE.getCode());
        businessRelateFileBaseService.addBusinessRelateFiles(Collections.singletonList(businessRelateFile));
        Map<String, Object> variables = new HashMap<>();
        variables.put("entityName", entityName);
        variables.put("purchaseContractNo", purchaseContract.getContractNo());
        variables.put("purchaseContractName", purchaseContract.getContractName());
        variables.put("orderNo", purchaseOrder.getOrderNo());
        variables.put("contactPerson", contactPerson);
        variables.put("phone", phone);
        variables.put("address", address);
        variables.put("mailbox", email);
        variables.put("companyName", customerName);
        CompletableFuture
                .runAsync(() -> sendEmail(receiver, outputItem.getFileId(), purchaseOrder.getOrderNo(), variables))
                .exceptionally(e -> {
                    log.error("customerUserId={}orderNo={},发送邮件失败:{}", purchaseOrder.getCustomerUserId(),
                            purchaseOrder.getOrderNo(), e);
                    return null;
                });
    }

    /**
     * 发送邮件
     * 
     * @param receiver
     * @param fileId
     * @param orderNo
     * @param variables
     */
    private void sendEmail(String receiver, Long fileId, String orderNo, Map<String, Object> variables) {
        TFileStorage tFileStorage = tFileStorageService.getFileStorageById(fileId);
        InputStream in = ossUtil.downloadFile(tFileStorage.getPath());
        String title = EmailConstant.POKPTZS_EMAIL_SUBJECT.replace("xxx", orderNo);
        emailTemplate.sendMailTemplate(title, EmailConstant.POKPTZS_EMAIL_TEMPLATE, IoUtil.readBytes(in),
                tFileStorage.getOriginalName(), variables, null, null, new String[] {
                        receiver
                });
    }
}
