<?php
/**
 * 应收单管理模块
 * Created by PhpStorm.
 * User: wxj
 * Date: 2019/10/30
 * Time: 14:02
 */

namespace JinDouYun\Model\Finance;

use JinDouYun\Dao\Finance\DReceived;
use JinDouYun\Dao\Finance\DReceiveOffset;
use JinDouYun\Model\Order\MOrder;
use function FastRoute\TestFixtures\empty_options_cached;
use JinDouYun\Model\MBaseModel;
use Mall\Framework\Core\ErrorCode;
use Mall\Framework\Core\StatusCode;
use Mall\Framework\Core\ResultWrapper;

use JinDouYun\Dao\Finance\DReceive;
use JinDouYun\Dao\Finance\DReceiveReceiptIndex;
use JinDouYun\Model\Finance\MCustomerBalanceDetail;
use JinDouYun\Model\Finance\MCustomerBalance;
use JinDouYun\Cache\FinanceCache;

class MReceive extends MBaseModel
{
    private $objDReceive;
    private $objDReceiveReceiptIndex;
    private $objMCustomerBalanceDetail;
    private $objMCustomerBalance;
    private $objFinanceCache;
    private $objDReceived;
    private $objDReceiveOffset;
    private $enterpriseId;
    private $userCenterId;

    public function __construct($enterpriseId, $userCenterId)
    {
        parent::__construct($enterpriseId, $userCenterId);
        $this->enterpriseId = $enterpriseId;
        $this->userCenterId = $userCenterId;

        $this->objMCustomerBalanceDetail = new MCustomerBalanceDetail($enterpriseId, $userCenterId);
        $this->objMCustomerBalance = new MCustomerBalance($enterpriseId, $userCenterId);
        $this->objDReceive = new DReceive('finance');
        $this->objDReceiveReceiptIndex = new DReceiveReceiptIndex('finance');
        $this->objFinanceCache = new FinanceCache();
        $this->objDReceived = new DReceived('finance');
        $this->objDReceiveOffset = new DReceiveOffset('finance');

        $this->objDReceiveOffset->setTable('qianniao_receive_offset_'. $enterpriseId);

        $this->objDReceive->setTable('qianniao_receive_receipt_' . $enterpriseId . '_' . date('Y') . '_' . ceil(date('m') / 3));
        $this->objDReceiveReceiptIndex->setTable('qianniao_receive_receipt_index_' . $enterpriseId);

        $this->objDReceive->setSearchIndex('should_receive_receipt_search')->setType('should_receive_receipt');
    }

    /**
     * 临时财务脚本解决索引表id重复问题
     */
    public function tmp()
    {
        // 查询应收索引表
        $result = $this->objDReceiveReceiptIndex->select('id > 82');
        if ($result === false) {
            return ResultWrapper::fail($this->objDReceiveReceiptIndex->error(), ErrorCode::$dberror);
        }

        foreach ($result as $key => $value){
            $suffix = date('Y', $value['createTime']) . '_' . ceil(date('m', $value['createTime']) / 3);
            $this->objDReceive->setTable('qianniao_receive_receipt_' . $this->enterpriseId . '_' . $suffix);
            $dbResult = $this->objDReceive->get($value['receiveReceiptId']);
            if ($dbResult === false) {
                return ResultWrapper::fail($this->objDReceive->error(), ErrorCode::$dberror);
            }
            
            // 把应收单id改成索引表的自增id
            $dbResult = $this->objDReceive->update(['id'=>$value['id']], $value['receiveReceiptId']);
            if ($dbResult === false) {
                return ResultWrapper::fail($this->objDReceive->error(), ErrorCode::$dberror);
            }

            // 把索引表应收id改成空
            $result = $this->objDReceiveReceiptIndex->update(['receiveReceiptId'=>0], $value['id']);
            if ($result === false) {
                return ResultWrapper::fail($this->objDReceiveReceiptIndex->error(), ErrorCode::$dberror);
            }

            echo $value['id'].'操作完成'.PHP_EOL;
        }

        return ResultWrapper::success('全部更新完成');
    }

    /**
     * 添加应收单
     *
     * @param array $params 应收单数据
     *
     * @return ResultWrapper
     */
    public function addReceive($params)
    {
        $this->objDReceive->beginTransaction();
        // 生成编号
        $dbResult =  $this->objDReceive->get('createTime >='.strtotime(date('Ymd'.'0:0:0')), 'no', 'createTime desc');
        if ($dbResult === false) {
            return ResultWrapper::fail($this->objDReceive->error(), ErrorCode::$dberror);
        }
        if(empty($dbResult)){
            $params['no'] = createSerialNumberByDate('');
        }else{
            $params['no'] = createSerialNumberByDate($dbResult['no']);
        }

        //索引表数据
        $indexData = [
            'receiveReceiptId' => 0,
            'customerId'       => $params['customerId'],
            'sourceNo'         => $params['sourceNo'],
            'originId'         => $params['originId'],
            'auditStatus'      => $params['auditStatus'],
            'offsetStatus'      =>($params['receiveMoney']<0) ? 5 : 4,
            'financeTypeId'    => $params['financeTypeId'],
            'financeType'      => $params['financeType'],
            'shopId'           => $params['shopId'],
            'createTime'       => $params['createTime'],
            'updateTime'       => $params['updateTime'],

        ];
        $receiveReceiptId = $this->objDReceiveReceiptIndex->insert($indexData);
        if ($receiveReceiptId === false) {
            $this->objDReceive->rollBack();
            return ResultWrapper::fail($this->objDReceiveReceiptIndex->error(), ErrorCode::$dberror);
        }

        //应付单检测重复数据
        $allResult = $this->objDReceive->get(['sourceNo'=>$params['sourceNo'],'receiveMoney'=>$params['receiveMoney']]);
        if( $allResult === false  ){
            return ResultWrapper::fail($this->objDReceive->error(), ErrorCode::$dberror);
        }
        if( !empty($allResult) ){
            return ResultWrapper::fail('应收单已经创建过了',ErrorCode::$notAllowAccess);
        }

        $params['id'] = $receiveReceiptId;
        $ReceiveId = $this->objDReceive->insert($params);
        if ($ReceiveId === false) {
            $this->objDReceive->rollBack();
            return ResultWrapper::fail($this->objDReceive->error(), ErrorCode::$dberror);
        }
        $this->objDReceive->commit();

        /*
        $_id = self::createEsDocumentId($ReceiveId, $params['createTime']);
        $esData = $params;
        $esData['id'] = $ReceiveId;
        $esData['enterpriseId'] = $this->enterpriseId;
        $result = $this->objDReceive->addUpSearchIndexDocument($esData, $_id);
        if (isset($result['_shards']) && isset($result['_shards']['successful']) && $result['_shards']['successful'] == 1) {
            //echo "es操作成功";die;
        }else {
            file_put_contents('/www/wwwroot/logs/api.junhailan.com/elasticsearch.log',date('Y-m-d H:i:s').'生成应收单es错误,错误原因'.var_export($result,true).PHP_EOL,FILE_APPEND);
        }*/
        return ResultWrapper::success($receiveReceiptId);
    }

    /**
     * 生成es的文档id
     * @param $receiveId
     * @param $time
     * @return string
     */
    private function createEsDocumentId($receiveId, $time)
    {
        $t = date('Y', $time) . '_' . ceil(date('m', $time) / 3);
        return 'EnterpriseId_' . $this->enterpriseId . '_' . $t . '_receiveId_' . $receiveId;
    }

    /**
     * 获取应收单数据
     * @param $params
     * @return ResultWrapper
     */
    public function getReceiveInfo($params) {
        $suffix = date('Y', $params['createTime']) . '_' . ceil(date('m', $params['createTime']) / 3);
        $this->objDReceive->setTable('qianniao_receive_receipt_' . $this->enterpriseId . '_' . $suffix);
        $dbResult = $this->objDReceive->get($params['id']);
        if ($dbResult === false) {
            return ResultWrapper::fail($this->objDReceive->error(), ErrorCode::$dberror);
        }
        if(!empty($dbResult)){
            $dbResult['no'] = StatusCode::$noPrefix[16] . '-' . $dbResult['no'];
            $dbResult['sourceNo'] = StatusCode::$noPrefix[1] .'-'.$dbResult['sourceNo'];

            $dbResult['customerCode'] = createCode(StatusCode::$code['customer']['prefix'], $dbResult['customerId'], StatusCode::$code['customer']['length']);
        }
        return ResultWrapper::success($dbResult);

    }

    /**
     * 更新应收单核销状态
     * @param $id
     * @param $offsetMoney
     * @param $createTime
     * @return ResultWrapper
     */
    public function updateOffsetStatus($id,$offsetMoney,$createTime)
    {
        $suffix = date('Y', $createTime) . '_' . ceil(date('m', $createTime) / 3);
        $this->objDReceive->setTable('qianniao_receive_receipt_' . $this->enterpriseId . '_' . $suffix);
        $shouldReceiveData = $this->objDReceive->get($id);
        if ($shouldReceiveData === false) {
            $this->objDReceive->rollBack();
            return ResultWrapper::fail($this->objDReceive->error(), ErrorCode::$dberror);
        }
        if( empty($shouldReceiveData) ){
            return ResultWrapper::fail('要审核的单据不存在', ErrorCode::$contentNotExists);
        }
//        $notOffsetMoney = bcsub($shouldReceiveData['receiveMoney'], $offsetMoney, 4);
        //判断该单据是否
        $updateData = [
            'offsetMoney'    => bcadd(abs($offsetMoney), abs($shouldReceiveData['offsetMoney']),4),
            'notOffsetMoney' => bcsub($shouldReceiveData['notOffsetMoney'], abs($offsetMoney),4),
            'offsetStatus'  => StatusCode::$delete
        ];
        switch (true)
        {
            case $updateData['notOffsetMoney'] == 0;
                $updateData['offsetStatus'] = StatusCode::$standard;
                break;
            case $updateData['notOffsetMoney'] == $shouldReceiveData['receiveMoney'];
                $updateData['offsetStatus'] = StatusCode::$delete;
                break;
            case $updateData['notOffsetMoney'] > 0 && $updateData['notOffsetMoney'] < $shouldReceiveData['receiveMoney'];
                $updateData['offsetStatus'] = StatusCode::$partion;
                break;
        }
        $beginTransactionStatus = $this->objDReceive->beginTransaction();
        unset($dbResult);
        $dbResult = $this->objDReceive->update($updateData, $id);
        if ($dbResult === false) {
            $this->objDReceive->rollBack();
            return ResultWrapper::fail($this->objDReceive->error(), ErrorCode::$dberror);
        }

        //修改索引表状态
        unset($dbResult);
        $dbResult = $this->objDReceiveReceiptIndex->update(['offsetStatus' => $updateData['offsetStatus']], $id);
        if ($dbResult === false) {
            $this->objDReceive->rollBack();
            return ResultWrapper::fail($this->objDReceiveReceiptIndex->error(), ErrorCode::$dberror);
        }
        if($beginTransactionStatus){
            $this->objDReceive->commit();
        }

        return ResultWrapper::success($dbResult);
    }

    /**
     * 应收单审核
     * @param array $params
     * @return ResultWrapper
     * @throws \Exception
     */
    public function updateReceiveStatus($params)
    {
        // 根据创建时间切表
        $suffix = date('Y', $params['createTime']) . '_' . ceil(date('m', $params['createTime']) / 3);
        $this->objDReceive->setTable('qianniao_receive_receipt_' . $this->enterpriseId . '_' . $suffix);

        // 判断是否已审核
        $shouldReceiveData = $this->objDReceive->get($params['id']);
        if( $shouldReceiveData === false ){
            return ResultWrapper::fail($this->objDReceive->error(), ErrorCode::$dberror);
        }
        if(empty($shouldReceiveData)){
            return ResultWrapper::fail('要审核的单据不存在', ErrorCode::$contentNotExists);
        }
        if ($shouldReceiveData['auditStatus'] == StatusCode::$auditStatus['auditPass']) {
            return ResultWrapper::fail('单据已审核', ErrorCode::$actionIsDo);
        }

        $beginTransactionStatus = $this->objDReceive->beginTransaction();

        // 修改应收单审核状态
        $dbResult = $this->objDReceive->update(['auditStatus' => StatusCode::$auditStatus['auditPass']], $params['id']);
        if ($dbResult === false) {
            $this->objDReceive->rollBack();
            return ResultWrapper::fail($this->objDReceive->error(), ErrorCode::$dberror);
        }

        // 修改应收单索引表审核状态
        $dbResult = $this->objDReceiveReceiptIndex->update(['auditStatus' => StatusCode::$auditStatus['auditPass']], ['id' => $params['id']]);
        if ($dbResult === false) {
            $this->objDReceive->rollBack();
            return ResultWrapper::fail($this->objDReceiveReceiptIndex->error(), ErrorCode::$dberror);
        }

        // 获取客户余额
        $customerBalance = $this->objMCustomerBalance->getCustomerBalance($shouldReceiveData['customerId']);

        // 自动核销
        $autoOffset = self::autoOffset($customerBalance,$params['id'],$params['createTime']);
        if (!$autoOffset->isSuccess()) {
            $this->objDReceive->rollBack();
            return ResultWrapper::fail($autoOffset->getData(), $autoOffset->getErrorCode());
        }
        $detailData = [
            'customerId'             => $shouldReceiveData['customerId'],//'客户id',
            'receiptTime'            => $shouldReceiveData['createTime'],//'单据日期',
            'sourceId'               => $shouldReceiveData['id'],//'单据编号',
            'sourceNo'               => $shouldReceiveData['no'],//'单据编号',
            'financeType'            => $shouldReceiveData['financeType'],//'财务类型名称',
            'financeTypeId'          => $shouldReceiveData['financeTypeId'],//'财务类型id',
            'originId'               => $shouldReceiveData['originId'],  // 订单id
            'originNo'               => $shouldReceiveData['sourceNo'], // 订单编号
            'salesAmount'            => bcadd($shouldReceiveData['receiveMoney'], $shouldReceiveData['discountMoney'], 4),//TODO:
            'discountMoney'          => $shouldReceiveData['discountMoney'],// '优惠金额',
            'customerAmount'         => $shouldReceiveData['receiveMoney'],// '客户承担金额',
            'receivableAmount'       => $shouldReceiveData['receiveMoney'],// '应收金额',
            'actualReceivableAmount' => 0.00,//'实际收款金额',
            'receivableBalance'      => $customerBalance + $shouldReceiveData['receiveMoney'],//'应收款余额',
            'remark'                 => '应收单审核通过,本单据应收'.$shouldReceiveData['receiveMoney'].'元',//'备注',
            'createTime'             => time(),//'创建日期',
            'updateTime'             => time(),//'修改日期',
        ];

        //添加客户余额明细
        $result = $this->objMCustomerBalanceDetail->addCustomerBalanceDetail($detailData);
        if ($result->isSuccess() === false) {
            $this->objDReceive->rollBack();
            return ResultWrapper::fail($result->getData(), $result->getErrorCode());
        }

        //编辑客户余额
        $result = $this->objMCustomerBalance->addCustomerBalance($shouldReceiveData['customerId'], $shouldReceiveData['receiveMoney']);
        if ($result->isSuccess() === false) {
            $this->objDReceive->rollBack();
            return ResultWrapper::fail($result->getData(), $result->getErrorCode());
        }
        // 判断该单据是否有已生成的应付单(根据orderId查找并且付款金额大于零)
//        if ($shouldReceiveData['receiveMoney']<0 && $shouldReceiveData['offsetMoney'] == 0){
//            $whereSql = ' WHERE orderId = ' . $shouldReceiveData['orderId'] . ' AND receiveMoney > 0';
//            $sql = 'SELECT * FROM ' .$this->objDReceive->get_Table().$whereSql;
//            $repeatReceiveData = $this->objDReceive->query($sql);
//            if ($repeatReceiveData === false) {
//                return ResultWrapper::fail('退款应付单不存在', ErrorCode::$dberror);
//            }
//            if(!empty($repeatReceiveData)){
//                foreach ($repeatReceiveData as $key =>$value){
//                    $value['notOffsetMoney'] = bcadd($value['notOffsetMoney'], $shouldReceiveData['receiveMoney'],4);
//                    $value['offsetMoney'] = abs($shouldReceiveData['receiveMoney']);
//                    //更新源应付单核销金额,未核销金额
//                    $updateDate = $this->objDReceive->update(['notOffsetMoney'=>$value['notOffsetMoney'],'offsetMoney'=>$value['offsetMoney']],['id'=>$value['id']]);
//                    if ($updateDate === false) {
//                        $this->objDReceive->rollBack();
//                        return ResultWrapper::fail($this->objDReceive->error(), ErrorCode::$dberror);
//                    }
//                }
//            }
//        }
        if ($beginTransactionStatus){
            $this->objDReceive->commit();
        }

        //修改订单支付状态
        $objMOrder = new MOrder($this->userCenterId, $this->enterpriseId);

        $offsetDbResult = $this->objDReceiveOffset->select(['receiveReceiptId'=>$params['id'],'type'=>StatusCode::$delete]);
        if ($offsetDbResult === false) {
            return ResultWrapper::fail($this->objDReceiveOffset->error(), ErrorCode::$dberror);
        }
        if(!empty($offsetDbResult)){
            foreach ($offsetDbResult as $offsetDbResultKey => $offsetDbResultValue){
                $orderIdDbResult = $this->objDReceive->get(['id' => $offsetDbResult[$offsetDbResultKey]['receiveReceiptId']]);
                if ($orderIdDbResult === false) {
                    return ResultWrapper::fail($this->objDReceive->error(), ErrorCode::$dberror);
                }
                if (empty($orderIdDbResult)) {
                    return ResultWrapper::fail('应付单不存在', ErrorCode::$notAllowAccess);
                }
                //判断核销金额,未核销金额,来计算payStatus的状态
                $updateOrderPayData1 = ['payStatus' => StatusCode::$standard, 'payTime' => time()];
                $updateOrderPayData2 = ['id' => $orderIdDbResult['originId']];
                switch (true) {
                    case $orderIdDbResult['offsetMoney'] == $orderIdDbResult['receiveMoney'];
                        $updateOrderPayData1['payStatus'] = StatusCode::$standard;
                        break;
                    case $orderIdDbResult['offsetMoney'] == 0;
                        $updateOrderPayData1['payStatus'] = StatusCode::$delete;
                        break;
                    case $orderIdDbResult['offsetMoney'] > 0 && $orderIdDbResult['offsetMoney'] < $orderIdDbResult['receiveMoney'];
                        $updateOrderPayData1['payStatus'] = StatusCode::$partion;
                        $updateOrderPayData1['notPayMoney'] = $orderIdDbResult['notOffsetMoney'];
                }
                $orderDbResult = $objMOrder->updateOrderPayData($updateOrderPayData1, $updateOrderPayData2);
                if ($orderDbResult->isSuccess() === false) {
                    return ResultWrapper::fail($orderDbResult->getData(), $orderDbResult->getErrorCode());
                }
            }
        }

        //更新es的审核状态

        //$_id = self::createEsDocumentId($params['id'], $params['createTime']);
        //$this->objDReceive->esupdateTypeFieldVaule(['auditStatus'=>StatusCode::$auditStatus['auditPass']], $_id);

        /*
        $_id = self::createEsDocumentId($params['id'], $params['createTime']);
        $this->objDReceive->esupdateTypeFieldVaule(['auditStatus'=>StatusCode::$auditStatus['auditPass']], $_id);*/

        $this->objFinanceCache->delSalesOutReceive($this->enterpriseId, $params['id']);
        return ResultWrapper::success($dbResult);

    }

    /**
     * 获取所有应收单数据
     * @param array $selectParams 过滤条件
     * @return ResultWrapper
     * @throws \Exception
     */
    public function getAllReceive($selectParams, $isExport = false)
    {
       
        $limit = $selectParams['limit'];
        $offset = $selectParams['offset'];
        unset($selectParams['limit']);
        unset($selectParams['offset']);
        if($isExport){
            $limit = 9999;
            $offset = 0;
        }
        $whereSql = '';
        if (isset($selectParams['customerId']) && !empty($selectParams['customerId'])) {
            $where = empty($whereSql) ? ' WHERE ' : ' AND ';
            $whereSql .= $where . ' customerId = ' . $selectParams['customerId'];
        }
        if (isset($selectParams['offsetStatus']) && !empty($selectParams['offsetStatus'])) {
            // 数组转字符串
            $selectParams['offsetStatus'] = implode(',',$selectParams['offsetStatus']);
            $where = empty($whereSql) ? ' WHERE ' : ' AND ';
            $whereSql .= $where . ' offsetStatus in( ' . $selectParams['offsetStatus'].')';
        }
        if (isset($selectParams['receiveReceiptIds']) && !empty($selectParams['receiveReceiptIds'])) {
            $where = empty($whereSql) ? ' WHERE ' : ' AND ';
            $whereSql .= $where . ' receiveReceiptId in (' . implode(',', $selectParams['receiveReceiptIds']).')';
        }
        if (isset($selectParams['auditStatus']) && !empty($selectParams['auditStatus'])) {
            $where = empty($whereSql) ? ' WHERE ' : ' AND ';
            $whereSql .= $where . ' auditStatus = ' . $selectParams['auditStatus'];
        }
        if (isset($selectParams['shopId']) && !empty($selectParams['shopId'])) {
            $where = empty($whereSql) ? ' WHERE ' : ' AND ';
            $whereSql .= $where . ' shopId = ' . $selectParams['shopId'];
        }
        if ( (isset($selectParams['start']) && !empty($selectParams['start']))&&(isset($selectParams['end']) && !empty($selectParams['end'])) ) {
            $where = empty($whereSql) ? ' WHERE ' : '  AND ';
            $whereSql .= $where . ' createTime BETWEEN ' . $selectParams['start'] . ' AND '. $selectParams['end'];
        }

        $sql = 'SELECT * FROM ' .$this->objDReceiveReceiptIndex->get_Table().$whereSql . ' ORDER BY createTime DESC LIMIT ' . $offset . ' , ' . $limit;
        $receiveReceiptIndexResult = $this->objDReceiveReceiptIndex->query($sql);
        if ($receiveReceiptIndexResult === false) {
            return ResultWrapper::fail($this->objDReceiveReceiptIndex->error(), ErrorCode::$dberror);
        }

        $tableSuffix = [];
        foreach ($receiveReceiptIndexResult as $receiveReceiptIndex) {
            $k = date('Y', $receiveReceiptIndex['createTime']) . '_' . ceil(date('m', $receiveReceiptIndex['createTime']) / 3);
            $tableSuffix[$k][] = $receiveReceiptIndex['id'];
        }

        $receiveReceiptResult = [];
        foreach ($tableSuffix as $suffix => $receiveReceiptIds) {
            $this->objDReceive->setTable('qianniao_receive_receipt_' . $this->enterpriseId . '_' . $suffix);
          
            if($isExport){
                $dbResult = $this->objDReceive->exportSelect($receiveReceiptIds, '*', 'createTime desc');
                $tmpArray = [];
                foreach($dbResult as $key => $value){
                    $tmpArray[] = $value;
                }
                $dbResult = $tmpArray;
            }else{
                $dbResult = $this->objDReceive->select($receiveReceiptIds, '*', 'createTime desc');
                
            }

            if ($dbResult === false) {
                return ResultWrapper::fail($this->objDReceive->error(), ErrorCode::$dberror);
            }

            if(!empty($dbResult)){
                $receiveReceiptResult = array_merge($receiveReceiptResult, self::format($dbResult));
            }
        }
    
        
        $totalSql = 'SELECT COUNT(1) as count FROM ' .$this->objDReceiveReceiptIndex->get_Table() . $whereSql;
        $dbTotalResult = $this->objDReceive->query($totalSql);
        $return = [
            'data'  => $receiveReceiptResult,
            'total' => ($dbTotalResult[0]['count']) ? intval($dbTotalResult[0]['count']) : 0,
        ];
        if($isExport){
            self::export($return['data']);
        }
        return ResultWrapper::success($return);
    }



    /**
     * 审核成功调用(预充余额)
     * @param array $params
     * @return ResultWrapper
     * @throws \Exception
     */
    public function autoOffset($customerBalance, $receiveId, $createTime)
    {
        // 切换应收单表
        $suffix = date('Y', $createTime) . '_' . ceil(date('m', $createTime) / 3);
        $this->objDReceive->setTable('qianniao_receive_receipt_' . $this->enterpriseId . '_' . $suffix);

        // 获取应收单数据
        $shouldReceiveData = $this->objDReceive->get($receiveId);
        if ($shouldReceiveData === false) {
            return ResultWrapper::fail($this->objDReceive->error(), ErrorCode::$dberror);
        }
        if (empty($shouldReceiveData)) {
            return ResultWrapper::fail('应收单id'.$receiveId.'数据为空', ErrorCode::$dberror);
        }

        // 查询这笔应收对应的订单是否有收款记录
        $this->objDReceived->setTable('qianniao_received_' . $this->enterpriseId . '_' . date('Y', $createTime) . '_' . ceil(date('m', $createTime) / 3));
        $receivedDbResult = $this->objDReceived->query('select * from '.$this->objDReceived->get_Table().' where sourceId ='.$shouldReceiveData['originId'].' and sourceId !=0 limit 1');
        if ($receivedDbResult === false) {
            $this->objDReceive->rollBack();
            return ResultWrapper::fail($this->objDReceived->error(), ErrorCode::$dberror);
        }
        if (!empty($receivedDbResult)){ //说明该应收是在线支付 现货后款
            $receiveOffsetMoney = $shouldReceiveData['receiveMoney'];
            foreach ($receivedDbResult as $receivedKey => $receivedValue){
                switch (true){
                    case bcsub($receiveOffsetMoney,$receivedValue['totalFinalMoney'],2) == 0; // 应收金额 = 收款金额
                        $receiveOffsetDate = [
                            'offsetMoney'       =>$receiveOffsetMoney,
                            'notOffsetMoney'    =>0,
                            'offsetStatus'      =>StatusCode::$standard
                        ];
                        $receiveIndexOffsetDate = [
                            'offsetStatus' => StatusCode::$standard
                        ];
                        $receivedOffsetDate = [
                            'offsetMoney'       =>$receiveOffsetMoney,
                            'notOffsetMoney'    =>0,
                            'offsetStatus'      =>StatusCode::$standard
                        ];
                        break;
                    case bcsub($receiveOffsetMoney,$receivedValue['totalFinalMoney'],2) > 0; // 应收金额 > 收款金额
                        $receiveOffsetDate = [
                            'offsetMoney'       =>$receivedValue['totalFinalMoney'],
                            'notOffsetMoney'    =>bcsub($receiveOffsetMoney,$receivedValue['totalFinalMoney'],2),
                            'offsetStatus'      =>StatusCode::$partion
                        ];
                        $receiveIndexOffsetDate = [
                            'offsetStatus' => StatusCode::$partion
                        ];
                        $receivedOffsetDate = [
                            'offsetMoney'       =>$receivedValue['totalFinalMoney'],
                            'notOffsetMoney'    =>0,
                            'offsetStatus'      =>StatusCode::$standard
                        ];
                        break;
                    case bcsub($receiveOffsetMoney,$receivedValue['totalFinalMoney'],2) < 0; // 应收金额 < 收款金额
                        $receiveOffsetDate = [
                            'offsetMoney'       =>$receiveOffsetMoney,
                            'notOffsetMoney'    =>0,
                            'offsetStatus'      =>StatusCode::$standard
                        ];
                        $receiveIndexOffsetDate = [
                            'offsetStatus' => StatusCode::$standard
                        ];
                        $receivedOffsetDate = [
                            'offsetMoney'       =>$receiveOffsetMoney,
                            'notOffsetMoney'    =>bcsub($receivedValue['totalFinalMoney'],$receiveOffsetMoney,2),
                            'offsetStatus'      =>StatusCode::$partion
                        ];
                }
                $updateOffsetStatus = $this->objDReceive->update($receiveOffsetDate,['id'=>$receiveId]);
                if ($updateOffsetStatus === false) {
                    $this->objDReceive->rollBack();
                    return ResultWrapper::fail($this->objDReceive->error(), ErrorCode::$dberror);
                }

                $dbResult = $this->objDReceiveReceiptIndex->update($receiveIndexOffsetDate, ['id' => $receiveId,'createTime'=>$createTime]);
                if ($dbResult === false) {
                    $this->objDReceive->rollBack();
                    return ResultWrapper::fail($this->objDReceiveReceiptIndex->error(), ErrorCode::$dberror);
                }
                //在线支付的收款单直接核销
                $updateReceivedOffset = $this->objDReceived->update($receivedOffsetDate,['id'=>$receivedValue['id']]);
                if ($updateReceivedOffset === false) {
                    $this->objDReceive->rollBack();
                    return ResultWrapper::fail($this->objDReceived->error(), ErrorCode::$dberror);
                }
                // 记录核销明细
                //核销完成,记录核销明细
                $updateOffset = [
                    'receiveReceiptId' => $receiveId,
                    'receivedId' => $receivedValue['id'],
                    'offsetMoney' => $receiveOffsetDate['offsetMoney'],
                    'receiveCreateTime' => $shouldReceiveData['createTime'],
                    'type'  => StatusCode::$delete
                ];
                $result = $this->objDReceiveOffset->insert($updateOffset);
                if ($result === false) {
                    $this->objDReceived->rollBack();
                    return ResultWrapper::fail($this->objDReceiveOffset->error(), ErrorCode::$dberror);
                }
            }
        }else{
            $offsetMoney = 0;
            $notOffsetMoney = 0;
            $offsetStatus = 5;
            if ($customerBalance < 0 && $shouldReceiveData['receiveMoney'] > 0){//说明客户是预收款进行自动核销
                switch (true)
                {
                    case bcsub(abs($customerBalance),$shouldReceiveData['receiveMoney'],4) > 0;//说明预收款完全核销应收单金额
                        $offsetMoney = $shouldReceiveData['receiveMoney'];
                        break;
                    case bcsub(abs($customerBalance),$shouldReceiveData['receiveMoney'],4) == 0;//说明预收款刚好完全核销
                        $offsetMoney = $shouldReceiveData['receiveMoney'];
                        break;
                    case bcsub(abs($customerBalance),$shouldReceiveData['receiveMoney'],4) < 0;//说明预收款不够核销应收单金额
                        $offsetMoney = abs($customerBalance);
                        $notOffsetMoney = bcadd($customerBalance,$shouldReceiveData['receiveMoney'],4);
                        $offsetStatus = StatusCode::$partion;
                }
                //更新应付单核销状态
                $updateOffsetStatus = $this->objDReceive->update(['offsetMoney'=>$offsetMoney,'notOffsetMoney'=>$notOffsetMoney,'offsetStatus'=>$offsetStatus],['id'=>$receiveId]);
                if ($updateOffsetStatus === false) {
                    $this->objDReceive->rollBack();
                    return ResultWrapper::fail($this->objDReceive->error(), ErrorCode::$dberror);
                }
                //更新应付单索引表核销状态
                unset($dbResult);
                $dbResult = $this->objDReceiveReceiptIndex->update(['offsetStatus' => $offsetStatus], ['id' => $receiveId,'createTime'=>$createTime]);
                if ($dbResult === false) {
                    $this->objDReceive->rollBack();
                    return ResultWrapper::fail($this->objDReceiveReceiptIndex->error(), ErrorCode::$dberror);
                }
                unset($dbResult);
                // 查询收款单,根据收款单找能核销的
//                $dbResult =  $this->objDReceived->select(['offsetStatus'!=StatusCode::$standard],'*','createTime asc');
                $dbResult =  $this->objDReceived->query('select * from '.$this->objDReceived->get_Table().' where customerId = '.$shouldReceiveData['customerId'].' and offsetStatus !='.StatusCode::$standard.' order by createTime asc');
                if ($dbResult === false) {
                    return ResultWrapper::fail($this->objDReceived->error(), ErrorCode::$dberror);
                }
                $receiveOffsetMoney = $shouldReceiveData['receiveMoney'];
                foreach ($dbResult as $key => $value){
                    if($receiveOffsetMoney>0){
                        switch (true){
                            case bcsub($value['notOffsetMoney'],$shouldReceiveData['receiveMoney'],2)>0: // 说明收款单能完全核销应收
                                $receivedOffset = [
                                    'offsetMoney' => bcadd($receiveOffsetMoney,$value['offsetMoney'],2),
                                    'notOffsetMoney' => bcsub($value['notOffsetMoney'],$receiveOffsetMoney,2),
                                    'offsetStatus' => StatusCode::$partion,
                                ];
                                $receiveOffsetMoney = abs(bcsub($receiveOffsetMoney,$receivedOffset['offsetMoney'],2));
                                break;
                            case bcsub($value['notOffsetMoney'],$shouldReceiveData['receiveMoney'],2) == 0: // 说明收款单能完全核销应收
                                $receivedOffset = [
                                    'offsetMoney' => $value['totalFinalMoney'],
                                    'notOffsetMoney' => 0,
                                    'offsetStatus' => StatusCode::$standard,
                                ];
                                $receiveOffsetMoney = abs(bcsub($value['totalFinalMoney'],$receivedOffset['offsetMoney'],2));
                                break;
                            case bcsub($value['notOffsetMoney'],$shouldReceiveData['receiveMoney'],2) < 0: // 说明收款单不能完全核销应收
                                $receivedOffset = [
                                    'offsetMoney' => $value['totalFinalMoney'],
                                    'notOffsetMoney' => 0,
                                    'offsetStatus' => StatusCode::$standard,
                                ];
                                $receiveOffsetMoney = abs(bcsub($value['totalFinalMoney'],$receivedOffset['offsetMoney'],2));
                        }
                        // 更新核销
                        $updateReceivedOffset = $this->objDReceived->update($receivedOffset,['id'=>$value['id']]);
                        if ($updateReceivedOffset === false) {
                            $this->objDReceive->rollBack();
                            return ResultWrapper::fail($this->objDReceived->error(), ErrorCode::$dberror);
                        }
                        //记录核销明细
                        $updateOffset = [
                            'receiveReceiptId' => $receiveId,
                            'receivedId' => $value['id'],
                            'offsetMoney' => $offsetMoney,
                            'receiveCreateTime' => $shouldReceiveData['createTime'],
                            'type'  => StatusCode::$delete
                        ];
                        $result = $this->objDReceiveOffset->insert($updateOffset);
                        if ($result === false) {
                            $this->objDReceived->rollBack();
                            return ResultWrapper::fail($this->objDReceiveOffset->error(), ErrorCode::$dberror);
                        }
                    }
                }

                return ResultWrapper::success($dbResult);

            }
        }
        return ResultWrapper::success([]);
    }

    /**
     * 导出方法
     * @param $exportData
     */
    private static function export($exportData)
    {
        //导出到本地
        header("Content-type:application/vnd.ms-excel");
        header("Content-Disposition:filename=应收单列表.csv");
        header('Cache-Control: max-age=0');
        $fp = fopen('php://output', 'a');
        $head = ['ID', '应收单编号', '客户名称', '源订单号', '创建时间', '应收类型', '优惠金额', '实际应收金额', '商铺', '状态'];       //定义标题
        foreach ($head as $i => $v) {
            $head[$i] = mb_convert_encoding($v, 'GBK', 'utf-8');     //将中文标题转换编码,否则乱码
        }
        fputcsv($fp, $head);
        $limit = 10000;
        $num = 0;//计数器
        foreach ($exportData as $v) {
            //循环数据
            $num++;
            if ($num == $limit) {
                ob_flush();//释放内存
                flush();
            }
            $rows['id'] = $v['id'];
            $rows['no'] = $v['no'];
            $rows['customerName'] = $v['customerName'];
            $rows['sourceNo'] = $v['sourceNo'];
            $rows['createTime'] = date('Y-m-d H:i:s', $v['createTime']);
            $rows['financeType'] = $v['financeType'];
            $rows['discountMoney'] = $v['discountMoney'];
            $rows['receiveMoney'] = $v['receiveMoney'];
            $rows['shopName'] = $v['shopName'];
            $rows['auditStatus'] = StatusCode::$auditStatus[$v['auditStatus']];

            foreach ($rows as $kk => $vv) {
                $rs[$kk] = mb_convert_encoding($vv, 'GBK', 'utf-8');  //转译编码
            }
            fputcsv($fp, $rs);
            $rows = [];
        }
        exit;
    }

    /**
     * @param $data
     * @return mixed
     */
    public function format($data)
    {
        foreach ($data as $k => $v) {
            $data[$k]['customerCode'] = createCode(StatusCode::$code['customer']['prefix'], $v['customerId'], StatusCode::$code['customer']['length']);
            $data[$k]['no'] = StatusCode::$noPrefix[16] . '-' . $v['no'];

            switch ($v['financeType']){
                case '销售退货单':
                    $data[$k]['originNo'] = StatusCode::$noPrefix[6].'-'.$v['originNo'];
                    break;
                case '销售单':
                    $data[$k]['originNo'] = StatusCode::$noPrefix[1].'-'.$v['originNo'];
                    break;
            }
        }
        return $data;
    }

    //搜索的where条件拼接
    public function setWhere($selectParams)
    {
        $defaultDSL = [
            'from' => $selectParams['offset'],
            'size' => $selectParams['limit'],
            'sort' => [
                'createTime' => [
                    'order' => 'desc'
                ],
            ],
        ];

        $dsl = [];
        $dsl['query']['bool']['must'][] = [
            'term' => ['enterpriseId' => $this->enterpriseId],
        ];

        if (isset($selectParams['keyword'])) {
            if (!empty($selectParams['keyword'])) {
                $dsl['query']['bool']['must'][] = [
                    'multi_match' => [
                        'fields'    => ['no', 'sourceNo', 'customerName'],
                        'query'     => $selectParams['keyword'],
                        'fuzziness' => 'AUTO',
                    ]
                ];
            }
        }

        if (!empty($selectParams['shopId'])) {
            $dsl['query']['bool']['must'][] = [
                'term' => ['shopId' => $selectParams['shopId']],
            ];
        }

        if (!empty($selectParams['start']) && !empty($selectParams['end'])) {
            $dsl['query']['bool']['must'][] = [
                'range' => [
                    'createTime' => [
                        'gte' => $selectParams['start'],
                        'lte' => strtotime(date('Y-m-d',$selectParams['end']).'23:59:59'),
                    ]
                ]
            ];
        } else {
            if (!empty($selectParams['start'])) {
                $dsl['query']['bool']['must'][] = [
                    'range' => [
                        'createTime' => [
                            'gte' => $selectParams['start'],
                        ]
                    ]
                ];
            }

            if (!empty($selectParams['end'])) {
                $dsl['query']['bool']['must'][] = [
                    'range' => [
                        'createTime' => [
                            'lte' => strtotime(date('Y-m-d',$selectParams['end']).'23:59:59'),
                        ]
                    ]
                ];
            }
        }

        if (isset($selectParams['receiptTypeId'])) {
            if (!empty($selectParams['receiptTypeId'])) {
                $dsl['query']['bool']['filter'][] =
                    ['term' => ['receiptTypeId' => $selectParams['receiptTypeId']]];
            }
        }

        if (isset($selectParams['auditStatus'])) {
            if (!empty($selectParams['auditStatus'])) {
                $dsl['query']['bool']['filter'][] =
                    ['term' => ['auditStatus' => $selectParams['auditStatus']]];
            }
        }

        $dsl = array_merge($defaultDSL, $dsl);
        return $dsl;
    }

    public function search($selectParams)
    {
        $is_export = $selectParams['isExport'];
        unset($selectParams['isExport']);

        if($is_export){
            unset($selectParams['limit']);
            unset($selectParams['offset']);
        }

        $dsl = $this->setWhere($selectParams);

        //导出
        if ($is_export) self::exportSearch($dsl);


        $result = $this->objDReceive->getSearchQueryDsl($dsl);

        if (isset($result['status']) && $result['status'] == 400) {
            if ($result['error']['reason'] == 'all shards failed') {
                return ResultWrapper::success([
                    'data'  => [],
                    'total' => 0
                ]);
            }
            return ResultWrapper::fail('获取应收数据失败' . $result['error']['reason'], ErrorCode::$apiNotResult);
        }

        if (!isset($result['hits']) || $result['hits']['total'] == 0) {
            return ResultWrapper::success([
                'data'  => [],
                'total' => 0
            ]);
        }
        $total = $result['hits']['total'];
        $dbResult = $result['hits']['hits'];

        $list = [];
        foreach ($dbResult as $key => &$value) {
            $data = [];
            $data = $value['_source'];
            $list[] = $data;
        }

        $return = [
            'data'  => self::format($list),
            'total' => ($total) ? intval($total) : 0,
        ];
        return ResultWrapper::success($return);
    }

    /**
     * 检索导出(ES)
     *
     * @param $dsl
     * @return ResultWrapper
     * @throws \Exception
     */
    private function exportSearch($dsl)
    {
        $result = $this->objDReceive->getScrollSearchQueryDsl($dsl);
        if (isset($result['status']) && $result['status'] == 400) {
            return ResultWrapper::fail('获取数据失败' . $result['error']['reason'], ErrorCode::$apiNotResult);
        }

        if (!isset($result['hits']) && $result['hits']['total'] == 0) {
            return ResultWrapper::fail('导出数据为空' . $result['error']['reason'], ErrorCode::$apiNotResult);
        }
        $dbResult = $result['hits']['hits'];

        $list = [];
        foreach ($dbResult as $key => &$value) {
            $list[] = $value['_source'];
        }
        self::export($list);
    }
}