<?php

/**
 * @link      http://www.u-bo.com
 * @copyright 南京友博网络科技有限公司 
 * @license   http://www.u-bo.com/license/
 */

namespace home\modules\contract\models;

use Yii;
use home\modules\contract\models\Status;
use common\models\User;
use home\modules\contract\models\Category;
use home\modules\receivable\models\Receivable;
use home\modules\receivable\models\Plan;
use home\modules\receivable\models\Billing;
use home\models\PaymentMethod;
use home\modules\customer\models\Customer;
use qcbase\models\Auth;
use yii\base\ErrorException;
use home\modules\contract\models\PaymentInstruction;
use common\models\Common;
use common\models\PermissionScope;

/**
 * This is the model class for table "qc_contract".
 * 
 * 合同模型
 *
 * @property integer $contract_id  (合同ID)
 * @property string $contract_no  (合同编号)
 * @property string $name  (合同名称)
 * @property string $project_no  (项目编号，关联表qc_project)
 * @property string $customer_no  (签约客户编号，关联表qc_customer)
 * @property integer $owner_id  (合同所有人，关联表qc_user)
 * @property integer $signing_time  (签订日期)
 * @property integer $due_time  (到期日期)
 * @property integer $acceptance_time  (验收时间)
 * @property tinyint $maint_period (维保周期)
 * @property integer $begin_time  (维保期开始日期)
 * @property integer $end_time  (维保期结束日期)
 * @property mediumint $method_id  (付款方式，关联qc_payment_method)
 * @property decimal $money  (合同金额)
 * @property decimal $purchase_amount  (外采购金额)
 * @property decimal $hardware_amount  (硬件金额)
 * @property integer $category_id  (合同类型，关联表qc_product_category)
 * @property integer $status_id  (合同状态，关联表qc_contract_status)
 * @property integer $user_id  (创建人，关联表qc_user)
 * @property integer $create_time  (合同登记时间)
 * @property integer $update_time  (更新时间)
 * @property integer $sort  (排序)
 * @property smallint $status  (状态：0 禁用 1开启 99逻辑删除 默认开启)
 * @property text $remark  (备注)
 * @property string $attach_ids  (附件，关联表qc_attachment)
 * @property string $ip  (创建人IP)
 * @property string $real_customer_no  (真实客户编号，关联表qc_customer)
 * @property integer $collator  (核对人)
 * @property integer $collate_time  (核对时间)
 * @property tinyint $collate_status  (核对状态   默认0：未核对    1：已核对)
 * @property tinyint $bill_collate_status  (开票核对状态   默认0：未核对    1：已核对)
 * @property tinyint $money_collate_status (回款核对状态   默认0：未核对    1：已核对)
 * @property varcher $payment_instruction  (付款方式说明)
 *
 * @author zealxd http://blog.u-bo.com
 * @since 0.1
 */
class Contract extends \yii\db\ActiveRecord
{

    public $customer_name;  //签约客户名称
    public $real_customer_name;  //真实客户名称
    public $project_name;   //项目名称
    public $owner_name;     //合同所有人
    public $instruction;   //付款说明

    const STATUS_ENABLE = 1;    //已核对
    const STATUS_DISABLE = 0;    //未核对
    const CHECK_ENABLE = 1; //合同核对状态：已核对
    const CHECK_DISABLE = 0; //合同核对状态：未核对

    /**
     * @inheritdoc
     */

    public static function tableName()
    {
        return '{{%contract}}';
    }

    public function init()
    {
        parent::init();
        $this->purchase_amount = 0;
        $this->hardware_amount = 0;
    }

    /**
     * @inheritdoc
     */
    public function rules()
    {
        return [//'acceptance_time', 'begin_time', 'end_time',  零时移除必填验证
            [['contract_no', 'name', 'customer_name', 'signing_time', 'due_time', 'money', 'category_id', 'status_id', 'owner_name'], 'required'],
            [['owner_id', 'category_id', 'status_id', 'user_id', 'collator', 'create_time', 'update_time', 'sort', 'status', 'method_id', 'collate_time', 'collate_status', 'bill_collate_status', 'money_collate_status', 'maint_period'], 'integer'],
            [['money', 'purchase_amount', 'hardware_amount'], 'number', 'max' => 9999999999],
            [['money', 'purchase_amount', 'hardware_amount'], 'default', 'skipOnEmpty' => true, 'value' => 0],
            [['project_no', 'customer_no', 'real_customer_no'], 'string', 'max' => 64],
            [['contract_no'], 'string', 'max' => 20],
            [['contract_no'], 'unique'],
            [['name'], 'string', 'max' => 100],
            [['attach_ids'], 'string', 'max' => 255],
            [['payment_instruction', 'acceptance_time', 'begin_time', 'end_time'], 'string', 'max' => 1600],
            [['remark', 'real_customer_name'], 'string'],
            [['ip'], 'string', 'max' => 15]
        ];
    }

    /**
     * @inheritdoc
     */
    public function attributeLabels()
    {
        return [
            'contract_id' => 'ID',
            'contract_no' => '合同编号',
            'name' => '合同名称',
            'customer_no' => '签约客户',
            'customer_name' => '签约客户',
            'project_no' => '项目名称',
            'project_name' => '项目名称',
            'owner_id' => '合同所有人',
            'owner_name' => '合同所有人',
            'signing_time' => '签订日期',
            'due_time' => '到期日期',
            'acceptance_time' => '验收日期',
            'begin_time' => '维保期开始日期',
            'end_time' => '维保期结束日期',
            'method_id' => '付款方式',
            'money' => '合同金额(元)',
            'purchase_amount' => '外采购金额(元)',
            'hardware_amount' => '硬件金额(元)',
            'category_id' => '合同类型',
            'status_id' => '合同状态',
            'user_id' => '创建人ID',
            'create_time' => '创建时间',
            'update_time' => '更新时间',
            'sort' => '排序',
            'status' => '状态',
            'remark' => '备注',
            'attach_ids' => '附件',
            'ip' => '创建人IP',
            'real_customer_no' => '真实客户',
            'real_customer_name' => '真实客户',
            'collator' => '核对人ID',
            'collate_time' => '核对时间',
            'collate_status' => '核对状态',
            'payment_instruction' => '付款方式说明',
            'maint_period' => '维保周期(月)'
        ];
    }

    /**
     * 公共搜索所需信息
     */
    public function search()
    {
        return [
            'keywords' => [
                'customer' => '签约客户',
                'realname' => '所有人',
                'name' => '合同名称',
                'contract_no' => '合同编号'
            ],
            'status' => Status::getStatus()
        ];
    }

    /**
     * 插入更新前置操作
     */
    public function beforeSave($insert)
    {
        //更新付款说明表
        $instruction = \Yii::$app->request->post('instruction');
        $sumArr = \yii\helpers\ArrayHelper::getColumn($instruction, 'sum');
        if(array_sum($sumArr) == $this->money){
            if(parent::beforeSave($insert)){
                //判断是否是插入操作
                if($this->isNewRecord){
                    $this->user_id = Yii::$app->user->identity->user_id;
                    $this->create_time = time();
                    $this->ip = Yii::$app->getRequest()->getUserIP();
                } else {
                    $this->update_time = time();
                }
                $this->signing_time = strtotime($this->signing_time);
                $this->due_time = strtotime($this->due_time);
                $this->acceptance_time = strtotime($this->acceptance_time);
                $this->begin_time = strtotime($this->begin_time);
                $this->end_time = strtotime($this->end_time);
                $this->status_name = Status::find()->select('name')->where(['status_id' => $this->status_id])->scalar();
                if($this->collate_status == 1){
                    $this->collator = Yii::$app->user->identity->user_id;
                    $this->collate_time = time();
                }
                return true;
            } else {
                return false;
            }
        } else {
            throw new ErrorException('付款计划总额与合同金额不符，请重新设置！');
            return false;
        }
    }

    public function afterSave($insert, $changedAttributes)
    {
        parent::afterSave($insert, $changedAttributes);

        $request = Yii::$app->request;

        //合同与项目关联的后置操作
//        $command = Yii::$app->db->createCommand();
//        if (!empty($this->project_no)) {
//            //原先项目关联的合同其关联解除
//            $command->update(Project::tableName(), ['contract_no' => ''], 'contract_no = :contract_no', [':contract_no' => $this->contract_no])->execute();
//            //更新关联关系
//            $command->update(Project::tableName(), ['contract_no' => $this->contract_no], 'project_no = :project_no', [':project_no' => $this->project_no])->execute();
//        } elseif (array_key_exists('project_no', $changedAttributes)) {
//            $command->update(Project::tableName(), ['contract_no' => ''], 'project_no = :project_no', [':project_no' => $changedAttributes['project_no']])->execute();
//        }

        $instruction = $request->post('instruction');
        PaymentInstruction::saveInstruction($instruction, $this->contract_no);
        \qcbase\models\ActionLog::insertLog('home', '修改', json_encode($changedAttributes));
    }

    /**
     * 获取合同的付款方式，关联qc_payment_method
     */
    public function getMethod()
    {
        return $this->hasOne(PaymentMethod::className(), ['method_id' => 'method_id'])->select('method_id, name');
    }

    /**
     * 获取合同的状态，关联qc_contract_status
     */
    public function getInfo()
    {
        return $this->hasOne(Status::className(), ['status_id' => 'status_id'])->select('status_id, name');
    }

    /**
     * 获取项目的名称，关联qc_project
     */
//    public function getProject()
//    {
//        return $this->hasOne(Project::className(), ['project_no' => 'project_no'])->select('project_id, name');
//    }

    /**
     * 获取合同所有人名称，关联qc_user
     */
    public function getUser()
    {
        return $this->hasOne(User::className(), ['user_id' => 'owner_id'])->select('realname');
    }

    /**
     * 获取合同状态名称,关联qc_contract_category
     */
    public function getCategory()
    {
        return $this->hasOne(Category::className(), ['cat_id' => 'category_id'])->select('cat_id, name');
    }

    /**
     * 获取当前合同的回款记录,关联qc_receivable
     */
    public function getReceivable()
    {
        return $this->hasMany(Receivable::className(), ['contract_no' => 'contract_no'])->select('rece_id, rece_money, to_date')->orderBy(['to_date' => SORT_ASC])->asArray();
    }

    /**
     * 获取当前合同的回款总金额,关联qc_receivable
     */
    public function getReceivableMoney()
    {
        return $this->hasMany(Receivable::className(), ['contract_no' => 'contract_no'])->sum('rece_money');
    }

    /**
     * 获取当前合同的回款计划,关联qc_receivable_plan
     */
    public function getReceivablePlan()
    {
        return $this->hasMany(Plan::className(), ['contract_no' => 'contract_no'])->select('plan_id, plan_time, plan_money, status')->orderBy(['status' => SORT_ASC, 'plan_time' => SORT_ASC])->asArray();
    }

    /**
     * 获取当前合同的开票记录,关联qc_billing_record
     */
    public function getBilling()
    {
        return $this->hasMany(Billing::className(), ['contract_no' => 'contract_no'])->select('record_id, invoice_time, invoice_money')->orderBy(['invoice_time' => SORT_ASC])->asArray();
    }

    /**
     * 获取当前合同的开票总金额,关联qc_billing_record
     */
    public function getBillingMoney()
    {
        return $this->hasMany(Billing::className(), ['contract_no' => 'contract_no'])->sum('invoice_money');
    }

    /**
     * 获取签约客户信息表，关联qc_customer
     */
    public function getCustomer()
    {
        return $this->hasOne(Customer::className(), ['customer_no' => 'customer_no'])->select('customer_id,name,customer_no, simple_name');
    }

    /**
     * 获取真实客户信息表，关联qc_customer
     */
    public function getRealCustomer()
    {
        return $this->hasOne(Customer::className(), ['customer_no' => 'real_customer_no'])->select('customer_id,name,simple_name,customer_no');
    }

    /**
     * 关联获取合同付款说明
     */
    public function getPaymentInstruction()
    {
        return $this->hasMany(PaymentInstruction::className(), ['contract_no' => 'contract_no'])->orderBy(['sort' => SORT_ASC, 'percentage' => SORT_ASC])->asArray();
    }

    /**
     * 合同状态下拉框
     *
     * @return array $date 合同状态数据
     */
    public static function getContractStatusList()
    {
        $data = [];
        $ContractStatusList = Status::getStatus([], 'status_id, name');
        foreach ($ContractStatusList as $item) {
            $data[$item['status_id']] = $item['name'];
        }
        return $data;
    }

    /**
     *  返回核对状态
     *
     * @return type返回状态
     */
    public static function getCollateList()
    {
        return [
            self::STATUS_ENABLE => '已核对',
            self::STATUS_DISABLE => '未核对',
        ];
    }

    /**
     * 生成合同编号编号
     */
    public static function getNo()
    {
        $prefix = 'HT';
        return $prefix . date('Ymd') . mt_rand(1000, 9999);
    }

    /**
     * 权限审核
     * @param  string  $url     操作URL
     * @param  integer $user_id 用户ID
     */
    public static function readAccess($url = null, $user_id = 0)
    {
        if(empty($url)){
            return false;
        }
        empty($user_id) ? $user_id = \Yii::$app->user->id : $user_id;
        //非超级管理员，需要检测权限
        if(Yii::$app->session->get('isSuperAdmin')){
            return true;
        }
        //检测是否具有某一特定权限
        if(Auth::checkAccess($url, $user_id)){
            return true;
        }
        return false;
    }

    /**
     * 检测合同
     *
     * @param object $data 操作对象
     * @param object $action 当前动作对象
     * @param bool $skipPermission 是否越过主权限判断，适用与没有权限节点的任务配置权限
     * @return bool 返回是否有权限
     */
    public static function checkAccess($data, $action, $skipPermission = false)
    {
        $permission = (is_string($action)) ? $action : Common::getActionPermission($action);
        //如果是管理员
        if(Yii::$app->session->get('isSuperAdmin')){
            return true;
        }

        //如果没有对应主权限
        if(!$skipPermission && !Yii::$app->user->can($permission)){
            return false;
        }

        //有主权限,进行范围过滤,这里只判断负责人在范围内就直接通过
        $scopeUser = PermissionScope::getScopeUser($permission);

        if(false !== $scopeUser){
            if($scopeUser === [] || in_array($data['owner_id'], $scopeUser) || ($data['owner_id'] == 0 && in_array($data['user_id'], $scopeUser))){
                return true;
            }
        }

        return false;
    }

    /**
     * 判断当前合同是否有跟进状态
     */
    public static function judgeFollow($id)
    {
        $time = time();
        $expectTime = time() + 2592000;
        $contract = static::find()->where(['contract_id' => $id])->select('contract_no, due_time, status_id')->one();

        if(!empty($contract)){
            //1.已到期还未结束的(到期时间：合同结束时间与维保结束时间)
            //到期。状态还未修改为完成
            $active_state = Status::findOne($contract['status_id']);
            if($active_state['active_state'] != 1){
                return '-';
            }

            if(($contract['due_time'] < $time) && ($active_state['active_state'] == 1)){
                return "<span style='color:red'>" . date('Y-m-d', $contract['due_time']) . "</span>";
            }

            //2.未来30天有回款计划的 
            $planContract = \home\modules\receivable\models\Plan::find()
                    ->where('contract_no = :contract_no AND status = :status AND plan_time >=:plan_time ', [':contract_no' => $contract['contract_no'], ':status' => 0, 'plan_time' => $time])
                    ->orderBy(['plan_time' => SORT_DESC])
                    ->one();

            if(empty($planContract['plan_time'])){
                return '-';
            }
            if($planContract['plan_time'] < $time){//回款计划超期
                return "<span style='color:red'>" . date('Y-m-d', $planContract['plan_time']) . "</span>"; //30天内绿色
            }
            if($planContract['plan_time'] > $expectTime){//30天后的黑色
                return date('Y-m-d', $planContract['plan_time']);
            }
            if($planContract['plan_time'] <= $expectTime){
                return "<span style='color:green'>" . date('Y-m-d', $planContract['plan_time']) . "</span>"; //30天内绿色
            }
        }
        return '-';
    }

    /**
     * 获取活动的合同编号  HuLimin
     */
    public static function followContract()
    {
        $time = time();
        $expectTime = time() + 2592000;
        $active_state = Status::find()
                ->select('status_id')
                ->where(['active_state' => 1])
                ->asArray()
                ->column();
        $queryWhere = "status_id in(" . implode(',', $active_state) . ") and (due_time<=" . $time . " or end_time<=" . $time . ")";
        $active_no = []; //活动的合同
        $active_no = static::find()
                ->where($queryWhere)
                ->select('contract_no')
                ->asArray()
                ->column();
        $plan_no = []; //有回款计划的
        $plan_no = \home\modules\receivable\models\Plan::find()
                ->where('status = :status AND plan_time >=:plan_time ', [':status' => 0, 'plan_time' => $time])
                ->select('contract_no')
                ->asArray()
                ->column();
        return \yii\helpers\ArrayHelper::merge($active_no, $plan_no);
    }

    /**
     * 统计数据
     */
    public static function SumMoney($query)
    {
        $allNo = $query->select('contract_no')->column();
        $total['invoice_money'] = Billing::find()->where(['contract_no' => $allNo])->sum('invoice_money');
        $total['rece_money'] = Receivable::find()->where(['contract_no' => $allNo])->sum('rece_money');
        return $total;
    }

    /**
     * 修改核对状态
     * @param string $statusName  需要调整的状态名，默认是collate_status核对状态
     */
    public function setCollate($id = 0, $check = 0, $statusName = 'collate_status')
    {
        $command = Yii::$app->db->createCommand();
        $result = $command->update('{{%contract}}', [$statusName => $check], 'contract_id = :contract_id', [':contract_id' => $id])->execute();

        if($result != 0){
            if($check == self::CHECK_DISABLE){
                $url = "<a  href=\"javascript:;\" class=\"set-status\"  data-url=\"" . \yii\helpers\Url::to(['set-check', 'id' => $id, 'check' => self::CHECK_ENABLE, 'status_name' => trim($statusName)]) . "\"><font color=\"red\">未</font></a>";
            } else {
                $url = "<a  href=\"javascript:;\" class=\"set-status\"  data-url=\"" . \yii\helpers\Url::to(['set-check', 'id' => $id, 'check' => self::CHECK_DISABLE, 'status_name' => trim($statusName)]) . "\"><font color=\"green\">已</font></a>";
            }
            $data = ['status' => 1, 'info' => '修改成功', 'url' => $url];
        } else {
            $data = ['status' => 0, 'info' => '修改失败'];
        }
        Yii::$app->response->format = \yii\web\Response::FORMAT_JSON;
        $remark = $statusName . ' 修改为‘' . $check . '’‘' . self::getCollateList()[$check] . '’' . $data['info'];
        @CollateLog::CollateLog('contract', $id, $statusName, $remark);
        return $data;
    }

    /**
     * 获取我的合同
     */
    public static function getMyContract()
    {
        $model = new Contract();
        $query = Contract::find();
        if(!Yii::$app->session->get('isSuperAdmin')){
            $scopeUser = PermissionScope::getScopeUser("contract/contract/index");  //查找合同的权限范围
            $result = \home\modules\customer\models\District::getMyDistrict("customer/customer/index");  //查找客户的权限范围
            if(count($scopeUser) > 0 && count($result) > 0){
                $district = Customer::find()->select('customer_no')->where(['in', 'district_id', $result])->asArray()->all();
                $customerArray = \yii\helpers\ArrayHelper::getColumn($district, 'customer_no');
                $query->andWhere(['or', ['in', 'owner_id', $scopeUser], ['in', 'customer_no', $customerArray]]);
            } else if(count($scopeUser) > 0 && ($result === false)){
                $query->andWhere(['in', 'owner_id', $scopeUser]);
            } else if(count($result) > 0 && ($scopeUser === false)){
                $district = Customer::find()->select('customer_no')->where(['in', 'district_id', $result])->asArray()->all();
                $customerArray = \yii\helpers\ArrayHelper::getColumn($district, 'customer_no');
                $query->andWhere(['in', 'customer_no', $customerArray]);
            } else if(($scopeUser === false) && ($result === false)){
                $scopeUser = [];
                $query->andWhere(['in', 'owner_id', $scopeUser]);
            }
        }
        $listContractNos = $query->select('contract_no')->column();
        return $listContractNos;
    }

    /**
     * 根据合同编号获取合同信息
     * @param type $contract_no 合同编号
     */
    public static function getContractItemByContractNo($contract_no = '')
    {
        if(empty($contract_no)){
            return;
        }
        return static::findOne(['contract_no' => $contract_no]);
    }

}
