<?php


namespace JinDouYun\Model\Merchant;


use JinDouYun\Dao\Merchant\DMerchantDetail;
use JinDouYun\Dao\Merchant\DMerchantWithdraw;
use JinDouYun\Dao\Merchant\DMerchantApply;

use JinDouYun\Model\Enterprise\MEnterprise;
use JinDouYun\Model\Finance\MMerchantFlow;
use JinDouYun\Model\MBaseModel;

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

/**
 * @copyright   Copyright (c) https://www.qianniaovip.com All rights reserved
 * Description:
 * Class MMerchantWithdraw
 * @package JinDouYun\Model\Merchant
 */
class MMerchantWithdraw extends MBaseModel
{
    private $onlineEnterpriseId;

    private $onlineUserId;

    private $objDMerchantWithdraw;

    private $objDMerchantApply;

    private $objDMerchantDetail;

    /**
     * MMerchantWithdraw constructor.
     * @param $onlineEnterpriseId
     * @param $onlineUserId
     * @throws \Exception
     */
    public function __construct($onlineEnterpriseId, $onlineUserId)
    {
        $this->onlineUserId = $onlineUserId;
        $this->onlineEnterpriseId = $onlineEnterpriseId;
        parent::__construct($onlineEnterpriseId, $onlineUserId);
        $this->objDMerchantWithdraw = new DMerchantWithdraw();
        $this->objDMerchantApply = new DMerchantApply();
        $this->objDMerchantDetail = new DMerchantDetail();
        $this->objDMerchantWithdraw->setTable('qianniao_merchant_withdraw_' . $this->onlineEnterpriseId);
        $this->objDMerchantDetail->setTable('qianniao_merchant_detail_' . $this->onlineEnterpriseId);
    }

    /**
     * Doc: (des="商户申请提现")
     * User: XMing
     * Date: 2020/12/8
     * Time: 11:27 上午
     * @param array $params
     * @param $shopId
     * @return ResultWrapper
     * @throws \Exception
     */
    public function add(array $params, $merchantId): ResultWrapper
    {
        $objMMerchant = new MMerchant($this->onlineEnterpriseId, $this->onlineUserId);
//        $merchResult = $objMMerchant->getMerchByShopId($shopId);
        $merchantApply = $this->objDMerchantApply->get($merchantId);
        if ($merchantApply=== false) {
            return ResultWrapper::fail($this->objDMerchantApply->error(), ErrorCode::$dberror);
        }
        $merch = $merchantApply;
        if ($merch['balance'] < $params['money']) {
            return ResultWrapper::fail('可提现余额不足', ErrorCode::$paramError);
        }
//        if ($merch['orderNum'] < $params['orderNum']) {
//            return ResultWrapper::fail('提现订单数异常', ErrorCode::$paramError);
//        }
        $objMEnterprise = new MEnterprise();
        $enterpriseResult = $objMEnterprise->getEnterpriseDataByEnterpriseId($this->onlineEnterpriseId);
        if (!$enterpriseResult->isSuccess()) {
            return ResultWrapper::fail($enterpriseResult->getData(), $enterpriseResult->getErrorCode());
        }
        $enterprise = $enterpriseResult->getData();
        if (empty($enterprise)) {
            return ResultWrapper::fail('未获取到平台数据', ErrorCode::$paramError);
        }

        $settingResult = $objMMerchant->getSetting();
        if (!$settingResult->isSuccess()) {
            return ResultWrapper::fail($settingResult->getData(), $settingResult->getErrorCode());
        }
        $setting = $settingResult->getData();
        $take_price = getArrayItem($setting, 'take_price', 0);
        $take_price_rate = bcdiv($take_price, 100, 4);
        $fee = bcmul($params['money'], $take_price_rate, 2);
        $nowMoney = bcsub($params['money'], $fee, 2);
        $no = createOrderSn(StatusCode::$source['manage'], StatusCode::$orderType['storeWithdraw'], $this->onlineUserId);
        $orderNum = $params['orderNum'];//本次提现订单数
        $insert = [
            'no'             => $no,
            'merchantId'     => $merch['id'],
            'merchantName'   => $merch['name'],
            'type'           => $params['type'],
            'accountContent' => json_encode($params['accountContent']),
            'money'          => $params['money'],
            'auditStatus'    => StatusCode::$auditStatus['auditing'],
            'rate'           => $take_price,//抽成比率
            'fee'            => $fee,//抽成金额
            'nowMoney'       => $nowMoney,//预计到账金额
            'orderNum'       => $orderNum,//本次提现金额订单数
            'createTime'     => time(),
        ];

        //减商户可提现余额
        $originMoney = getArrayItem($merch, 'balance', 0);
        $finalMoney = bcsub($originMoney, $params['money'], 2);
        $merch_log = [
            'merchantId'   => $merch['id'],
            'merchantName' => $merch['name'],
            'originId'     => 0,
            'originNo'     => $no,
            'tradeMoney'   => $params['money'],
            'originMoney'  => $originMoney,
            'changeMoney'  => $params['money'],
            'nowMoney'     => $finalMoney,
            'rate'         => $take_price,
            'fee'          => $fee,
            'type'         => StatusCode::$delete,
            'isPayment'    => StatusCode::$delete,
            'isPlatform'   => StatusCode::$delete,
            'source'       => 2,
            'describe'     => '账户可提现金额:' . $originMoney . '元,本次提现金额:' . $params['money'] . '元,抽成比率:' . $take_price . '%,预计抽成金额:' . $fee . '元,账户剩余可提现:' . $finalMoney . '元',
            'createTime'   => time()
        ];

        //加商户提现待审核金额
        $update_merch = [
            'orderNum'          => bcsub($merch['orderNum'], $orderNum, 0),//每次提现都是全部订单
            'auditOrderNum'     => bcadd($merch['auditOrderNum'], $orderNum, 0),//等待审核的订单数量
            'balance'           => $finalMoney,
            'waitAuditWithdraw' => bcadd(getArrayItem($merch, 'waitAuditWithdraw', 0), $params['money'], 2),
            'updateTime'        => time(),
        ];
        //打款成功后计入平台抽成收入
        $objMMerchantFlow = new MMerchantFlow($this->onlineEnterpriseId, $this->onlineUserId);
        $beginTransactionStatus =  $this->objDMerchantWithdraw->beginTransaction();
        $insertResult = $this->objDMerchantWithdraw->insert($insert);
        if ($insertResult === false) {
            $this->objDMerchantWithdraw->rollBack();
            return ResultWrapper::fail($this->objDMerchantWithdraw->error, ErrorCode::$dberror);
        }
        $merch_log['originId'] = $insertResult;
        $flowResult = $objMMerchantFlow->add($merch_log);
        if (!$flowResult->isSuccess()) {
            $this->objDMerchantWithdraw->rollBack();
            return ResultWrapper::fail($flowResult->getData(), $flowResult->getErrorCode());
        }
        $updateMerchResult = $objMMerchant->update($merch['id'], $update_merch);
        if (!$updateMerchResult->isSuccess()) {
            $this->objDMerchantWithdraw->rollBack();
            return ResultWrapper::fail($updateMerchResult->getData(), $updateMerchResult->getErrorCode());
        }

        //提现成功添加流水
        $insertDetail = [
            'merchantId'   => $merch['id'],
            'merchantName' => $merch['name'],
            'originId' => $insertResult,
            'originNo' => $no,
            'money' => $params['money'],
            'afterMoney' => $finalMoney,
            'type' => StatusCode::$delete,
            'source' => 1,
            'remark' => '提现',
            'createTime' => time(),
            'updateTime' => time()
        ];
        $detailsDbResult = $this->objDMerchantDetail->insert($insertDetail);
        if($detailsDbResult === false){
            $this->objDMerchantDetail->rollBack();
            return ResultWrapper::fail($this->objDMerchantDetail->error(), ErrorCode::$dberror);
        }
        if($beginTransactionStatus){
            $this->objDMerchantWithdraw->commit();
        }
        return ResultWrapper::success(true);
    }

    /**
     * Doc: (des="更新提现记录状态")
     * User: XMing
     * Date: 2020/12/8
     * Time: 3:58 下午
     * @param int $id
     * @param int $status
     * @return ResultWrapper
     * @throws \Exception
     */
    public function updateAuditStatus(int $id, int $status): ResultWrapper
    {
        if (!in_array($status, array_keys(StatusCode::$auditStatus))) {
            return ResultWrapper::fail('状态不存在', ErrorCode::$notAllowAccess);
        }
        //查询当前记录
        $withdraw = $this->objDMerchantWithdraw->get($id);
        if ($withdraw === false) {
            return ResultWrapper::fail($this->objDMerchantWithdraw->error, ErrorCode::$dberror);
        }
        if (empty($withdraw)) {
            return ResultWrapper::fail('未获取到指定的记录', ErrorCode::$paramError);
        }
        //获取商户的数据
        $objMMerchant = new MMerchant($this->onlineEnterpriseId, $this->onlineUserId);
//        $merchResult = $objMMerchant->getMerchByShopId($withdraw['shopId']);
//        if (!$merchResult->isSuccess()) {
//            return ResultWrapper::fail($merchResult->getData(), $merchResult->getErrorCode());
//        }
//        $merch = $merchResult->getData();
        $merchantApply = $this->objDMerchantApply->get($withdraw['merchantId']);
        if ($merchantApply=== false) {
            return ResultWrapper::fail($this->objDMerchantApply->error(), ErrorCode::$dberror);
        }
        $merch = $merchantApply;
        $oldBalance = $merch['balance'];//可提现
        $oldWaitAuditWithdraw = $merch['waitAuditWithdraw'];//提现等待审核
        $oldAuditWithdraw = $merch['auditWithdraw'];//提现待入账金额
        $oldWithdraw = $merch['withdraw'];//已提现金额

        $changeMoney = $withdraw['money'];//本次变动金额
        $updateMap = [];
        $plat_log = [];
        switch ($status) {
            case StatusCode::$auditStatus['auditing']:
                //申请提现操作
                break;
            case StatusCode::$auditStatus['auditPass']:
                //打款成功,需要给平台抽成
                // + finishOrderNum - waitFinishOrderNum
                if (bcsub($oldAuditWithdraw, $changeMoney, 2) < 0) {
                    return ResultWrapper::fail('待入账金额不足', ErrorCode::$paramError);
                }
                $updateMap = [
                    'updateTime'         => time(),
                    'auditWithdraw'      => bcsub($oldAuditWithdraw, $changeMoney, 2),
                    'withdraw'           => bcadd($oldWithdraw, $changeMoney, 2),
                    'finishOrderNum'     => bcadd($merch['finishOrderNum'], $withdraw['orderNum'], 0),
                    'waitFinishOrderNum' => bcsub($merch['waitFinishOrderNum'], $withdraw['orderNum'], 0),
                ];

                if ($withdraw['fee'] > 0) {
                    $objMEnterprise = new MEnterprise();
                    $enterpriseResult = $objMEnterprise->getEnterpriseDataByEnterpriseId($this->onlineEnterpriseId);
                    if (!$enterpriseResult->isSuccess()) {
                        return ResultWrapper::fail($enterpriseResult->getData(), $enterpriseResult->getErrorCode());
                    }
                    $enterprise = $enterpriseResult->getData();
                    if (empty($enterprise)) {
                        return ResultWrapper::fail('未获取到平台数据', ErrorCode::$paramError);
                    }
                    $plat_log = [
                        'merchantId'   => $merch['id'],
                        'merchantName' => $merch['name'],
                        'originId'     => $withdraw['id'],
                        'originNo'     => $withdraw['no'],
                        'tradeMoney'   => $withdraw['money'],
                        'originMoney'  => $enterprise['balance'],
                        'changeMoney'  => $withdraw['fee'],
                        'nowMoney'     => bcsub($enterprise['balance'], $withdraw['fee'], 2),
                        'rate'         => $withdraw['rate'],
                        'fee'          => $withdraw['fee'],
                        'type'         => StatusCode::$standard,
                        'isPayment'    => StatusCode::$delete,
                        'isPlatform'   => StatusCode::$standard,
                        'source'       => 2,
                        'describe'     => '当前平台账户金额:' . $enterprise['balance'] . '元,本次抽成比率:' . $withdraw['rate'] . '%,本次抽成金额:' . $withdraw['fee'] . '元,变动后账户金额:' . bcsub($enterprise['balance'], $withdraw['fee'], 2) . '元',
                        'createTime'   => time()
                    ];
                }
                break;
            case StatusCode::$auditStatus['auditNotPass']:
                //提现审核拒绝，回到余额
                // + notOrderNum - auditOrderNum + orderNum
                if (bcsub($oldWaitAuditWithdraw, $changeMoney, 2) < 0) {
                    return ResultWrapper::fail('待审核金额不足', ErrorCode::$paramError);
                }
                $updateMap = [
                    'updateTime'        => time(),
                    'balance'           => bcadd($oldBalance, $changeMoney, 2),
                    'waitAuditWithdraw' => bcsub($oldWaitAuditWithdraw, $changeMoney, 2),
                    'notOrderNum'       => bcadd($merch['notOrderNum'], $withdraw['orderNum'], 0),
                    'auditOrderNum'     => bcsub($merch['auditOrderNum'], $withdraw['orderNum'], 0),
                    'orderNum'          => bcadd($merch['orderNum'], $withdraw['orderNum'], 0),
                ];
                $plat_log = [
                    'merchantId'   => $merch['id'],
                    'merchantName' => $merch['name'],
                    'originId'     => $withdraw['id'],
                    'originNo'     => $withdraw['no'],
                    'tradeMoney'   => $withdraw['money'],
                    'originMoney'  => $oldBalance,
                    'changeMoney'  => $changeMoney,
                    'nowMoney'     => bcadd($oldBalance, $changeMoney, 2),
                    'rate'         => 0,
                    'fee'          => 0,
                    'type'         => StatusCode::$standard,
                    'isPayment'    => StatusCode::$delete,
                    'isPlatform'   => StatusCode::$delete,
                    'source'       => 2,
                    'describe'     => '当前账户金额:' . $oldBalance . '元,本次提现驳回金额:' . $changeMoney . '元,变动后账户金额:' . bcadd($oldBalance, $changeMoney, 2) . '元',
                    'createTime'   => time()
                ];
                break;
            case StatusCode::$auditStatus['auditIng']:
                //等待打款，审核成功
                // + passOrderNum - auditOrderNum + waitFinishOrderNum
                if (bcsub($oldWaitAuditWithdraw, $changeMoney, 2) < 0) {
                    return ResultWrapper::fail('待审核金额不足', ErrorCode::$paramError);
                }
                $updateMap = [
                    'updateTime'         => time(),
                    'waitAuditWithdraw'  => bcsub($oldWaitAuditWithdraw, $changeMoney, 2),
                    'auditWithdraw'      => bcadd($oldAuditWithdraw, $changeMoney, 2),
                    'passOrderNum'       => bcadd($merch['passOrderNum'], $withdraw['orderNum'], 0),
                    'waitFinishOrderNum' => bcadd($merch['waitFinishOrderNum'], $withdraw['orderNum'], 0),
                    'auditOrderNum'      => bcsub($merch['auditOrderNum'], $withdraw['orderNum'], 0),
                ];
                break;
            default:
                return ResultWrapper::fail('状态值有误', ErrorCode::$paramError);
                break;
        }

        $updateData = [
            'auditStatus' => $status,
            'updatetime'  => time(),
        ];

        // 审核通过时间
        if ($status == StatusCode::$auditStatus['auditIng']) {
            $updateData['auditTime'] = time();
        }

        // 打款完成时间
        if ($status == StatusCode::$auditStatus['auditIng']) {
            $updateData['payTime'] = time();
        }

        $this->objDMerchantWithdraw->beginTransaction();
        //操作余额
        $updateMerchResult = $objMMerchant->update($merch['id'], $updateMap);
        if (!$updateMerchResult->isSuccess()) {
            $this->objDMerchantWithdraw->rollBack();
            return ResultWrapper::fail($updateMerchResult->getData(), $updateMerchResult->getErrorCode());
        }
        //更新状态
        $auditResult = $this->objDMerchantWithdraw->update($updateData, $id);
        if ($auditResult === false) {
            $this->objDMerchantWithdraw->rollBack();
            return ResultWrapper::fail($this->objDMerchantWithdraw->error(), ErrorCode::$dberror);
        }
        //添加平台记录
        if (!empty($plat_log)) {
            $objMMerchantFlow = new MMerchantFlow($this->onlineEnterpriseId, $this->onlineUserId);
            $flowResult = $objMMerchantFlow->add($plat_log);
            if (!$flowResult->isSuccess()) {
                $this->objDMerchantWithdraw->rollBack();
                return ResultWrapper::fail($flowResult->getData(), $flowResult->getErrorCode());
            }
        }
        $this->objDMerchantWithdraw->commit();
        return ResultWrapper::success(true);
    }

    /**
     * Doc: (des="提现记录")
     * User: XMing
     * Date: 2020/12/8
     * Time: 4:53 下午
     * @param array $selectParams
     * @return ResultWrapper
     */
    public function getAll(array $selectParams): ResultWrapper
    {
        $limit = $selectParams['limit'];
        unset($selectParams['limit']);
        $offset = $selectParams['offset'];
        unset($selectParams['offset']);
        $returnData = [
            'data'  => [],
            'total' => 0,
        ];
        $fields = ' * ';
        $countField = ' COUNT(id) as total ';
        $whereSql = '';
        if (isset($selectParams['merchantId']) && !empty($selectParams['merchantId'])) {
            $where = empty($whereSql) ? ' WHERE ' : ' AND ';
            $whereSql .= $where . ' merchantId = ' . $selectParams['merchantId'];
        }
        if (isset($selectParams['type']) && !empty($selectParams['type'])) {
            $where = empty($whereSql) ? ' WHERE ' : ' AND ';
            $whereSql .= $where . ' type = ' . $selectParams['type'];
        }
        if (isset($selectParams['auditStatus']) && !empty($selectParams['auditStatus'])) {
            $where = empty($whereSql) ? ' WHERE ' : ' AND ';
            $whereSql .= $where . ' auditStatus = ' . $selectParams['auditStatus'];
        }
        if ( (isset($selectParams['startTime']) && !empty($selectParams['startTime']))&&(isset($selectParams['endTime']) && !empty($selectParams['endTime'])) ) {
            $where = empty($whereSql) ? ' WHERE ' : '  AND ';
            $whereSql .= $where . ' createTime BETWEEN ' . $selectParams['startTime'] . ' AND '. $selectParams['endTime'];
        }

        if (isset($selectParams['no']) && !empty($selectParams['no'])) {
            $where = empty($whereSql) ? ' WHERE ' : ' AND ';
            $whereSql .= $where . ' no = ' . $selectParams['no'];
        }
        $countSql = 'SELECT ' . $countField . ' FROM ' . $this->objDMerchantWithdraw->get_Table() . $whereSql;

        $sql = 'SELECT ' . $fields . ' FROM ' . $this->objDMerchantWithdraw->get_Table() . $whereSql .' ORDER BY createTime DESC LIMIT ' . $offset . ' , ' . $limit;

        $dbResult = $this->objDMerchantWithdraw->query($sql);
        if ($dbResult === false) {
            return ResultWrapper::fail($this->objDMerchantWithdraw->error(), ErrorCode::$dberror);
        }
        $total = $this->objDMerchantWithdraw->query($countSql);
        foreach ($dbResult as &$value) {
            $value['accountContent'] = json_decode($value['accountContent'], true);
            $value['passMoney'] = 0;
            $value['passOrderNum'] = 0;
            if (!in_array($value['auditStatus'], [StatusCode::$auditStatus['auditNotPass'], StatusCode::$auditStatus['auditing']])) {
                $value['passMoney'] = $value['money'];
                $value['passOrderNum'] = $value['orderNum'];
            }
        }
        $return = [
            'data'  => $dbResult,
            'total' => isset($total[0]['total']) ? $total[0]['total'] : 0,
        ];
        return ResultWrapper::success($return);
    }

    /**
     * Doc: (des="统计")
     * User: XMing
     * Date: 2020/12/9
     * Time: 2:15 下午
     * @param int $status
     * @param int $shopId
     * @param string $fields
     * @return int
     */
    public function statistics(int $status, int $shopId, $fields = 'nowMoney'): int
    {
        $sql = 'SELECT sum(' . $fields . ') as ' . $fields . ' FROM qianniao_merchant_withdraw_' . $this->onlineEnterpriseId . ' 
                WHERE auditStatus = ' . $status;
        $sum = $this->objDMerchantWithdraw->query($sql);
        if ($sum === false) {
            return 0;
        }
        $sum = isset($sum[0][$fields]) ? $sum[0][$fields] : 0;
        return $sum;
    }

}