package cn.iocoder.foodnexus.module.order.service.customerorder;

import cn.iocoder.foodnexus.framework.common.enums.UserSystemEnum;
import cn.iocoder.foodnexus.framework.common.util.CommonUtil;
import cn.iocoder.foodnexus.framework.common.util.spring.SpringUtils;
import cn.iocoder.foodnexus.framework.security.core.LoginUser;
import cn.iocoder.foodnexus.framework.security.core.util.SecurityFrameworkUtils;
import cn.iocoder.foodnexus.module.customerpermission.core.annotation.CustomerVisible;
import cn.iocoder.foodnexus.module.erp.api.PurchaseOrderSplitEvent;
import cn.iocoder.foodnexus.module.erp.api.service.ErpCustomerApi;
import cn.iocoder.foodnexus.module.erp.api.service.ErpSupplierApi;
import cn.iocoder.foodnexus.module.erp.api.service.ErpWarehouseApi;
import cn.iocoder.foodnexus.module.erp.controller.admin.sale.vo.returns.ErpSaleReturnSaveReqVO;
import cn.iocoder.foodnexus.module.erp.dal.dataobject.sale.*;
import cn.iocoder.foodnexus.module.erp.service.customerwarehouse.CustomerWarehouseService;
import cn.iocoder.foodnexus.module.erp.service.purchase.ErpPurchaseOrderServiceImpl;
import cn.iocoder.foodnexus.module.erp.service.sale.ErpSaleOrderService;
import cn.iocoder.foodnexus.module.erp.service.sale.ErpSaleOutService;
import cn.iocoder.foodnexus.module.erp.service.sale.ErpSaleReturnService;
import cn.iocoder.foodnexus.module.operations.dal.dataobject.inquiresupplierpush.InquireSupplierPushDO;
import cn.iocoder.foodnexus.module.operations.dal.dataobject.scoringweight.ScoringWeightDO;
import cn.iocoder.foodnexus.module.operations.service.inquiresupplierpush.InquireSupplierPushService;
import cn.iocoder.foodnexus.module.operations.service.scoringweight.ScoringWeightService;
import cn.iocoder.foodnexus.module.order.api.CustomerOrderApi;
import cn.iocoder.foodnexus.module.order.api.CustomerOrderRecordApi;
import cn.iocoder.foodnexus.module.order.controller.admin.orderScore.vo.OrderScoreSaveReqVO;
import cn.iocoder.foodnexus.module.order.controller.app.customerOrder.vo.*;
import cn.iocoder.foodnexus.module.order.dto.*;
import cn.iocoder.foodnexus.module.order.dto.CustomerOrderRemark;
import cn.iocoder.foodnexus.module.order.dal.dataobject.customerorderitem.CustomerOrderItemDO;
import cn.iocoder.foodnexus.module.order.dal.mysql.customerorderitem.CustomerOrderItemMapper;
import cn.iocoder.foodnexus.module.order.enums.CustomerOrderStatus;
import cn.iocoder.foodnexus.module.order.service.customeraddress.CustomerAddressService;
import cn.iocoder.foodnexus.module.order.service.customerorderitem.CustomerOrderItemService;
import cn.iocoder.foodnexus.module.order.service.orderScore.OrderScoreService;
import cn.iocoder.foodnexus.module.product.api.InquireCustomerApi;
import cn.iocoder.foodnexus.module.product.api.dto.CustomerVisibleProductRespDTO;
import cn.iocoder.foodnexus.module.product.api.dto.ProductInfo;
import cn.iocoder.foodnexus.module.product.dal.dataobject.spu.ProductSpuDO;
import cn.iocoder.foodnexus.module.product.service.spu.ProductSpuService;
import cn.iocoder.foodnexus.module.system.dal.dataobject.user.AdminUserDO;
import cn.iocoder.foodnexus.module.system.service.user.AdminUserService;
import cn.iocoder.foodnexus.module.system.util.GenCodeUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import jakarta.annotation.Resource;
import org.springframework.validation.annotation.Validated;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.*;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;

import cn.iocoder.foodnexus.module.order.controller.admin.customerorder.vo.*;
import cn.iocoder.foodnexus.module.order.dal.dataobject.customerorder.CustomerOrderDO;
import cn.iocoder.foodnexus.framework.common.pojo.PageResult;
import cn.iocoder.foodnexus.framework.common.util.object.BeanUtils;

import cn.iocoder.foodnexus.module.order.dal.mysql.customerorder.CustomerOrderMapper;

import static cn.iocoder.foodnexus.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.foodnexus.module.order.enums.ErrorCodeConstants.*;

/**
 * 客户总订单 Service 实现类
 *
 * @author 超级管理员
 */
@Service
@Validated
public class CustomerOrderServiceImpl implements CustomerOrderService, CustomerOrderApi {

    @Resource
    private CustomerOrderMapper customerOrderMapper;

    @Autowired
    private CustomerOrderItemService customerOrderItemService;

    @Autowired
    private CustomerOrderItemMapper customerOrderItemMapper;

    @Autowired
    private CustomerWarehouseService customerWarehouseService;

    @Autowired
    private InquireCustomerApi inquireCustomerApi;

    @Autowired
    private ErpCustomerApi customerApi;

    @Autowired
    private ErpWarehouseApi warehouseApi;

    @Autowired
    private CustomerAddressService addressService;

    @Autowired
    private InquireSupplierPushService inquireSupplierPushService;

    @Autowired
    private ErpSupplierApi supplierApi;

    @Autowired
    @Lazy
    private CustomerOrderRecordApi orderRecordApi;

    @Autowired
    private ProductSpuService productSpuService;

    @Autowired
    @Lazy
    private ErpSaleOutService saleOutService;

    @Autowired
    @Lazy
    private ErpSaleReturnService saleReturnService;

    @Autowired
    @Lazy
    private ErpSaleOrderService saleOrderService;

    @Autowired
    private ScoringWeightService scoringWeightService;

    @Autowired
    private OrderScoreService orderScoreService;

    @Autowired
    private AdminUserService userService;

    @Autowired
    private GenCodeUtils genCodeUtils;

    @Override
    public Long createCustomerOrder(CustomerOrderSaveReqVO createReqVO) {
        // 插入
        CustomerOrderDO customerOrder = BeanUtils.toBean(createReqVO, CustomerOrderDO.class);
        customerOrderMapper.insert(customerOrder);

        // 返回
        return customerOrder.getId();
    }

    @Override
    public void updateCustomerOrder(CustomerOrderSaveReqVO updateReqVO) {
        // 校验存在
        validateCustomerOrderExists(updateReqVO.getId());
        // 更新
        CustomerOrderDO updateObj = BeanUtils.toBean(updateReqVO, CustomerOrderDO.class);
        customerOrderMapper.updateById(updateObj);
    }

    @Override
    public void deleteCustomerOrder(Long id) {
        // 校验存在
        validateCustomerOrderExists(id);
        // 删除
        customerOrderMapper.deleteById(id);
    }

    @Override
        public void deleteCustomerOrderListByIds(List<Long> ids) {
        // 删除
        customerOrderMapper.deleteByIds(ids);
        }


    private void validateCustomerOrderExists(Long id) {
        if (customerOrderMapper.selectById(id) == null) {
            throw exception(CUSTOMER_ORDER_NOT_EXISTS);
        }
    }

    @Override
    public CustomerOrderDO getCustomerOrder(Long id) {
        return customerOrderMapper.selectById(id);
    }

    @Override
    public PageResult<CustomerOrderDO> getCustomerOrderPage(CustomerOrderPageReqVO pageReqVO) {
        return customerOrderMapper.selectPage(pageReqVO);
    }

    /**
     * 客户创建订单
     *
     * @param createReqVO
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    @CustomerVisible
    public Long appCreateCustomerOrder(AppCustomerOrderSaveReqVO createReqVO) {
        LoginUser loginUser = SecurityFrameworkUtils.getLoginUser();
        Long customerId = customerApi.queryCustomerIdByUserId(loginUser.getId());
        this.validCustomerOrder(createReqVO, customerId);
        CustomerVisibleProductRespDTO dto = inquireCustomerApi.queryCustomerIdByCustomerId(customerId);
        Map<Long, CustomerVisibleProductRespDTO.CustomerProduct> customerProductMap = CommonUtil.listConvertMap(dto.getItems(), CustomerVisibleProductRespDTO.CustomerProduct::getProductId);
        Set<Long> supplierSet = new HashSet<>();
        Set<Long> procuctSet = new HashSet<>();
        for (AppCustomerOrderItemSaveReqVO item : createReqVO.getOrderItems()) {
            if (customerProductMap.containsKey(item.getProductId())) {
                CustomerVisibleProductRespDTO.CustomerProduct customerProduct = customerProductMap.get(item.getProductId());
                item.setOrderItemPrice(customerProduct.getSupplierQuote());
                item.setOrderItemTotal(customerProduct.getSupplierQuote() * item.getOrderItemQuantity());
                item.setMarketPrice(customerProduct.getMarketPrice());
                item.setDiscount(customerProduct.getFloatingRate());
                InquireSupplierPushDO inquireSupplierPush = inquireSupplierPushService.getInquireSupplierPush(customerProduct.getInquireSupplierId());
                procuctSet.add(inquireSupplierPush.getProductId());

                item.setSupplierId(inquireSupplierPush.getSupplierId());
                item.setSupplierName(supplierApi.queryNameById(inquireSupplierPush.getSupplierId()));
                supplierSet.add(inquireSupplierPush.getSupplierId());
            }
        }

        // 数据补全
        CustomerOrderSaveReqVO createOrder = BeanUtils.toBean(createReqVO, CustomerOrderSaveReqVO.class);
        createOrder.setCode(genCodeUtils.createAmBatch("XS"));
        createOrder.setOrderStatus(CustomerOrderStatus.ORDER_SUCCESS);
        createOrder.setCustomerId(customerId);
        AdminUserDO user = userService.getUser(loginUser.getId());
        createOrder.setCustomerDeptId(user.getDeptId());
        createOrder.setWarehouseInfo(warehouseApi.getInfoByWarehouseAreaId(createOrder.getWarehouseAreaId()));
        createOrder.setAddressInfo(BeanUtils.toBean(addressService.getCustomerAddress(createReqVO.getAddressId()), CustomerAddressInfo.class));
        createOrder.setSupplierCount(supplierSet.size());
        createOrder.setProductCount(procuctSet.size());
        // 子订单补全
        AtomicReference<Integer> orderAmount = new AtomicReference<>(0);
        List<CustomerOrderItemDO> collect = createReqVO.getOrderItems().stream().map(orderItem -> {
            CustomerOrderItemDO item = BeanUtils.toBean(orderItem, CustomerOrderItemDO.class);
            item.setCustomerId(customerId);
            item.setProductInfo(BeanUtils.toBean(productSpuService.getSpu(item.getProductId()),
                    ProductInfo.class));
            item.setProductName(item.getProductInfo().getName());
            item.setSignedQuantity(0);
            item.setSignedTotal(0);
            orderAmount.updateAndGet(v -> v + item.getOrderItemTotal());
            return item;
        }).collect(Collectors.toList());

        createOrder.setOrderAmount(orderAmount.get());

        Long customerOrderId = this.createCustomerOrder(createOrder);
        customerOrderItemService.createBatch(collect, customerOrderId);

        // 拆分采购订单
        orderSplitPurchase(customerOrderId);

        // 订单记录
        CustomerOrderRecordEvent event = new CustomerOrderRecordEvent();
        event.setOrderStatus(CustomerOrderStatus.ORDER_SUCCESS);
        event.setCustomerOrderId(customerOrderId);
        event.setCopyWriter(CommonUtil.asList(String.valueOf(createOrder.getOrderAmount()),
                String.valueOf(createOrder.getProductCount())));
        orderRecordApi.recordEvent(event);

        return customerOrderId;
    }

    /**
     * 客户修改订单
     *
     * @param updateReqVO
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    @CustomerVisible
    public void appUpdateCustomerOrder(AppCustomerOrderSaveReqVO updateReqVO) {
        LoginUser loginUser = SecurityFrameworkUtils.getLoginUser();
        CustomerOrderDO customerOrder = getCustomerOrder(updateReqVO.getId());
        if (CommonUtil.isEmpty(customerOrder)) {
            throw exception(CUSTOMER_ORDER_NOT_EXISTS);
        }
        Long customerId = customerApi.queryCustomerIdByUserId(loginUser.getId());
        this.validCustomerOrder(updateReqVO, customerId);
        // TODO 具体修改什么待定

        // TODO 采购订单拆分更新

    }

    /**
     * 取消订单
     *
     * @param reqVO
     */
    @Override
    public void cancel(AppCustomerOrderRemarkReqVO reqVO) {
        CustomerOrderDO customerOrder = getCustomerOrder(reqVO.getId());
        if (CommonUtil.isEmpty(customerOrder)) {
            throw exception(CUSTOMER_ORDER_NOT_EXISTS);
        }
        // TODO ... 取消订单校验待定（订单状态）
        CustomerOrderStatus orderStatus = customerOrder.getOrderStatus();
        if (orderStatus.equals(CustomerOrderStatus.ORDER_SUCCESS) ||
                orderStatus.equals(CustomerOrderStatus.ORDER_MATCH)) {
            CustomerOrderRemark orderRemark = new CustomerOrderRemark();
            orderRemark.setOperTime(new Date());
            orderRemark.setRemark(CommonUtil.getEls(reqVO.getRemark(), ""));
            orderRemark.setRemarkFiles(reqVO.getRemarkFiles());

            CustomerOrderDO updateInfo = new CustomerOrderDO();
            updateInfo.setId(reqVO.getId());
            updateInfo.setOrderRemark(orderRemark);
            customerOrderMapper.updateById(updateInfo);

            // 订单记录
            CustomerOrderRecordEvent event = new CustomerOrderRecordEvent();
            event.setOrderStatus(CustomerOrderStatus.CANCEL);
            event.setCustomerOrderId(reqVO.getId());
            orderRecordApi.recordEvent(event);
        } else {
            throw exception(CUSTOMER_ORDER_STATUS_ERROR);
        }
    }

    /**
     * 签收订单
     *
     * @param reqVO
     */
    @Override
    public void receipt(AppCustomerOrderRemarkReqVO reqVO) {
        // TODO .. 校验订单
        CustomerOrderDO customerOrder = getCustomerOrder(reqVO.getId());
        if (CommonUtil.isEmpty(customerOrder)) {
            throw exception(CUSTOMER_ORDER_NOT_EXISTS);
        }
        if (!customerOrder.getOrderStatus().equals(CustomerOrderStatus.ARRIVAL)) {
            throw exception(CUSTOMER_ORDER_STATUS_ERROR);
        }
        List<CustomerOrderItemDO> customerOrderItems = customerOrderItemMapper.selectList(CustomerOrderItemDO::getOrderId, reqVO.getId());
        ErpSaleOutDO saleOut = saleOutService.getSaleOutByCustomerOrderId(reqVO.getId());
        if (CommonUtil.isEmpty(saleOut)) {
            throw exception(CUSTOMER_ORDER_OUT_ERROR);
        }
        List<ErpSaleOutItemDO> saleOutItems = saleOutService.getSaleOutItemListByOutId(saleOut.getId());
        Map<Long, ErpSaleOutItemDO> productMap = CommonUtil.listConvertMap(saleOutItems, ErpSaleOutItemDO::getProductId);

        List<CustomerOrderItemDO> updateBatch = new ArrayList<>();
        AtomicReference<Integer> actualAmount = new AtomicReference<>(0);
        customerOrderItems.forEach(customerOrderItem -> {
            CustomerOrderItemDO updateItem  = new CustomerOrderItemDO();
            updateItem.setId(customerOrderItem.getId());
            if (productMap.containsKey(customerOrderItem.getProductId())) {
                ErpSaleOutItemDO saleOutItem = productMap.get(customerOrderItem.getProductId());
                updateItem.setSignedQuantity(saleOutItem.getCount());
                CustomerOrderRemark remark = new CustomerOrderRemark();
                remark.setOperTime(Date.from(saleOutItem.getCreateTime()
                        .atZone(ZoneId.systemDefault())  // 绑定系统默认时区
                        .toInstant() ));
                remark.setRemarkFiles(saleOutItem.getRemarkFiles());
                remark.setRemark(saleOutItem.getRemark());
                updateItem.setOrderRemark(remark);
            } else {
                updateItem.setSignedQuantity(customerOrderItem.getOrderItemQuantity());
            }
            updateItem.setSignedTotal(updateItem.getSignedQuantity() * customerOrderItem.getOrderItemPrice());
            actualAmount.updateAndGet(v -> v + updateItem.getSignedTotal());
            updateBatch.add(updateItem);
        });

        customerOrderItemMapper.updateBatch(updateBatch);
        // 更新实际支付金额
        CustomerOrderDO updateOrder = new CustomerOrderDO();
        updateOrder.setId(customerOrder.getId());
        updateOrder.setActualAmount(actualAmount.get());
        customerOrderMapper.updateById(updateOrder);

        // 订单记录
        CustomerOrderRecordEvent event = new CustomerOrderRecordEvent();
        event.setOrderStatus(CustomerOrderStatus.SIGN_RECEIPT);
        event.setCustomerOrderId(reqVO.getId());
        // TODO 签收单链接
        event.setCopyWriter(CommonUtil.asList("TODO 签收单链接"));
        orderRecordApi.recordEvent(event);
    }

    @Override
    public List<AppCustomerOrderReceiptRespVO> queryReceipt(Long id) {
        CustomerOrderDO customerOrder = getCustomerOrder(id);
        if (CommonUtil.isEmpty(customerOrder)) {
            throw exception(CUSTOMER_ORDER_NOT_EXISTS);
        }
        if (!customerOrder.getOrderStatus().equals(CustomerOrderStatus.ARRIVAL)) {
            throw exception(CUSTOMER_ORDER_STATUS_ERROR);
        }
        List<CustomerOrderItemDO> customerOrderItems = customerOrderItemMapper.selectList(CustomerOrderItemDO::getOrderId, id);
        ErpSaleOutDO saleOut = saleOutService.getSaleOutByCustomerOrderId(id);
        if (CommonUtil.isEmpty(saleOut)) {
            throw exception(CUSTOMER_ORDER_OUT_ERROR);
        }
        List<ErpSaleOutItemDO> saleOutItems = saleOutService.getSaleOutItemListByOutId(saleOut.getId());
        Map<Long, ErpSaleOutItemDO> productMap = CommonUtil.listConvertMap(saleOutItems, ErpSaleOutItemDO::getProductId);

        return CommonUtil.listConvert(customerOrderItems, customerOrderItem -> {
            AppCustomerOrderReceiptRespVO result = new AppCustomerOrderReceiptRespVO();
            result.setProductId(customerOrderItem.getProductId());
            if (productMap.containsKey(customerOrderItem.getProductId())) {
                ErpSaleOutItemDO saleOutItem = productMap.get(customerOrderItem.getProductId());
                result.setSignedQuantity(saleOutItem.getCount());
                result.setRemark(saleOutItem.getRemark());
                result.setRemarkFiles(saleOutItem.getRemarkFiles());
            } else {
                result.setSignedQuantity(customerOrderItem.getOrderItemQuantity());
            }
            return result;
        });
    }

    /**
     * 订单退货
     *
     * @param reqVO
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void orderReturn(AppCustomerReturnOrderReqVO reqVO) {
        Long id = reqVO.getCustomerOrderId();
        CustomerOrderDO customerOrder = getCustomerOrder(id);
        if (CommonUtil.isEmpty(customerOrder)) {
            throw exception(CUSTOMER_ORDER_NOT_EXISTS);
        }
        if (!customerOrder.getOrderStatus().equals(CustomerOrderStatus.SIGN_RECEIPT)) {
            throw exception(CUSTOMER_ORDER_STATUS_ERROR);
        }

        // 修改客户订单状态
        CustomerOrderRecordEvent event = new CustomerOrderRecordEvent();
        event.setOrderStatus(CustomerOrderStatus.RETURN);
        event.setCustomerOrderId(id);
        event.setCopyWriter(null);
        orderRecordApi.recordEvent(event);

        // 添加销售退货单
        List<CustomerOrderItemDO> customerOrderItems = customerOrderItemMapper.selectList(CustomerOrderItemDO::getOrderId, id);
        Map<Long, CustomerOrderItemDO> orderItemMap = CommonUtil.listConvertMap(customerOrderItems, CustomerOrderItemDO::getId);

        ErpSaleReturnSaveReqVO returnSaveReqVO = new ErpSaleReturnSaveReqVO();
        returnSaveReqVO.setReturnTime(LocalDateTime.now());
        returnSaveReqVO.setCustomerId(customerOrder.getCustomerId());
        // 查询对应的销售订单
        ErpSaleOrderDO saleOrderDO = saleOrderService.queryByCustomerOrderId(customerOrder.getId());
        returnSaveReqVO.setOrderId(saleOrderDO.getId());
        returnSaveReqVO.setCustomerOrderId(customerOrder.getId());
        returnSaveReqVO.setRemark(reqVO.getRemark());
        returnSaveReqVO.setFilesUrl(reqVO.getRemarkFiles());
        List<ErpSaleReturnSaveReqVO.Item> items = new ArrayList<>(reqVO.getOrderItems().size());
        for (AppCustomerReturnOrderReqVO.ReturnItems item : reqVO.getOrderItems()) {
            CustomerOrderItemDO customerOrderItemDO = orderItemMap.get(item.getCustomerOrderItemId());
            if (!Objects.equals(customerOrderItemDO.getProductId(), item.getProductId())) {
                throw exception(CUSTOMER_ORDER_RETURN_PRODUCT_ERROR);
            }
            ErpSaleReturnSaveReqVO.Item returnItem = new ErpSaleReturnSaveReqVO.Item();
            ErpSaleOrderItemDO saleOrderItemDO = saleOrderService.queryItemByCustomerOrderItemId(customerOrderItemDO.getId());
            if (customerOrderItemDO.getSignedQuantity() - CommonUtil.getEls(customerOrderItemDO.getReturnsQuantity(), 0)
                    < item.getReturnCount()) {
                throw exception(CUSTOMER_ORDER_RETURN_COUNT_ERROR, customerOrderItemDO.getProductName());
            }
            returnItem.setOrderItemId(saleOrderItemDO.getId());
            returnItem.setCustomerOrderItemId(customerOrderItemDO.getId());
            returnItem.setWarehouseId(customerOrder.getWarehouseAreaId());
            returnItem.setProductId(item.getProductId());
            returnItem.setProductUnit(customerOrderItemDO.getProductInfo().getUnitName());
            returnItem.setProductPrice(customerOrderItemDO.getOrderItemPrice());
            returnItem.setCount(item.getReturnCount());
            returnItem.setRemark(item.getRemark());
            returnItem.setSupplierId(customerOrderItemDO.getSupplierId());
            items.add(returnItem);
        }
        returnSaveReqVO.setItems(items);
        saleReturnService.createSaleReturn(returnSaveReqVO);
    }

    /**
     * 查询订单评价
     *
     * @param id
     * @return
     */
    @Override
    public AppCustomerOrderScoreRespVO queryScore(Long id) {
        CustomerOrderDO customerOrder = getCustomerOrder(id);
        if (CommonUtil.isEmpty(customerOrder)) {
            throw exception(CUSTOMER_ORDER_NOT_EXISTS);
        }
        AppCustomerOrderScoreRespVO result = new AppCustomerOrderScoreRespVO();
        result.setOrderRemark(customerOrder.getOrderRemark());
        List<ScoringWeightDO> scoringWeightDOS = scoringWeightService.queryByUserSystem(UserSystemEnum.CUSTOMER);
        result.setItems(CommonUtil.listConvert(scoringWeightDOS, item -> {
            AppCustomerOrderScoreRespVO.Item resultItem = new AppCustomerOrderScoreRespVO.Item();
            resultItem.setScoreId(item.getId());
            resultItem.setScoreName(item.getScoreName());
            resultItem.setScore(orderScoreService.queryScore(id, item.getId()));
            return resultItem;
        }));
        return result;
    }

    /**
     * 评价订单
     *
     * @param reqVO
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void score(AppCustomerOrderScoreReqVO reqVO) {
        Long id = reqVO.getOrderId();
        CustomerOrderDO customerOrder = getCustomerOrder(id);
        if (CommonUtil.isEmpty(customerOrder)) {
            throw exception(CUSTOMER_ORDER_NOT_EXISTS);
        }
        if (CommonUtil.isNotEmpty(customerOrder.getHasScore()) && customerOrder.getHasScore()) {
            throw exception(CUSTOMER_ORDER_HAS_RECEIPT);
        }
        if (CommonUtil.isNotEmpty(reqVO.getItems())) {
            reqVO.getItems().forEach(item -> {
                if (!orderScoreService.exists(id, item.getScoreId())) {
                    ScoringWeightDO scoringWeight = scoringWeightService.getScoringWeight(item.getScoreId());
                    Set<Long> supplierIds = CommonUtil.listConvertSet(customerOrderItemMapper.selectList(CustomerOrderItemDO::getOrderId, id), CustomerOrderItemDO::getSupplierId);
                    for (Long supplierId : supplierIds) {
                        OrderScoreSaveReqVO saveReqVO = new OrderScoreSaveReqVO();
                        saveReqVO.setOrderId(id);
                        saveReqVO.setScoreId(item.getScoreId());
                        saveReqVO.setScoreName(scoringWeight.getScoreName());
                        saveReqVO.setSupplierId(supplierId);
                        saveReqVO.setCustomerId(customerOrder.getCustomerId());
                        saveReqVO.setScore(item.getScore());
                        saveReqVO.setSort(scoringWeight.getSort());
                        orderScoreService.createScore(saveReqVO);
                    }
                } else {
                    throw exception(SCORE_EXISTS);
                }
            });
        }
        if (CommonUtil.isNotEmpty(reqVO.getOrderRemark())) {
            reqVO.getOrderRemark().setOperTime(new Date());
            customerOrderMapper.update(Wrappers.<CustomerOrderDO>lambdaUpdate()
                    .eq(CustomerOrderDO::getId, id)
                    .set(CustomerOrderDO::getOrderRemark, reqVO.getOrderRemark()));
        }

        CustomerOrderDO updateScore = new CustomerOrderDO();
        updateScore.setId(id);
        updateScore.setHasScore(Boolean.TRUE);
        customerOrderMapper.updateById(updateScore);
    }

    @Override
    public Map<String, Long> queryStatusCount(Long loginUserId) {
        Map<String, Long> result = new HashMap<>();
        List<Map<String, Object>> maps = customerOrderMapper.queryStatusCount(loginUserId);
        Map<String, Long> statusMap = CommonUtil.listConvertMap(maps, key -> String.valueOf(key.get("order_status")),
                value -> Long.valueOf(String.valueOf(value.getOrDefault("status_count", "0"))));
        for (CustomerOrderStatus em : CustomerOrderStatus.values()) {
            result.put(em.getKey(), statusMap.getOrDefault(em.getKey(), 0L));
        }
        return result;
    }

    /**
     * 分页获取月度账单
     *
     * @param reqVO
     * @return
     */
    @Override
    public AppCustomerMonthOrderRespVO reconciliationPageYear(AppCustomerYearOrderPageReqVO reqVO) {
        AppCustomerMonthOrderRespVO respVO = customerOrderMapper.reconciliationPageYearTotal(reqVO.getYear());
        if (CommonUtil.isNotEmpty(respVO)) {
            respVO.setPageResult(customerOrderMapper.reconciliationPageYearPage(reqVO));
        }
        return respVO;
    }

    /**
     * 月订单汇总
     *
     * @param yearMonth
     * @return
     */
    @Override
    public AppCustomerMonthOrderTotalRespVO monthTotal(String yearMonth) {
        return customerOrderMapper.reconciliationMonthTotal(yearMonth);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void reconciliationConfirm(AppCustomerOrderReconciliationReqVO reqVO) {
        reqVO.getIds().forEach(id -> {
            CustomerOrderDO customerOrder = getCustomerOrder(id);
            if (CommonUtil.isEmpty(customerOrder)) {
                throw exception(CUSTOMER_ORDER_NOT_EXISTS);
            }
            if (CustomerOrderStatus.SIGN_RECEIPT.equals(customerOrder.getOrderStatus())) {
                // 订单记录
                CustomerOrderRecordEvent event = new CustomerOrderRecordEvent();
                event.setOrderStatus(CustomerOrderStatus.FINISH);
                event.setCustomerOrderId(id);
                orderRecordApi.recordEvent(event);
            }
        });
    }

    /**
     * 查询退款
     *
     * @param id
     * @return
     */
    @Override
    public AppCustomerOrderReturnRespVO queryReturn(Long id) {
        AppCustomerOrderReturnRespVO result = new AppCustomerOrderReturnRespVO();
        CustomerOrderDO customerOrder = getCustomerOrder(id);
        if (CommonUtil.isEmpty(customerOrder)) {
            throw exception(CUSTOMER_ORDER_NOT_EXISTS);
        }
        if (!customerOrder.getOrderStatus().equals(CustomerOrderStatus.RETURN)) {
            throw exception(CUSTOMER_ORDER_STATUS_ERROR);
        }
        ErpSaleReturnDO saleReturn = saleReturnService.queryByCustomerOrderId(id);
        if (CommonUtil.isEmpty(saleReturn)) {
            return result;
        }
        result.setSaleReturnId(saleReturn.getId());
        result.setTotalReturnPrice(saleReturn.getTotalPrice());
        result.setRemark(saleReturn.getRemark());
        result.setRemarkFiles(saleReturn.getFilesUrl());
        List<ErpSaleReturnItemDO> returnItems = saleReturnService.getSaleReturnItemListByReturnId(saleReturn.getId());
        List<CustomerOrderItemDO> customerOrderItems = customerOrderItemMapper.selectList(CustomerOrderItemDO::getOrderId, id);
        Map<Long, CustomerOrderItemDO> orderItemMap = CommonUtil.listConvertMap(customerOrderItems, CustomerOrderItemDO::getId);
        result.setReturnItems(CommonUtil.listConvert(returnItems, item -> {
            CustomerOrderItemDO customerOrderItemDO = orderItemMap.get(item.getCustomerOrderItemId());
            AppCustomerOrderReturnRespVO.ReturnItems returnItem = new AppCustomerOrderReturnRespVO.ReturnItems();
            returnItem.setProductId(item.getProductId());
            returnItem.setCustomerOrderItemId(customerOrderItemDO.getId());
            returnItem.setProductInfo(customerOrderItemDO.getProductInfo());
            returnItem.setOrderItemPrice(customerOrderItemDO.getOrderItemPrice());
            returnItem.setReturnCount(item.getCount());
            returnItem.setReturnPrice(item.getProductPrice());
            returnItem.setTotalReturnPrice(item.getTotalPrice());
            returnItem.setRemark(item.getRemark());
            return returnItem;
        }));
        return result;
    }

    /**
     * {@link ErpPurchaseOrderServiceImpl#orderSplit(PurchaseOrderSplitEvent)}
     */
    private void orderSplitPurchase(Long customerOrderId) {
        PurchaseOrderSplitEvent event = new PurchaseOrderSplitEvent();
        event.setCustomerOrderId(customerOrderId);
        SpringUtils.getApplicationContext().publishEvent(event);
    }

    private void validCustomerOrder(AppCustomerOrderSaveReqVO createReqVO, Long customerId) {
        if (!warehouseApi.existsById(createReqVO.getWarehouseId())) {
            throw exception(CUSTOMER_ORDER_WAREHOUSE_NOEXISTS);
        }
        if (!warehouseApi.existsById(createReqVO.getWarehouseAreaId())) {
            throw exception(CUSTOMER_ORDER_WAREHOUSE_NOEXISTS);
        }
        if (!customerWarehouseService.exists(createReqVO.getWarehouseAreaId(), customerId)) {
            throw exception(CUSTOMER_WAREHOUSE_NOT_BIND);
        }
        if (!addressService.existsById(createReqVO.getAddressId())) {
            throw exception(CUSTOMER_ORDER_ADDRESS_NOEXISTS);
        }
    }

    @Override
    public CustomerOrderDTO queryById(Long customerOrderId) {
        return BeanUtils.toBean(customerOrderMapper.selectById(customerOrderId), CustomerOrderDTO.class);
    }

    @Override
    public List<CustomerOrderItemDTO> queryItemsByOrderId(Long customerOrderId) {
        return BeanUtils.toBean(customerOrderItemMapper.selectList(CustomerOrderItemDO::getOrderId, customerOrderId),
                CustomerOrderItemDTO.class);
    }

    @Override
    public void updateOrderStatus(Long customerOrderId, CustomerOrderStatus updateOrderStatus) {
        customerOrderMapper.update(Wrappers.<CustomerOrderDO>lambdaUpdate()
                .set(CustomerOrderDO::getOrderStatus, updateOrderStatus)
                .eq(CustomerOrderDO::getId, customerOrderId));
    }
}