<?php
/**
 * 盘点库存管理Model
 * Created by PhpStorm.
 * User: 小威
 * Date: 2019/12/04
 * Time: 12:00
 */

namespace JinDouYun\Model\Stock;

use Exception;
use Mall\Framework\Core\ErrorCode;
use Mall\Framework\Core\StatusCode;
use Mall\Framework\Core\ResultWrapper;

use JinDouYun\Cache\InventoryCache;

use JinDouYun\Dao\Stock\DStocktaking;
use JinDouYun\Dao\Stock\DStocktakingDetails;
use JinDouYun\Dao\Stock\DInventory;
use JinDouYun\Dao\Stock\DInventoryDetails;

use JinDouYun\Model\MBaseModel;
use JinDouYun\Model\GoodsManage\MSku;
use JinDouYun\Model\Stock\MInventory;
use JinDouYun\Model\Common\MCommon;



class MStocktaking extends MBaseModel
{

    private $objDStocktaking;
    private $objDStocktakingDetails;
    private $enterpriseId;
    private $userCenterId;


    public function __construct($enterpriseId, $userCenterId)
    {
        $this->userCenterId = $userCenterId;
        $this->enterpriseId = $enterpriseId;
        $this->objDStocktaking = new DStocktaking('stock');
        $this->objDStocktakingDetails = new DStocktakingDetails('stock');
        $this->objDStocktaking->setTable($this->objDStocktaking->get_Table() . '_' . $enterpriseId);
        $this->objDStocktakingDetails->setTable($this->objDStocktakingDetails->get_Table() . '_' . $enterpriseId);
        $this->objDStocktaking->setSearchIndex('stocktaking_search')->setType('stocktaking');
    }

    /**
     * 盘点库存添加
     * @param $params
     * @return ResultWrapper
     */
    public function addStocktaking($params)
    {
        $details = $params['details'];
        unset($params['details']);
        unset($params['deleteArray']);

        $beginStatus = $this->objDStocktaking->beginTransaction();
        // 生成编号
        $dbResult =  $this->objDStocktaking->get('createTime >='.strtotime(date('Ymd'.'0:0:0')), 'no', 'createTime desc');
        if ($dbResult === false) {
            return ResultWrapper::fail($this->objDStocktaking->error(), ErrorCode::$dberror);
        }
        if(empty($dbResult)){
            $params['no'] = createSerialNumberByDate('');
        }else{
            $params['no'] = createSerialNumberByDate($dbResult['no']);
        }

        //$params['no'] = createOrderSn(StatusCode::$source['manage'], StatusCode::$orderType['stocktaking'], $this->enterpriseId);
        $params['auditId'] = null;
        $params['auditName'] = null;
        $params['deleteStatus'] = StatusCode::$standard;
        $params['auditStatus'] = StatusCode::$auditStatus['auditing'];
        $params['auditTime'] = null;
        $params['createTime'] = time();

        $dbResult = $this->objDStocktaking->insert($params);
        if($dbResult === false){
            $this->objDStocktaking->rollBack();
            return ResultWrapper::fail($this->objDStocktaking->error(), ErrorCode::$dberror);
        }
        $returnData = $dbResult;
        unset($dbResult);
        foreach ($details as &$value){
            $value['linkId'] = $returnData;
            $value['linkNo'] = $params['no'];
            $value['deleteStatus'] = StatusCode::$standard;
            if($value['currentInventoryNum'] < 0){
                return ResultWrapper::fail('实盘库存不能小于0', ErrorCode::$paramError);
            }
            if(bccomp($value['documentInventoryNum'] , $value['currentInventoryNum']) == 1){
                //账面 > 实盘
                //亏
                $value['differenceStatus'] = StatusCode::$delete;
                $value['differenceNum'] = bcsub($value['documentInventoryNum'] , $value['currentInventoryNum'], 8);
            }elseif(bccomp($value['documentInventoryNum'] , $value['currentInventoryNum']) == -1){
                //账面 < 实盘
                //盈
                $value['differenceStatus'] = StatusCode::$standard;
                $value['differenceNum'] = bcsub($value['currentInventoryNum'] , $value['documentInventoryNum'], 8);
            }elseif(bccomp($value['documentInventoryNum'] , $value['currentInventoryNum']) == 0){
                $value['differenceStatus'] = 0;
                $value['differenceNum'] = bcsub($value['currentInventoryNum'] , $value['documentInventoryNum'], 8);
            }else{
                return ResultWrapper::fail('盈亏计算错误', ErrorCode::$paramError);
            }
        }
        $dbResult = $this->objDStocktakingDetails->insert($details, true);
        if($dbResult === false){
            $this->objDStocktaking->rollBack();
            return ResultWrapper::fail($this->objDStocktaking->error(), ErrorCode::$dberror);
        }

        //增加es搜索
        /*$modelResult = self::updateEsData($params, $returnData);
        if(!$modelResult->isSuccess()){
            $this->objDStocktaking->rollBack();
            return ResultWrapper::fail($modelResult->getData(), $modelResult->getErrorCode());
        }*/

        $beginStatus && $this->objDStocktaking->commit();
        return ResultWrapper::success($returnData);
    }

    /**
     * 盘点库存审核
     * @param $params
     * @return ResultWrapper
     * @throws Exception
     */
    public function auditStocktaking($params)
    {
        $id = $params['id'];
        unset($params['id']);
        $params['auditStatus'] = StatusCode::$auditStatus['auditPass'];
        $params['auditTime'] = time();

        // 查询盘点单数据
        $dbResult = $this->objDStocktaking->get($id);
        if($dbResult === false){
            return ResultWrapper::fail($this->objDStocktaking->error(), ErrorCode::$dberror);
        }
        if($dbResult['auditStatus'] == StatusCode::$auditStatus['auditPass']) {
            return ResultWrapper::fail('该单据已审核', ErrorCode::$paramError);
        }
        $stocktakingData = $dbResult;
        unset($dbResult);

        $stocktakingData['originId'] = $stocktakingData['id'];
        $stocktakingData['originNo'] = $stocktakingData['no'];
        $stocktakingData['auditId']  = $params['auditId'];
        $stocktakingData['auditName'] =  $params['auditName'];
        $stocktakingData['sourceId'] = $stocktakingData['id'];
        $stocktakingData['sourceNo'] = $stocktakingData['no'];
        $stocktakingData['type'] = StatusCode::$orderType['stocktaking'];

        // 查询盘点单明细数据
        $dbResult = $this->objDStocktakingDetails->select(['linkId' => $id]);
        if($dbResult === false){
            return ResultWrapper::fail($this->objDStocktakingDetails->error(), ErrorCode::$dberror);
        }
        $details = $dbResult;
        unset($dbResult);

        $addInventoryParams = $stocktakingData;
        $delInventoryParams = $stocktakingData;
        //组装数据
        foreach($details as $value){
            //如果盘点盈亏状态为0 没有盈亏  不操作库存
            if($value['differenceStatus'] == 0){
                continue;
            }
            $value['num'] = $value['differenceNum'];
            if($value['differenceStatus'] == StatusCode::$standard){
                //盈  加
                $addInventoryParams['details'][] = $value;
            }else{
                //亏  减
                $delInventoryParams['details'][] = $value;
            }
        }

        $beginStatus = $this->objDStocktaking->beginTransaction();

        //修改库存
        $objMInventory = new MInventory($this->enterpriseId, $this->userCenterId);
        //加库存
        if(!empty($addInventoryParams['details'])){
            $modelResult = $objMInventory->updateIncInventoryNum($addInventoryParams);
            if(!$modelResult->isSuccess()){
                $this->objDStocktaking->rollBack();
                return ResultWrapper::fail($modelResult->getData(), $modelResult->getErrorCode());
            }
        }
        //减库存
        if(!empty($delInventoryParams['details'])){
            $modelResult = $objMInventory->updatedecInventoryNum($delInventoryParams);
            if(!$modelResult->isSuccess()){
                $this->objDStocktaking->rollBack();
                return ResultWrapper::fail($modelResult->getData(), $modelResult->getErrorCode());
            }
        }

        //修改盘点单
        $dbResult = $this->objDStocktaking->update($params,['id'=>$id]);
        if($dbResult === false){
            $this->objDStocktaking->rollBack();
            return ResultWrapper::fail($this->objDStocktaking->error(), ErrorCode::$dberror);
        }
        $returnData = $dbResult;
        unset($dbResult);

        $beginStatus && $this->objDStocktaking->commit();
        return ResultWrapper::success($returnData);
    }

    /**
     * 盘点库存修改
     * @param $updateData
     * @return ResultWrapper
     */
    public function updateStocktaking($updateData)
    {
        $where['id'] = $updateData['id'];
        unset($updateData['id']);
        unset($updateData['no']);
        $details = $updateData['details'];
        unset($updateData['details']);
        $deleteArray = $updateData['deleteArray'];
        unset($updateData['deleteArray']);

        $dbResult = $this->objDStocktaking->get($where);
        if($dbResult === false){
            return ResultWrapper::fail($this->objDStocktaking->error(), ErrorCode::$dberror);
        }
        $stocktaking = $dbResult;
        unset($dbResult);
        if(empty($stocktaking)){
            return ResultWrapper::fail('单据不存在', ErrorCode::$paramError);
        }

        $beginStatus = $this->objDStocktaking->beginTransaction();
        if(isset($updateData['extend'])) unset($updateData['extend']);
        $dbResult = $this->objDStocktaking->update($updateData,$where);
        if($dbResult === false){
            $this->objDStocktaking->rollBack();
            return ResultWrapper::fail($this->objDStocktaking->error(), ErrorCode::$dberror);
        }
        $returnData = $dbResult;
        unset($dbResult);
        if(!empty($deleteArray)){
            $dbResult = $this->objDStocktakingDetails->update(['deleteStatus' => StatusCode::$delete],['id'=>$deleteArray]);
            if($dbResult === false){
                $this->objDStocktaking->rollBack();
                return ResultWrapper::fail($this->objDStocktakingDetails->error(), ErrorCode::$dberror);
            }
            unset($dbResult);
        }
        $addDetails = [];
        foreach ($details as &$value){
            if(bccomp($value['documentInventoryNum'] , $value['currentInventoryNum']) == 1){
                //账面 > 实盘
                //亏
                $value['differenceStatus'] = StatusCode::$delete;
                $value['differenceNum'] = bcsub($value['documentInventoryNum'] , $value['currentInventoryNum'], 8);
            }elseif(bccomp($value['documentInventoryNum'] , $value['currentInventoryNum']) == -1){
                //账面 < 实盘
                //盈
                $value['differenceStatus'] = StatusCode::$standard;
                $value['differenceNum'] = bcsub($value['currentInventoryNum'] , $value['documentInventoryNum'], 8);
            }elseif(bccomp($value['documentInventoryNum'] , $value['currentInventoryNum']) == 0){
                $value['differenceStatus'] = 0;
                $value['differenceNum'] = bcsub($value['currentInventoryNum'] , $value['documentInventoryNum'], 8);
            }else{
                return ResultWrapper::fail('盈亏计算错误', ErrorCode::$paramError);
            }
            if(isset($value['id']) && !empty($value['id'])){
                //修改
                $id = $value['id'];
                unset($value['id']);
                $dbResult = $this->objDStocktakingDetails->update($value,['id'=>$id]);
                if($dbResult === false){
                    $this->objDStocktaking->rollBack();
                    return ResultWrapper::fail($this->objDStocktakingDetails->error(), ErrorCode::$dberror);
                }
                unset($dbResult);
            }else{
                //新增
                $data['linkId'] = $stocktaking['id'];
                $data['linkNo'] = $stocktaking['no'];
                $data['materielId'] = $value['materielId'];
                $data['materielCode'] = $value['materielCode'];
                $data['materielName'] = $value['materielName'];
                $data['skuId'] = $value['skuId'];
                $data['documentInventoryNum'] = $value['documentInventoryNum'];
                $data['currentInventoryNum'] = $value['currentInventoryNum'];
                $data['differenceNum'] = $value['differenceNum'];
                $data['otherNum'] = $value['otherNum'];
                $data['remark'] = $value['remark'];
                $data['differenceStatus'] = $value['differenceStatus'];
                $data['deleteStatus'] = StatusCode::$standard;
                $data['createTime'] = time();
                $data['updateTime'] = time();
                $addDetails[] = $data;
            }
        }
        if(!empty($addDetails)){
            $dbResult = $this->objDStocktakingDetails->insert($addDetails, true);
            if($dbResult === false){
                $this->objDStocktaking->rollBack();
                return ResultWrapper::fail($this->objDStocktakingDetails->error(), ErrorCode::$dberror);
            }
        }
        $beginStatus && $this->objDStocktaking->commit();
        return ResultWrapper::success($returnData);
    }

    /**
     * 盘点库存列表
     * @param $selectParams
     * @param $export
     * @return ResultWrapper
     */
    public function getAllStocktaking($selectParams, $export)
    {

        $limit = $selectParams['limit'];
        unset($selectParams['limit']);
        $offset = $selectParams['offset'];
        unset($selectParams['offset']);
        if($export){
            $limit = null;
            $offset = null;
        }
        $selectParams['deleteStatus'] = StatusCode::$standard;
        
//        if($export){
//            $selectParams['auditStatus'] = StatusCode::$auditStatus['auditPass'];
//            $dbResult = $this->objDStocktaking->select($selectParams);
//            if($dbResult === false){
//                return ResultWrapper::fail($this->objDStocktaking->error(), ErrorCode::$dberror);
//            }
//            $modelResult = self::export($dbResult);
//            if(!$modelResult->isSuccess()){
//                return ResultWrapper::fail($modelResult->getData(), $modelResult->getErrorCode());
//            }
//            exit;
//        }

        $dbResult = $this->objDStocktaking->select($selectParams, '*', 'createTime desc', $limit, $offset);
        if ($dbResult === false) {
            return ResultWrapper::fail($this->objDStocktaking->error(), ErrorCode::$dberror);
        }

        $total = $this->objDStocktaking->count($selectParams);

        $formatData = parent::formatOrderMan($this->enterpriseId, $dbResult);
        foreach ($formatData as $key => $value){
            if( isset($value['no']) && !empty($value['no']) ){
                $formatData[$key]['no'] = StatusCode::$noPrefix[13].'-'.$value['no'];
            }
        }

        $return = [
            'data' => $formatData,
            'total' => ($total) ? intval($total) : 0,
        ];
        if($export){
            self::export($return['data']);
            exit;
        }
        if($return === false){
            return ResultWrapper::fail($this->objDStocktaking->error(), ErrorCode::$dberror);
        }else{
            return ResultWrapper::success($return);
        }
    }

    /**
     * 盘点搜索
     * @param $params
     * @param $export
     * @return ResultWrapper
     */
    public function searchAllStocktaking($params, $export)
    {
        $defaultDSL = ['from' => $params['offset'],'size' => $params['limit'],'sort' => ['createTime' => ['order' => 'desc']]];
        $selectParams = [];
//        !empty($params['warehouseId']) && $selectParams[] = ['term' => ['warehouseId' => $params['warehouseId']]];
        $selectParams[] = ['term' => ['enterpriseId' => $this->enterpriseId]];
        (!empty($params['start']) && !empty($params['end'])) && $selectParams[] = ['range' => ['createTime' => ['gte' => $params['start'],'lte' => $params['end']]]];
        !empty($params['search']) && $selectParams[] = ['multi_match' => ['fields' => ['no', 'operatorName'],'query' => $params['search'],'fuzziness' => 'AUTO']];
        $dsl = [];
        !empty($selectParams) && $dsl['query']['bool']['must'][] = $selectParams;
        $dsl = array_merge($defaultDSL, $dsl);

        if($export){
            $dbResult = $this->objDStocktaking->getScrollSearchQueryDsl($dsl);
            if(isset($dbResult['error'])){
                return ResultWrapper::fail($dbResult, ErrorCode::$dberror);
            }
            $returnData = parent::formatEsSelectData($dbResult);
            $formatIds = [];
            $formatData = [];
            foreach($returnData['data'] as $value){
                $formatIds[] = $value['id'];
                $formatData[$value['id']] = $value;
            }
            unset($dbResult);
            $dbResult = $this->objDStocktakingDetails->exportSelect(['linkId'=>$formatIds, 'deleteStatus' => StatusCode::$standard]);
            if($dbResult === false){
                return ResultWrapper::fail($this->objDStocktakingDetails->error(), ErrorCode::$dberror);
            }
            $modelResult = self::export($dbResult);
            if(!$modelResult->isSuccess()){
                return ResultWrapper::fail($modelResult->getData(), $modelResult->getErrorCode());
            }
            exit;
        }

        $dbResult = $this->objDStocktaking->getSearchQueryDsl($dsl);
        if(isset($dbResult['error'])){
            return ResultWrapper::fail($dbResult, ErrorCode::$dberror);
        }
        $returnData = parent::formatEsSelectData($dbResult, $this->enterpriseId);
        return ResultWrapper::success($returnData);
    }

    /**
     * 盘点导出方法
     * @param $result
     * @return ResultWrapper
     */
    public function export($result)
    {
        $formatIds = [];
        $formatData = [];
        foreach($result as $value){
            $formatIds[] = $value['id'];
            $formatData[$value['id']] = $value;
        }
        unset($dbResult);
        $details = $this->objDStocktakingDetails->select(['linkId'=>$formatIds, 'deleteStatus' => StatusCode::$standard]);
        if($details === false){
            return ResultWrapper::fail($this->objDStocktakingDetails->error(), ErrorCode::$dberror);
        }

        //导出到本地
        header ( "Content-type:application/vnd.ms-excel" );
        header ( "Content-Disposition:filename=盘点记录表.csv" );
        header ('Cache-Control: max-age=0');

        $fp = fopen('php://output', 'a');

        $head = ['盘点单号','仓库/门店','制单人','商品名称', '商品编码', '单位','属性', '账面库存', '实盘库存', '盈亏数量','盈亏状态','盘点日期'];//定义标题

        foreach ($head as $i => $v) {
            $head[$i] = mb_convert_encoding($v, 'GBK', 'utf-8');     //将中文标题转换编码，否则乱码
        }

        fputcsv($fp, $head);

        $limit = 10000;
        $num = 0;                                         //计数器
        foreach ( $details as $value ) {                           //循环数据
            $num++;
            if($num == $limit){
                ob_flush();         //释放内存
                flush();
            }

            $value = parent::formatOrderMan($this->enterpriseId, $value);

            $v = parent::formatOrderMan($this->enterpriseId,$formatData[$value['linkId']]);

            $rows['no'] = isset($v['no']) ? $v['no'] : null;
//            $rows['auditStatus'] = $v['auditStatus'] == StatusCode::$auditStatus['auditPass'] ? '已审核' : '未审核';
            $rows['warehouseName'] = isset($v['warehouseName']) ? $v['warehouseName'] : null;
//            $rows['num'] = isset($v['num']) ? $v['num'] : null;
            $rows['operatorName'] = isset($v['operatorName']) ? $v['operatorName'] : null;
            $rows['materielName'] = isset($value['materielName']) ? $value['materielName'] : null;
            $rows['materielCode'] = isset($value['materielCode']) ? $value['materielCode'] : null;
            $rows['unitName'] = isset($value['unitName']) ? $value['unitName'] : null;
            $rows['skuName'] = isset($value['skuName']) ? $value['skuName'] : null;
            $rows['documentInventoryNum'] = isset($value['documentInventoryNum']) ? $value['documentInventoryNum'] : null;
            $rows['currentInventoryNum'] = isset($value['currentInventoryNum']) ? $value['currentInventoryNum'] : null;
            $icon = $value['differenceStatus'] == StatusCode::$standard ? '+' : '-';
            $differenceNum = isset($value['differenceNum']) ? $value['differenceNum'] : null;
            $rows['differenceNum'] = $icon.$differenceNum;
            $rows['differenceStatus'] = $value['differenceStatus'] == StatusCode::$standard ? '盈' : '亏';
            $rows['stocktakingTime'] = date('Y-m-d H:i:s', $v['stocktakingTime']);
           
            foreach ( $rows as $kk => $vv){
                $rs[$kk] = mb_convert_encoding($vv, 'GBK', 'utf-8');  //转译编码
            }
            fputcsv($fp, $rs);

            $rows = [];
        }
        return ResultWrapper::success('成功');
    }

    /**
     * 盘点库存详情
     * @param $params
     * @return ResultWrapper
     * @throws Exception
     */
    public function getStocktakingInfo($params)
    {
        $params['deleteStatus'] = StatusCode::$standard;
        $dbResult = $this->objDStocktaking->get($params);
        if($dbResult === false){
            return ResultWrapper::fail($this->objDStocktaking->error(), ErrorCode::$dberror);
        }
        $returnData = $dbResult;
        unset($dbResult);
        $dbResult = $this->objDStocktakingDetails->select(['linkId' => $returnData['id'],'deleteStatus'=>StatusCode::$standard]);
        if($dbResult === false){
            return ResultWrapper::fail($this->objDStocktakingDetails->error(), ErrorCode::$dberror);
        }
        $returnData['details'] = $dbResult;
        $returnData = parent::formatOrderMan($this->enterpriseId, $returnData);
        return ResultWrapper::success($returnData);
    }

    /**
     * 添加es
     * @param $id
     * @param $data
     * @return ResultWrapper
     */
    public function updateEsData($data,$id)
    {
        $addEsData = [
            //采购入库信息
            'id' => $id,
            'enterpriseId' => $this->enterpriseId,
            'no' => $data['no'],
            'num' => $data['num'],
            'warehouseId' => $data['warehouseId'],
            'warehouseName' => $data['warehouseName'],
            'operatorId' => $data['operatorId'],
            'operatorName' => $data['operatorName'],
            'auditId' => $data['auditId'],
            'auditName' => $data['auditName'],
            'remark' => $data['remark'],
            'stocktakingTime' => $data['stocktakingTime'],
            'deleteStatus' => $data['deleteStatus'],
            'auditStatus' => $data['auditStatus'],
            'auditTime' => $data['auditTime'],
            'createTime' => $data['createTime'],
            'updateTime' => $data['updateTime'],
        ];

        //创建es id
        $esId = self::esId($id);
        $result = $this->objDStocktaking->addUpSearchIndexDocument($addEsData, $esId);
        if (isset($result['_shards']) && isset($result['_shards']['successful']) && $result['_shards']['successful'] == 1) {
            return ResultWrapper::success(isset($result['_id']) ? $result['_id'] : false);
        }
        return ResultWrapper::fail($result['error']['reason'], ErrorCode::$paramError);
    }

    /**
     * 拼接es id
     * @param $id
     * @return string
     */
    public function esId($id)
    {
        return 'EnterpriseId_' . $this->enterpriseId . '_stocktakingId_' . $id;
    }




}