525 lines
		
	
	
		
			15 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
			
		
		
	
	
			525 lines
		
	
	
		
			15 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
<?php
 | 
						||
 | 
						||
namespace app\common\model\user\invoice;
 | 
						||
 | 
						||
use app\common\model\BaseModel;
 | 
						||
use app\common\model\school\activity\order\Order;
 | 
						||
use app\common\model\school\activity\order\OrderLog;
 | 
						||
use think\Model;
 | 
						||
 | 
						||
 | 
						||
class Apply extends BaseModel
 | 
						||
{
 | 
						||
 | 
						||
    
 | 
						||
 | 
						||
    
 | 
						||
 | 
						||
    // 表名
 | 
						||
    protected $name = 'user_invoice_apply';
 | 
						||
    
 | 
						||
    // 自动写入时间戳字段
 | 
						||
    protected $autoWriteTimestamp = 'integer';
 | 
						||
 | 
						||
    // 定义时间戳字段名
 | 
						||
    protected $createTime = 'createtime';
 | 
						||
    protected $updateTime = 'updatetime';
 | 
						||
    protected $deleteTime = false;
 | 
						||
 | 
						||
    // 追加属性
 | 
						||
    protected $append = [
 | 
						||
        'status_text',
 | 
						||
        'apply_type_text',
 | 
						||
        'head_type_text',
 | 
						||
        'invoice_type_text',
 | 
						||
        'invoicingtime_text',
 | 
						||
        'createtime_text',
 | 
						||
    ];
 | 
						||
 | 
						||
 | 
						||
    public function getCreatetimeTextAttr($value, $data)
 | 
						||
    {
 | 
						||
        $value = $value ? $value : (isset($data['createtime']) ? $data['createtime'] : '');
 | 
						||
        return is_numeric($value) ? date("Y-m-d H:i:s", $value) : $value;
 | 
						||
    }
 | 
						||
 | 
						||
 | 
						||
 | 
						||
 | 
						||
 | 
						||
 | 
						||
    public function getStatusList()
 | 
						||
    {
 | 
						||
        return ['1' => __('Status 1')
 | 
						||
            , '2' => __('Status 2')
 | 
						||
            , '-3' => __('Status -3')
 | 
						||
        ];
 | 
						||
    }
 | 
						||
 | 
						||
    public function getApplyTypeList()
 | 
						||
    {
 | 
						||
        return ['1' => __('Apply_type 1'), '2' => __('Apply_type 2')];
 | 
						||
    }
 | 
						||
 | 
						||
    public function getHeadTypeList()
 | 
						||
    {
 | 
						||
        return ['personal' => __('Head_type personal'), 'corporate' => __('Head_type corporate')];
 | 
						||
    }
 | 
						||
 | 
						||
    public function getInvoiceTypeList()
 | 
						||
    {
 | 
						||
        return ['ordinary' => __('Invoice_type ordinary'), 'special' => __('Invoice_type special')];
 | 
						||
    }
 | 
						||
 | 
						||
 | 
						||
    public function getStatusTextAttr($value, $data)
 | 
						||
    {
 | 
						||
        $value = $value ? $value : (isset($data['status']) ? $data['status'] : '');
 | 
						||
        $list = $this->getStatusList();
 | 
						||
        return isset($list[$value]) ? $list[$value] : '';
 | 
						||
    }
 | 
						||
 | 
						||
 | 
						||
    public function getApplyTypeTextAttr($value, $data)
 | 
						||
    {
 | 
						||
        $value = $value ? $value : (isset($data['apply_type']) ? $data['apply_type'] : '');
 | 
						||
        $list = $this->getApplyTypeList();
 | 
						||
        return isset($list[$value]) ? $list[$value] : '';
 | 
						||
    }
 | 
						||
 | 
						||
 | 
						||
    public function getHeadTypeTextAttr($value, $data)
 | 
						||
    {
 | 
						||
        $value = $value ? $value : (isset($data['head_type']) ? $data['head_type'] : '');
 | 
						||
        $list = $this->getHeadTypeList();
 | 
						||
        return isset($list[$value]) ? $list[$value] : '';
 | 
						||
    }
 | 
						||
 | 
						||
 | 
						||
    public function getInvoiceTypeTextAttr($value, $data)
 | 
						||
    {
 | 
						||
        $value = $value ? $value : (isset($data['invoice_type']) ? $data['invoice_type'] : '');
 | 
						||
        $list = $this->getInvoiceTypeList();
 | 
						||
        return isset($list[$value]) ? $list[$value] : '';
 | 
						||
    }
 | 
						||
 | 
						||
 | 
						||
    public function getInvoicingtimeTextAttr($value, $data)
 | 
						||
    {
 | 
						||
        $value = $value ? $value : (isset($data['invoicingtime']) ? $data['invoicingtime'] : '');
 | 
						||
        return is_numeric($value) ? date("Y-m-d H:i:s", $value) : $value;
 | 
						||
    }
 | 
						||
 | 
						||
    protected function setInvoicingtimeAttr($value)
 | 
						||
    {
 | 
						||
        return $value === '' ? null : ($value && !is_numeric($value) ? strtotime($value) : $value);
 | 
						||
    }
 | 
						||
 | 
						||
 | 
						||
 | 
						||
    public function getImagesAttr($value, $data)
 | 
						||
    {
 | 
						||
        $imagesArray = [];
 | 
						||
        if (!empty($value)) {
 | 
						||
            $imagesArray = explode(',', $value);
 | 
						||
            foreach ($imagesArray as &$v) {
 | 
						||
                $v = cdnurl($v, true);
 | 
						||
            }
 | 
						||
            return $imagesArray;
 | 
						||
        }
 | 
						||
        return $imagesArray;
 | 
						||
    }
 | 
						||
 | 
						||
 | 
						||
 | 
						||
    public function setImagesAttr($value, $data)
 | 
						||
    {
 | 
						||
        $imagesArray = $value;
 | 
						||
        if (!empty($value) && is_array($value)) {
 | 
						||
            //转成逗号拼接字符串
 | 
						||
            $imagesArray = implode(',', $value);
 | 
						||
        }
 | 
						||
        return $imagesArray;
 | 
						||
    }
 | 
						||
 | 
						||
 | 
						||
    public function user()
 | 
						||
    {
 | 
						||
        return $this->belongsTo('app\admin\model\User', 'user_id', 'id', [], 'LEFT')->setEagerlyType(0);
 | 
						||
    }
 | 
						||
 | 
						||
 | 
						||
 | 
						||
    public function activityorders()
 | 
						||
    {
 | 
						||
        return $this->hasMany(Order::class, 'user_invoice_apply_id', 'id');
 | 
						||
    }
 | 
						||
 | 
						||
 | 
						||
 | 
						||
 | 
						||
    /** 通用详情(后台api版本)
 | 
						||
     * @param $params
 | 
						||
     * @param $trans
 | 
						||
     * @return $this
 | 
						||
     * @throws \Exception
 | 
						||
     */
 | 
						||
    public function detail($id,$show_field=[],$except_field=[]){
 | 
						||
        $row = $this->get($id);
 | 
						||
        if (!$row) {
 | 
						||
            throw new \Exception(__('No Results were found'));
 | 
						||
        }
 | 
						||
        $row->activityorders;
 | 
						||
 | 
						||
 | 
						||
        if($show_field){
 | 
						||
            $row->visible($show_field);
 | 
						||
        }
 | 
						||
        if($except_field){
 | 
						||
            $row->hidden($except_field);
 | 
						||
        }
 | 
						||
 | 
						||
 | 
						||
        return $row;
 | 
						||
    }
 | 
						||
 | 
						||
 | 
						||
 | 
						||
    /** 申请发票
 | 
						||
     * @param $order_no 申请发票的订单号
 | 
						||
     * @param
 | 
						||
     * @param $trans
 | 
						||
     * @throws \Exception
 | 
						||
     */
 | 
						||
    public function add($order_no,$params,$oper_id = 0,$oper_type='user',$check=true,$trans=false){
 | 
						||
 | 
						||
        if (empty($params)) {
 | 
						||
            throw new \Exception(__('Parameter %s can not be empty', ''));
 | 
						||
        }
 | 
						||
 | 
						||
        $params['type'] = $params['type'] ?? '1'; //默认新开
 | 
						||
 | 
						||
        $rule =  [
 | 
						||
//            'user_id'=>'require',
 | 
						||
            'head_type'=>'require',
 | 
						||
            'invoice_type'=>'require',
 | 
						||
            'invoice_header' => 'require',
 | 
						||
            'invoice_reservation_phone' => 'require',
 | 
						||
            'invoice_reservation_email' => 'require',
 | 
						||
        ];
 | 
						||
 | 
						||
        $rule_msg = [
 | 
						||
//            "user_id.require"=>'提交用户必填',
 | 
						||
            "head_type.require"=>'抬头类型必填',
 | 
						||
            "invoice_type.require"=>'发票类型必填',
 | 
						||
            'invoice_header.require' => '发票抬头必填',
 | 
						||
            'invoice_reservation_phone.require' => '发票预留电话必填',
 | 
						||
            'invoice_reservation_email.require' => '发票预留邮箱必填',
 | 
						||
        ];
 | 
						||
 | 
						||
        self::check($params,$rule,$rule_msg);
 | 
						||
 | 
						||
        //个人无法开专用发票
 | 
						||
        if($params['head_type']=='personal' && $params['invoice_type']=='special'){
 | 
						||
            throw new \Exception('个人用户无法开专用发票');
 | 
						||
        }
 | 
						||
 | 
						||
        //企业需要填写纳税人识别号等信息
 | 
						||
        if($params['head_type']=='corporate'){
 | 
						||
            $rule =  [
 | 
						||
                'tax_id'=>'require',
 | 
						||
                'type'=>'require',
 | 
						||
                'bank_deposit'=>'require',
 | 
						||
                'bank_number'=>'require',
 | 
						||
                'enterprise_address'=>'require',
 | 
						||
                'enterprise_phone'=>'require',
 | 
						||
            ];
 | 
						||
            $rule_msg = [
 | 
						||
                'tax_id.require' => '纳税人识别号必填',
 | 
						||
                'type.require' => '开票类型必填',
 | 
						||
                'bank_deposit.require' => '开户银行必填',
 | 
						||
                'bank_number.require' => '银行账号必填',
 | 
						||
                'enterprise_address.require' => '企业地址必填',
 | 
						||
                'enterprise_phone.require' => '企业电话必填',
 | 
						||
            ];
 | 
						||
            self::check($params,$rule,$rule_msg);
 | 
						||
        }
 | 
						||
 | 
						||
 | 
						||
        //是否存在逗号隔开
 | 
						||
        $order_nos = explode(',',$order_no);
 | 
						||
        $order_ids = [];
 | 
						||
        $orders = [];
 | 
						||
        foreach ($order_nos as $orderno){
 | 
						||
            $order = Order::getHaveInvoiceApplyOrder($orderno);
 | 
						||
            if($check){
 | 
						||
                //用户操作权限检测
 | 
						||
                Order::checkOptionAuth($order['id'],$oper_id ,$oper_type);
 | 
						||
            }
 | 
						||
            $order_ids[] = $order->id;
 | 
						||
            $orders[] = $order;
 | 
						||
            $params['user_id'] =  $order->user_id;
 | 
						||
 | 
						||
        }
 | 
						||
        if(empty($order_ids)){
 | 
						||
            throw new \Exception('订单不存在或已开过发票');
 | 
						||
        }
 | 
						||
 | 
						||
        //是单开还是连开
 | 
						||
        if(count($order_ids) >1){
 | 
						||
            $params['apply_type'] = '2';
 | 
						||
            $typeinfo = "(联合开票)";
 | 
						||
        }else{
 | 
						||
            $params['apply_type'] = '1';
 | 
						||
            $typeinfo = "(单独开票)";
 | 
						||
        }
 | 
						||
 | 
						||
 | 
						||
 | 
						||
 | 
						||
 | 
						||
 | 
						||
       //计算合开金额
 | 
						||
         //用户支付金额
 | 
						||
        $params['price'] = Order::where( "id","in",$order_ids)->sum("sub_refundprice");
 | 
						||
         //平台手续费
 | 
						||
        $params['fee_price'] = Order::where( "id","in",$order_ids)->sum("fee_price");
 | 
						||
        if(!$params['price']) throw new \Exception('订单金额异常,该订单无可申请发票金额');
 | 
						||
        //$order_ids 按字典序排序后重新合并成字符串再保存
 | 
						||
        //int数组字典序排序
 | 
						||
        sort($order_ids,SORT_NUMERIC);
 | 
						||
 | 
						||
        $order_ids =  implode(',',$order_ids);
 | 
						||
 | 
						||
        //如果是换开,orderIds不能变
 | 
						||
        if($params['type']=='2'){
 | 
						||
            $invoiceaplpy =  self::where( "order_ids",$order_ids)->find();
 | 
						||
            if(!$invoiceaplpy){
 | 
						||
                throw new \Exception('换开失败,请选择已经开票的记录操作换开');
 | 
						||
            }
 | 
						||
        }
 | 
						||
 | 
						||
 | 
						||
//判断逻辑
 | 
						||
        if($trans){
 | 
						||
            self::beginTrans();
 | 
						||
        }
 | 
						||
        $res = true;
 | 
						||
        try{
 | 
						||
 | 
						||
            //是否采用模型验证
 | 
						||
//            if ($this->modelValidate) {
 | 
						||
//                $name = str_replace("\\model\\", "\\validate\\", get_class($this));
 | 
						||
//                $validate = is_bool($this->modelValidate) ? ($this->modelSceneValidate ? $name . '.add' : $name) : $this->modelValidate;
 | 
						||
//                $this->validateFailException()->validate($validate);
 | 
						||
//            }
 | 
						||
 | 
						||
 | 
						||
            $params["order_ids"] = $order_ids;
 | 
						||
            //添加发票申请
 | 
						||
            $self = new self;
 | 
						||
            $result = $self->allowField(true)->save($params);
 | 
						||
 | 
						||
 | 
						||
            //更新订单发票申请状态
 | 
						||
            Order::where( "id","in",$order_ids)->update([
 | 
						||
                'invoice_status'=>'1',
 | 
						||
                'user_invoice_apply_id'=> $self->id,
 | 
						||
            ]);
 | 
						||
            //逐个发订单日志
 | 
						||
            foreach ($orders as $order){
 | 
						||
                $invoiceaplpy = $order->invoiceaplpy;
 | 
						||
                if($invoiceaplpy){
 | 
						||
                    $invoiceaplpy["status"] = '-3';
 | 
						||
                    $invoiceaplpy->save();
 | 
						||
                    //换开
 | 
						||
                    OrderLog::log($order['id'],"活动订单重新发起了发票申请{$typeinfo},等待发票换开",$oper_id ,$oper_type);
 | 
						||
                }else{
 | 
						||
                    //新开
 | 
						||
                    OrderLog::log($order['id'],"活动订单发起了发票申请{$typeinfo},等待系统开票",$oper_id ,$oper_type);
 | 
						||
                }
 | 
						||
 | 
						||
 | 
						||
            }
 | 
						||
            //合并调用开发票事件
 | 
						||
            $data = [
 | 
						||
                'orders' => Order::where( "id","in",$order_ids)->select(),
 | 
						||
                'invoice_apply' => $self,
 | 
						||
 | 
						||
                'oper_id' => $oper_id,
 | 
						||
                'oper_type' => $oper_type,
 | 
						||
            ];
 | 
						||
            \think\Hook::listen('activity_order_invoice_apply_after', $data);
 | 
						||
 | 
						||
 | 
						||
            if($trans){
 | 
						||
                self::commitTrans();
 | 
						||
            }
 | 
						||
        }catch (\Exception $e){
 | 
						||
            if($trans){
 | 
						||
                self::rollbackTrans();
 | 
						||
            }
 | 
						||
            throw new \Exception($e->getMessage().$e->getFile().$e->getLine());
 | 
						||
        }
 | 
						||
        return $self;
 | 
						||
    }
 | 
						||
 | 
						||
    /** 发票开票(线下)
 | 
						||
     * @param $id 申请的发票id
 | 
						||
     * @param $images 发票展示
 | 
						||
     * @param $desc 开票备注
 | 
						||
     * @param $trans
 | 
						||
     * @throws \Exception
 | 
						||
     */
 | 
						||
    public function examine($id,$images,$desc,$oper_id = 0,$oper_type='user',$check=true,$trans=false)
 | 
						||
    {
 | 
						||
        $self = self::get($id);
 | 
						||
        if(!$self) throw new \Exception('发票申请不存在');
 | 
						||
        //已开票则直接返回
 | 
						||
        if($self["status"] == '2'){
 | 
						||
            return $self;
 | 
						||
        }
 | 
						||
        if(! $desc) throw new \Exception('请填写开票备注');
 | 
						||
        if(! $images) throw new \Exception( '请上传发票图片');
 | 
						||
        //
 | 
						||
        $params = [
 | 
						||
            'status' => '2',
 | 
						||
            'desc' => $desc,
 | 
						||
            'images' => $images,
 | 
						||
            'invoicingtime' => time(),
 | 
						||
        ];
 | 
						||
 | 
						||
        if($check){
 | 
						||
 | 
						||
 | 
						||
        }
 | 
						||
 | 
						||
        if($trans){
 | 
						||
            self::beginTrans();
 | 
						||
        }
 | 
						||
        $res = true;
 | 
						||
        try{
 | 
						||
 | 
						||
            //是否采用模型验证
 | 
						||
//            if ($this->modelValidate) {
 | 
						||
//                $name = str_replace("\\model\\", "\\validate\\", get_class($this));
 | 
						||
//                $validate = is_bool($this->modelValidate) ? ($this->modelSceneValidate ? $name . '.add' : $name) : $this->modelValidate;
 | 
						||
//                $this->validateFailException()->validate($validate);
 | 
						||
//            }
 | 
						||
            //更新发票状态
 | 
						||
            $self->allowField(true)->save($params);
 | 
						||
 | 
						||
            $activityorders = $self->activityorders;
 | 
						||
            foreach ($activityorders as $order){
 | 
						||
                //更新订单发票申请状态
 | 
						||
                $order["invoice_status"] = '2';
 | 
						||
                $order->save();
 | 
						||
                //发订单日志
 | 
						||
                OrderLog::log($order['id'],"活动订单已开票",$oper_id ,$oper_type);
 | 
						||
            }
 | 
						||
 | 
						||
            //调用开发票事件
 | 
						||
            $data = [
 | 
						||
                'orders' => $activityorders,
 | 
						||
                'invoice_apply' => $self,
 | 
						||
                'oper_id' => $oper_id,
 | 
						||
                'oper_type' => $oper_type,
 | 
						||
            ];
 | 
						||
            //开票成功事件
 | 
						||
            \think\Hook::listen('activity_order_invoice_success_after', $data);
 | 
						||
 | 
						||
 | 
						||
            if($trans){
 | 
						||
                self::commitTrans();
 | 
						||
            }
 | 
						||
        }catch (\Exception $e){
 | 
						||
            if($trans){
 | 
						||
                self::rollbackTrans();
 | 
						||
            }
 | 
						||
            throw new \Exception($e->getMessage().$e->getFile().$e->getLine());
 | 
						||
        }
 | 
						||
        return $self;
 | 
						||
 | 
						||
 | 
						||
    }
 | 
						||
 | 
						||
 | 
						||
 | 
						||
 | 
						||
 | 
						||
 | 
						||
 | 
						||
 | 
						||
 | 
						||
    /**得到基础条件
 | 
						||
     * @param $status
 | 
						||
     * @param null $model
 | 
						||
     * @param string $alisa
 | 
						||
     */
 | 
						||
    public static function getBaseWhere($whereData = [], $model = null, $alisa = '',$with = false)
 | 
						||
    {
 | 
						||
 | 
						||
        if (!$model) {
 | 
						||
            $model = new static;
 | 
						||
            if ($alisa&&!$with) $model = $model->alias($alisa);
 | 
						||
        }
 | 
						||
        if ($alisa) $alisa = $alisa . '.';
 | 
						||
//        $alisa = '';
 | 
						||
        $tableFields = (new static)->getTableFields();
 | 
						||
        foreach ($tableFields as $fields)
 | 
						||
        {
 | 
						||
            if(in_array($fields, ["user_id","status"]))continue;
 | 
						||
//            if (isset($whereData[$fields]) && $whereData[$fields]) $model = $model->where("{$alisa}{$fields}", '=', $whereData[$fields]);
 | 
						||
 | 
						||
            if (isset($whereData[$fields]) && $whereData[$fields]){
 | 
						||
                if(is_array($whereData[$fields])){
 | 
						||
                    $model = $model->where("{$alisa}{$fields}", $whereData[$fields][0], $whereData[$fields][1]);
 | 
						||
                }else{
 | 
						||
                    $model = $model->where("{$alisa}{$fields}", '=', $whereData[$fields]);
 | 
						||
                }
 | 
						||
 | 
						||
            }
 | 
						||
 | 
						||
 | 
						||
        }
 | 
						||
        if (isset($whereData['user_id']) && $whereData['user_id']) $model = $model->where("{$alisa}user_id", 'in', $whereData['user_id']);
 | 
						||
 | 
						||
        if (isset($whereData['keywords'])&&$whereData['keywords']) $model = $model->where("{$alisa}invoice_header|{$alisa}tax_id|{$alisa}bank_number|{$alisa}invoice_reservation_phone|{$alisa}invoice_reservation_email", 'like', "%". $whereData['keywords']."%");
 | 
						||
 | 
						||
        if (isset($whereData['time'])&&$whereData['time']){
 | 
						||
            $model = $model->time(["{$alisa}createtime",$whereData['time']]);
 | 
						||
        }
 | 
						||
 | 
						||
 | 
						||
        if (isset($whereData['status']) && $whereData['status']) $model = $model->where("{$alisa}status", 'in', $whereData['status']);
 | 
						||
        if (isset($whereData['not_status']) && $whereData['not_status']) $model = $model->where("{$alisa}status", 'not in', $whereData['not_status']);
 | 
						||
 | 
						||
 | 
						||
 | 
						||
 | 
						||
 | 
						||
        return $model;
 | 
						||
    }
 | 
						||
 | 
						||
 | 
						||
 | 
						||
 | 
						||
    public static function applyList($page, $limit,$params=[]){
 | 
						||
        $with_field = [
 | 
						||
            'base'=>['*'],
 | 
						||
            'user'=>['nickname',"avatar","mobile"],
 | 
						||
            "activityorders.detail"=>['*'],
 | 
						||
        ];
 | 
						||
        $alisa = (new self)->getWithAlisaName();
 | 
						||
        $sort = "{$alisa}.id desc";
 | 
						||
 | 
						||
//        $sort = "id desc";
 | 
						||
 | 
						||
        $serch_where = [];
 | 
						||
        $serch_where = array_merge($serch_where,$params);
 | 
						||
        return (new self)->getBaseList($serch_where, $page, $limit,$sort,$with_field);
 | 
						||
    }
 | 
						||
 | 
						||
 | 
						||
}
 |