<?php
/**
 * 客户余额明细管理模块
 * Created by PhpStorm.
 * User: wxj
 * Date: 2019/10/30
 * Time: 14:02
 */

namespace JinDouYun\Model\Finance;

use Mall\Framework\Core\ErrorCode;
use Mall\Framework\Core\StatusCode;
use Mall\Framework\Core\ResultWrapper;
use JinDouYun\Model\MBaseModel;
use JinDouYun\Dao\Finance\DCustomerBalanceDetail;
use JinDouYun\Dao\Finance\DCustomerBalanceDetailIndex;

class MCustomerBalanceDetail extends MBaseModel
{

    private $objDCustomerBalanceDetail;
    private $objDCustomerBalanceDetailIndex;
    private $enterpriseId;
    private $userCenterId;
    private $objMCustomerBalance;

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

        $this->objDCustomerBalanceDetail = new DCustomerBalanceDetail('finance');
        $this->objDCustomerBalanceDetailIndex = new DCustomerBalanceDetailIndex('finance');
        $this->objMCustomerBalance = new MCustomerBalance($enterpriseId, $userCenterId);

        $this->objDCustomerBalanceDetail->setTable('qianniao_customer_balance_detail_' . $enterpriseId . '_' . date('Y') . '_' . ceil(date('m') / 3));
        $this->objDCustomerBalanceDetailIndex->setTable('qianniao_customer_balance_detail_index_' . $enterpriseId);
    }

    /**
     * 添加客户余额明细
     * @param array $params 客户余额明细数据
     * @return ResultWrapper
     * @throws \Exception
     */
    public function addCustomerBalanceDetail($params)
    {
        $beginTransactionStatus = $this->objDCustomerBalanceDetail->beginTransaction();

        $CustomerBalanceDetailId = $this->objDCustomerBalanceDetail->insert($params);
        if ($CustomerBalanceDetailId === false) {
            $this->objDCustomerBalanceDetail->rollBack();
            return ResultWrapper::fail($this->objDCustomerBalanceDetail->error(), ErrorCode::$dberror);
        }
        $params['no'] = empty($params['no'])?$params['sourceNo']:$params['no'];
        //添加索引表
        $indexData = [
            'detailId'    => $CustomerBalanceDetailId,
            'customerId'  => $params['customerId'],
            'receiptTime' => $params['receiptTime'],
            'no'          => $params['no'],
            'createTime'  => $params['createTime'],
            'updateTime'  => $params['updateTime'],
        ];
        $result = $this->objDCustomerBalanceDetailIndex->insert($indexData);

        if ($result === false) {
            $this->objDCustomerBalanceDetail->rollBack();
            return ResultWrapper::fail($this->objDCustomerBalanceDetailIndex->error(), ErrorCode::$dberror);
        }

        if($beginTransactionStatus){
            $this->objDCustomerBalanceDetail->commit();
        }
        return ResultWrapper::success($CustomerBalanceDetailId);

    }

    /**
     * 获取所有客户余额明细数据
     *
     * @param array $selectParams 过滤条件
     *
     * @return ResultWrapper
     * @throws \Exception
     */
    public function getAllCustomerBalanceDetail($selectParams,$export = 0)
    {
        $limit = $selectParams['limit'];
        unset($selectParams['limit']);
        $offset = $selectParams['offset'];
        unset($selectParams['offset']);
        if($export){
            $limit = null;
            $offset = null;
        }
        $customerId = $selectParams['customerId'];
        unset($selectParams['customerId']);
        $start = $selectParams['start'];
        unset($selectParams['start']);
        $end = $selectParams['end'];
        unset($selectParams['end']);

        // 先从客户余额明细主索引表查询客户数据
        $where = "customerId = " . $customerId . ' AND createTime>=' . $start . ' AND createTime<=' . $end;
        $customerBalanceDetailIndexResult = $this->objDCustomerBalanceDetailIndex->select($where, '*', 'createTime asc', $limit, $offset);
        if($customerBalanceDetailIndexResult === false) {
            return ResultWrapper::fail($this->objDCustomerBalanceDetailIndex->error(), ErrorCode::$dberror);
        }

        // 计算明细数据都落在那几张分表上
        $tableSuffix = [];
        foreach ($customerBalanceDetailIndexResult as $customerBalanceDetailIndex) {
            $k = date('Y', $customerBalanceDetailIndex['createTime']) . '_' . ceil(date('m', $customerBalanceDetailIndex['createTime']) / 3);
            $tableSuffix[$k][] = $customerBalanceDetailIndex['detailId'];
        }

        // 切换分表获取单据明细数据
        $detailResult = [];
        foreach ($tableSuffix as $suffix => $detailIds) {
            $this->objDCustomerBalanceDetail->setTable('qianniao_customer_balance_detail_' . $this->enterpriseId . '_' . $suffix);
            $dbResult = $this->objDCustomerBalanceDetail->select($detailIds, '*', 'createTime asc');
            if ($dbResult === false) {
                return ResultWrapper::fail($this->objDCustomerBalanceDetail->error(), ErrorCode::$dberror);
            }
            $detailResult = array_merge($detailResult, self::format($dbResult));
        }

        if(!empty($customerBalanceDetailIndexResult)){
            $total = $this->objDCustomerBalanceDetailIndex->count($where);
        }

        //期初余额
        $start = $this->objMCustomerBalance->getShouldReceiveMoneyByTime($start, $customerId);
        //期末余额
        $end = $this->objMCustomerBalance->getShouldReceiveMoneyByTime($end, $customerId);

        //应收款余额总计
        $shouldReceiveTotal = $this->objMCustomerBalance->getCustomerBalance($customerId);
        //实际收款金额总计
        $actualReceiveTotal = $this->objMCustomerBalance->getCustomerBalance($customerId, 'totalPayMoney');

        $return = [
            'data'               => $detailResult,
            'total'              => (isset($total)&&!empty($total)) ? intval($total) : 0,
            'openingBalance'     => $start ? $start : 0,
            'endingBalance'      => $end ? $end : 0,
            'shouldReceiveTotal' => $shouldReceiveTotal ? $shouldReceiveTotal : 0,
            'actualReceiveTotal' => $actualReceiveTotal ? $actualReceiveTotal : 0
        ];
        //导出
        if($export){
            self::exportCustomerBalanceDetail($detailResult);
            exit;
        }
        return ResultWrapper::success($return);
    }

    /**
     * 公共的格式化方法
     */
    public function format($data)
    {
        foreach ($data as $k => $v){
            //如果是销售单，销售收款，只展示应收金额
            $data[$k]['salesAmount'] = $v['financeType'] == '预存收款' || $v['financeType'] == '销售收款' ? '--' : $v['salesAmount'];
            $data[$k]['discountMoney'] = $v['financeType'] == '预存收款' || $v['financeType'] == '销售收款' ? '--' : $v['discountMoney'];
            $data[$k]['receivableAmount'] = $v['financeType'] == '预存收款' || $v['financeType'] == '销售收款' ? '--' : $v['receivableAmount'];

            switch ($v['financeType']){
                case '销售单':
                    $data[$k]['sourceNo'] = StatusCode::$noPrefix[16].'-'.$v['sourceNo'];
                    $data[$k]['originNo'] = StatusCode::$noPrefix[1].'-'.$v['originNo'];
                    break;
                case '销售收款':
                    $data[$k]['sourceNo'] = StatusCode::$noPrefix[17].'-'.$v['sourceNo'];
                    $data[$k]['originNo'] = ($data[$k]['originNo']) ? StatusCode::$noPrefix[16].'-'.$v['originNo'] : '';
                    break;
                case '线上支付收款':
                case '预存收款':
                case '银行打款收款':
                    $data[$k]['sourceNo'] = StatusCode::$noPrefix[17].'-'.$v['sourceNo'];
                    $data[$k]['originNo'] = ($data[$k]['originNo']) ? StatusCode::$noPrefix[1].'-'.$v['originNo'] : '';
                    break;
                case '销售退货单':
                    $data[$k]['sourceNo'] = StatusCode::$noPrefix[16].'-'.$v['sourceNo'];
                    $data[$k]['originNo'] = ($data[$k]['originNo']) ? StatusCode::$noPrefix[6].'-'.$v['originNo'] : '';
                    break;
                case '订单退货退款':
                    $data[$k]['sourceNo'] = StatusCode::$noPrefix[20].'-'.$v['sourceNo'];
                    $data[$k]['originNo'] = ($data[$k]['originNo']) ? StatusCode::$noPrefix[15].'-'.$v['originNo'] : '';
                    break;
                case '订单完结退款':
                    $data[$k]['sourceNo'] = StatusCode::$noPrefix[20].'-'.$v['sourceNo'];
                    $data[$k]['originNo'] = ($data[$k]['originNo']) ? StatusCode::$noPrefix[1].'-'.$v['originNo'] : '';
                    break;
            }
        }

        return $data;
    }
    
    /**
     * 导出方法
     * @param $result
     * @return void
     * @throws Exception
     */
    public function exportCustomerBalanceDetail($result)
    {
      
        //导出到本地
        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 ($result as $v) {                           //循环数据
            $num++;
            if ($num == $limit) {
                ob_flush();         //释放内存
                flush();
            }
            $rows['receiptTime']    = isset($v['receiptTime']) ? date('Y-m-d', $v['receiptTime']) : '';//单据日期
            $rows['no']             = isset($v['no']) ? $v['no'] : '';//单据编号
            $rows['financeType']    = isset($v['financeType']) ? $v['financeType'] : '';//业务类别
            $rows['sourceNo']       = isset($v['sourceNo']) ? $v['sourceNo'] : '';//源销货订单号
            $rows['salesAmount']    = isset($v['salesAmount']) ? $v['salesAmount'] : '';//销售金额
            $rows['discountMoney']  = isset($v['discountMoney']) ? $v['discountMoney'] : '';//优惠金额
            $rows['receivableAmount'] = isset($v['receivableAmount']) ? $v['receivableAmount'] : '';//应收金额
            $rows['actualReceivableAmount'] = isset($v['actualReceivableAmount']) ? $v['actualReceivableAmount'] : '';//实收金额
            $rows['receivableBalance'] = isset($v['receivableBalance']) ? $v['receivableBalance'] : '';//应收余额
            $rows['remark'] = isset($v['remark']) ? $v['remark'] : '';//备注
            
            foreach ($rows as $kk => $vv) {
                $rs[$kk] = mb_convert_encoding($vv, 'GBK', 'utf-8');  //转译编码
            }
            fputcsv($fp, $rs);
            
            $rows = [];
        }
    }

}