<?php
namespace model\pro;
use model\sample\sample;
use model\pro\pro;
use model\element;
class codeRule extends \model\element
{
    public $table = 'pro_code_rule';
    public $key = 'pcr_id';
    public $brand;
	public function __construct($elecfg='pro_code_rule')
    {
        $this->brand = [
            2 => 'GSP',
            4 => 'G',
            5 => 'NCV',
            6 => 'ENERTEK',
        ];
		$this->pro = new pro();
		parent::__construct($elecfg);
	}

	/**
	 * 通过属性集合住创建产品CODE
	 * @param array $values 属性集合[
	 	s_cate, s_usa_make, s_procode_ext, s_procode_a, s_procode_b, s_procode_c
	 ]
	 * @param string $innum 内部编码
	 * @param string $ruleId 规则ID,默认0 取属性集合中对应的规则
	 * @param string $seq 指定流水
	 * @return string
	 */
	public function createCodeByValues($values,$innum,$ruleId=0,$_outnum='',$seq='')
    {
        $cate = $values['s_cate'];
        $usaMake = $values['s_usa_make'];
        $ext = $values['s_procode_ext'];
        $eleExt = new element('pro_code_ext');
        $extHasMake = $eleExt->getRowByKey($ext)['hasmake'];
        $eleArea = new element('m_area');

        if(empty($cate)){
            //exitJson('没有定义[品名]');
			return ['code'=>0,'msg'=>'没有定义[品名]'];
        }

		$data = [];
        //根据内部编码生成GSP新编码
        $where = [
           'pcr_enable'=> 1,
           'pcr_am'=> 0,
           'pcr_type'=> 0,
           'pcr_gsp_brand'=> 0,
           'pcr_cate'=> $cate,
           'pcr_ext'=> $ext,
        ];
        if(!empty($extHasMake) && !empty($usaMake)){
            //$where['pcr_make'] = $usaMake;
        }
        $where['ORDER'] =[
            'pcr_id'=>'DESC',
        ];
		if($ruleId==0){
	        $ruleRow = $this->db->get($this->table,'*',$where);
		}else{
	        $ruleRow = $this->db->get($this->table,'*',[$this->key=>$ruleId]);
		}
        if(empty($ruleRow) && empty($_outnum)){
			$msg = 'createCodeByValues() 没有找到符合条件的GSP新编码规则:' . json_encode([
				'values' => $values,
				'innum' => $innum,
				'ruleId' => $ruleId,
				'_outnum' => $_outnum,
				'seq' => $seq
			], JSON_UNESCAPED_UNICODE);
			errorLog($msg, 'autoCode');
			return ['code'=>0,'msg'=> $msg];
        }
		if($_outnum==''){
			$outnum = $this->getCodeByRuleFromSample($ruleRow['pcr_rule'],$values,$innum,$seq);
		}else{
			$outnum = [
				'code'=>$_outnum,
				'seq'=>$seq,
				'seq_group'=>'',
				'seq_must'=> empty($seq),
			];
		}
		if(empty($outnum['code'])){
			return ['code'=>0,'msg'=>'生成编码失败'];
		}
		$data['OUTNUM']  = [
			'areaId' => 0,
			'areaName' => '',
			'brandId'=> 2,
			'brandName'=> 'OUTNUM',
			'num' => $outnum['code'],
			'seq' => $outnum['seq'],
			'seq_group' => $outnum['seq_group'],
			'seq_must' => $outnum['seq_must'],
		];
        //生成其他品牌编码
        $where = [
           'pcr_enable'=> 1,
           'pcr_am'=> 0,
           'pcr_gsp_brand[>]'=> 0,
           'pcr_cate'=> $cate,
           'pcr_ext'=> $ext,
        ];
        $ruleRows = $this->db->select($this->table,'*',$where);
        foreach($ruleRows as $k=>$row){
			$i=$k+1;
            if(!empty($row['pcr_area'])){
                $tRow = $eleArea->getRowByKey($row['pcr_area']);
                $areaId = $tRow['ma_id'];
                $areaName = $tRow['name'];
				
            }else{
                $areaId = 0;
                $areaName = '';
            }
            if($row['pcr_type']==0){
                $code = $this->createCodeFromNum($innum, $row['pcr_rule']);
            }else{
                $code = $this->createCodeFromNum($outnum['code'], $row['pcr_rule']);
            }
			$data[$this->brand[$row['pcr_gsp_brand']]][]  = [
				'areaId' => $areaId,
				'areaName' => $areaName,
				'brandId'=> $row['pcr_gsp_brand'],
				'brandName'=> $this->brand[$row['pcr_gsp_brand']],
				'num' => $code
			];
        }
		return ['code'=>1,'data'=>$data];
	}

	/**
	 * 通过样品创建产品CODE
	 * @param string $plmseq 流水号
	 * @param string $innum 内部编码
	 * @param string $ruleId 规则ID，默认0 根据样品参数查自动规则
	 * @param string $seq 指定流水
	 * @return string
	 */
	public function createCode($plmseq,$innum,$ruleId=0,$outnum='',$seq='')
    {
        $sample = new sample($plmseq);
        $sampleRow = $sample->getRowByFieldValue('s_plmseq',$plmseq,$ruleId);
        if(empty($sampleRow)){
            //exitJson('没有找到此流水号的样品');
			return ['code'=>0,'msg'=>'没有找到此流水号的样品'];
        }
		return $this->createCodeByValues($sampleRow,$innum,$ruleId,$outnum,$seq);
    }

	/**
	 * 通过样品创建产品
	 * @return string
	 */
	public function getCodeByRuleFromSample($rule,$values,$innum,$seq)
    {
        //PAD[S:001-110]AK
        $rule = strtoupper($rule);
        $code = $rule;
		$seqInt = 0;
		$seq_must = false;
        preg_match_all('/\[([^\[|\]]+)\]/', $rule, $res);
        $m = new element('m_make');
        $a = new element('pro_code_a');
        $b = new element('pro_code_b');
        $c = new element('pro_code_c');
        foreach($res[1] as $k=>$v){
            $v = trim($v);
            if(substr($v,0,1)=='M'){
				$t = substr($v,1,1);
                $makeId = $values['s_usa_make'];
                if(!empty($makeId)){
                    $tRow = $m->getRowByKey($makeId);
					$cf = 'mk_code_'.strtolower($t);
                    if($tRow[$cf]!='')
                        $code = str_replace('['.$v.']',$tRow[$cf],$code);
                    else
                        $code = str_replace('['.$v.']','',$code);
                }else{
                    $code = str_replace('['.$v.']','',$code);
                }
            }else if($v=='A'){
                $tRow = $a->getRowByKey($values['s_procode_a']);
                if($tRow['code']!='')
                    $code = str_replace('[A]',$tRow['code'],$code);
                else
                    $code = str_replace('[A]','',$code);
            }else if($v=='B'){
                $tRow = $b->getRowByKey($values['s_procode_b']);
                if($tRow['code']!='')
                    $code = str_replace('[B]',$tRow['code'],$code);
                else
                    $code = str_replace('[B]','',$code);
            }else if($v=='C'){
                $tRow = $c->getRowByKey($values['s_procode_c']);
                if($tRow['code']!='')
                    $code = str_replace('[C]',$tRow['code'],$code);
                else
                    $code = str_replace('[C]','',$code);
            }else if(substr($v,0,2)=='S:'){
                $seq_must = true;
                if(empty($seq)){
                    $tmp = explode('-',substr($v,2));
                    $start = $tmp[0];
                    $end = $tmp[1];
                    $len = strlen($start);
    				$seqInt = $this->pro->getSeqByCate($values['s_cate'],ltrim($start,'0')*1,ltrim($end,'0')*1);
                    $seqStr = str_pad($seqInt,$len,'0',STR_PAD_LEFT);
                }else{
                    $seqInt = $seq*1;
                    $seqStr = $seqInt;
                }
                $code = str_replace('['.$v.']',$seqStr,$code);
            }else if(substr($v,0,4)==='SIN:'){
                $seq_must = true;
				$p = explode('-',substr($v,4));
				$p[0] = $p[0]*1;
				$p[1] = !empty($p[1]) ? $p[1]*1 : strlen($innum);
				$start = $p[0] * 1 -1;
				$end = $p[1] * 1 -1;
				$len = $end - $start + 1;
				$seqInt = ltrim(substr($innum,$start,$len),'0');
				$code = str_replace('['.$v.']','',$code).$seqInt;
            }else if( is_numeric(substr($v,0,1)) ){
				$p = explode('-',$v);
				$p[0] = $p[0]*1;
				$p[1] = !empty($p[1]) ? $p[1]*1 : strlen($innum);
				$start = $p[0] * 1 -1;
				$end = $p[1] * 1 -1;
				$len = $end - $start + 1;
				$code = str_replace('['.$v.']',substr($innum,$start,$len),$code);
			}
       }
	   if($this->getCheckCode($code)){
			$msg = 'getCodeByRuleFromSample() ' . lg('自动编码') . ': ' . $code . ' ' . lg('已经被使用');
			errorLog($msg, 'autoCode');			
			exitJson($msg);
	   }
       return ['seq'=>$seqInt, 'seq_group'=>0, 'seq_must'=>$seq_must, 'code'=>$code];
    }

	/**
	 * getCheckCode
	 * @param string $code
	 * @return bool
	 */
	public function getCheckCode($code)
    {
		return $this->db->has('p_code',['pc_outnum'=>$code]);
	}

	/**
	 * 通过编码创建编码
	 * @param string $no
	 * @return string
	 */
	public function createCodeFromNum($no,$rule)
    {
		if($no==''){
			exitJson(lg('号码不能为空[createCodeFromNum]'));
		}
        $rule = strtoupper($rule);
        $code = $rule;
        $codeArr = [];
        preg_match_all('/\[([^\[|\]]+)\]/', $rule, $res);
        $i = 0;
        foreach($res[1] as $k=>$v){
            $p = explode('-',$v);
			if(!is_numeric($p[0])){
				exitJson($rule.' '.lg('不适用于条件规则'));
			}
			$p[0] = $p[0]*1;
			$p[1] = !empty($p[1]) ? $p[1]*1 : strlen($no);
            $start = $p[0] * 1 -1;
			$end = $p[1] * 1 -1;
            $len = $end - $start + 1;
            $code = str_replace('['.$v.']',substr($no,$start,$len),$code);
        }
		return $code;
	}
	
    /**
     * 获取下一条条码
	 * @return string|false
     */
    public function getNextBarCode()
    {
        $barCode = $this->db->get('pro_barcode','*',['pb_active' => 1]);

        if(empty($barCode))
        {
            $this->error = lg('当前没有激活的企业商品编码');
            return false;
        }

        if($barCode['pb_use_total'] > 9999 )
        {
            $this->error = lg('企业商品编码使用次数超过了9999次');
            return false;
        }

        $num = $barCode['pb_com_code'].sprintf("%04d", $barCode['pb_use_total'] + 1);
        $result = $this->codeAlgorithm($num);
        if($result!=false){
            //条码计算+1
            $this->db->update('pro_barcode',['pb_use_total[+]' => 1],['pb_id' => $barCode['pb_id']]);
        }
        return $result;
    }
    
    /**
     * 生成条码算法
     * @return int
     */
    public function codeAlgorithm(string $num)
    {
        //$str= 694133840010 测试样例
        //MOD(3,2) = 3 / 2 的余数
        //c = SUMPRODUCT(MID(C9,ROW($1:$6)*2,1)*3)
        //b = SUMPRODUCT(MID(C9,ROW($1:$6)*2-1,1)*1)
        //a = c+b
        //补位公式=10-MOD($a,10)
        if(!is_numeric($num) || strlen($num) < 10)
        {
            $this->error = lg('要生成的条形码格式不正确');
            return false;
        }

        $group1 = 0;
        for($i=1;$i<=6;$i++){
            $pos = $i * 2 -1;
            $group1 = intval($num[$pos-1])*1 + $group1;
        }
        $group2 = 0;
        for($i=1;$i<=6;$i++){
            $pos = $i * 2;
            $group2 = intval($num[$pos-1])*3 + $group2;
        }
        $result = 10 - (($group1 + $group2) % 10);
        $result = $num.substr($result,-1,1);
        return $result;
    }
    
	
	/**
	 * 生成条码
	 * @param string $ids
	 * @return bool
	 */
	public function buildBarCode($ids)
    {
        if($ids=='') return false;
        $ids = explode(',',$ids);
        $barCode = $this->db->get('pro_barcode','*',['pb_active' => 1]);
        if($barCode['pb_use_total'] > 9000 )
        {
    		//消息记录与在线提醒
    		$msg = [
    			'amsg_title'=> '条码次数警告',
    			'amsg_body'=> '企业商品编码使用次数到达了 9000 次',
    		];
    		makeOne(\model\message::class)->send([getOpuser()],$msg);
    		socketSendMsg([getOpuser()],$msg);
        }
       
        //$rows = $this->db->select('p_code_number',['pcn_id'],['pcn_id'=>$ids,'pcn_pf_id[!]'=>3,'OR'=>['pcn_barcode'=>'','pcn_barcode'=>null]]);
		$sql = "select * from p_code_number where pcn_id in({1}) and pcn_pf_id<>3 and (pcn_barcode='' or pcn_barcode is null)";//qg
        $rows = $this->db->query(qgprintf($sql,implode(',',$ids)))->fetchAll();
        $this->db->begin();
        foreach($rows as $row){
            $barCode = $this->getNextBarCode();
            if($barCode==false){
				exitJson($row['pcn_number'].lg('条码生成失败'));
				//continue;
                /*$this->db->rollBack();
                return false;*/
            }
            $this->db->update('p_code_number',['pcn_barcode'=>$barCode],['pcn_id'=>$row['pcn_id']]);
            $this->db->update('pro_numidx',['pn_barcode'=>$barCode],['pn_pf_id'=>$row['pcn_pf_id'],'pn_formart'=>$row['pcn_format']]);
        }
        return $this->db->end();
    }    
    
	
	/**
	 * 自动生成条码
	 * @param array $ids
	 * @return bool
	 */
	public function autoBuildBarCode($ids)
    {
        if(empty($ids)) return false;
        if(is_string($ids)) $ids = explode(',',$ids);
        $join = [
            '[>]p_code(pc)'=> ['pcn.pcn_pc_id'=>'pc_id'],
            '[>]pro_cate(cate)'=> ['pc.pc_cate'=>'id'],
        ];
        
        $where = [
            'pcn_id'=>$ids,         
            'autobarcode'=>1,         //品名设置了自动条码
            'pcn_pf_id'=>[2,4],       //只有GSP和G品牌参入
            'pc_rule_1[!]'=>'1',      //有北美编码规则的不参入
            'pc_state_main[!]'=>'Y3', //主状态 客户专用的不参入
        ];
        $rows = $this->db->select('p_code_number(pcn)',$join,['pcn_id'],$where);
        if($rows){
            $rows = array_column($rows,'pcn_id');
            $autoIds = implode(',',$rows);
            $this->buildBarCode($autoIds);
        }
    }    
	
	/**
	 * 区域&本地码 删除
	 * @param string $ids
	 * @return bool
	 */
	public function codeAreaNumberDeleteRows($ids)
    {
        if($ids=='') return false;
        $ids = explode(',',$ids);
        $this->db->begin();
        if(\p::isAdmin()){
            $rows = $this->db->select('p_code_number','*',['pcn_id'=>$ids,'OR'=>['pcn_check2'=>0,'pcn_pf_id[!]'=>[2,3]]]);
            foreach ($rows as $row){
                $this->db->delete('pro_numidx',['pn_p_id'=>$row['pcn_pc_id'],'pn_pf_id'=>$row['pcn_pf_id'],'pn_number'=>$row['pcn_number']]);
                $this->db->delete('p_code_number',['pcn_id'=>$row['pcn_id']]);
            }
        }else{
            $rows = $this->db->select('p_code_number','*',['pcn_id'=>$ids,'pcn_check2'=>0]);
            foreach ($rows as $row){
                $this->db->delete('pro_numidx',['pn_p_id'=>$row['pcn_pc_id'],'pn_pf_id'=>$row['pcn_pf_id'],'pn_number'=>$row['pcn_number']]);
            }
            $this->db->delete('p_code_number',['pcn_id'=>$ids,'pcn_check2'=>0]);
        }
        return $this->db->end();
    }    
	
	/**
	 * 区域&本地码 审核
	 * @param string $ids
	 * @param bool $autobarcode 是否自动条码
	 * @return bool
	 */
	public function codeAreaNumberCheck2($ids,$autobarcode=false)
    {
        if($ids=='') return false;
        //自动条码
        if($autobarcode==true){
 	        $this->autoBuildBarCode($ids); 
        }
        $this->db->begin();
        $sql = qgprintf("SELECT pcn.*,pc_p_id FROM p_code_number pcn
                JOIN `p_code` pc ON pcn.pcn_pc_id > 0 AND pcn.pcn_pc_id = pc.pc_id
                WHERE ck3=1 AND pcn_check2 = 0 AND pcn.`pcn_id` IN ({1})
                ",$ids);
        $rows = $this->db->query($sql)->fetchAll();
		$iocrm = new \model\iocrm();
        foreach($rows as $row)
		{
            $data = [
                'pn_p_id'=>$row['pc_p_id'],
                'pn_is_gsp'=>1,
                'pn_pf_id'=>$row['pcn_pf_id'],
                'pn_number'=>$row['pcn_number'],
                'pn_formart'=>$row['pcn_format'],
                'pn_ma_id'=>$row['pcn_ma_id'],
                'pn_barcode'=>$row['pcn_barcode'],
                'pn_type'=>'none',
                'ckuser2'=>getOpuser(),
                'opuser'=>getOpuser(),
                'cktime2'=>getNowTime(),
                'create_time'=>getNowTime(),
                'update_time'=>getNowTime()
            ];
            $this->db->replace('pro_numidx',$data,['pn_p_id','pn_mk_id','pn_pf_id','pn_formart'],['create_time']);
            if($row['pcn_pf_id']=='5'){
                //编码类型  ncv(ENERTEK品牌) 
                $this->db->update('pro',['p_numtype'=>'ncv'],['p_id'=>$row['pc_p_id']]);
            }
            $this->db->update('p_code_number',['pcn_check2'=>1],['pcn_id'=>$row['pcn_id'],'pcn_check2'=>0]);
			if(!in_array($row['pcn_pf_id'], [2,3]))
				$iocrm->crmCodeNumber($row['pcn_id'], 'A');
        }
        return $this->db->end();
    }


	/**
	  * @method 生成编码
	  * @param  ids  string  [必填] pcn_id  多个逗号分隔
	  * @author soul
	  */
	public function buildAreaCode($idArr, $auto = 1, $pcr_id = 0)
	{
		if(!empty($idArr))
		{
			$where = [
				'pc.ck3'=>1,					
				'pcn.pcn_id'=>$idArr,
				'GROUP'=>'pc.pc_id'
			];
			$join = ["[><]p_code_number(pcn)" => ["pc.pc_id" => "pcn_pc_id"]];
			$rows = $this->db->select('p_code(pc)', $join, 'pc.*', $where);
			$codeRule = new \model\pro\codeRule();
			$this->db->begin();
			foreach($rows as $pcArr)
			{
				$pc_id = $pcArr['pc_id'];
				if(!empty($pcArr['pc_samseq']))
				{
					if($auto)
					{
						$codeArr = $codeRule->createCode($pcArr['pc_samseq'], $pcArr['pc_innum'],'',$pcArr['pc_outnum'],$pcArr['pc_seq']);
					}
					else
					{
						$codeArr = $codeRule->createCode($pcArr['pc_samseq'], $pcArr['pc_innum'], $pcr_id,$pcArr['pc_outnum'],$pcArr['pc_seq']);
					}
				}
				else
				{
					$ruleArr = [
						's_cate'=>$pcArr['pc_cate'],
						's_procode_ext'=>$pcArr['pc_rule_1'],
						's_procode_a'=>$pcArr['pc_rule_a'],
						's_procode_b'=>$pcArr['pc_rule_b'],
						's_procode_c'=>$pcArr['pc_rule_c'],
						's_usa_make'=>$pcArr['pc_usa_make'],
					];
					if($auto)
					{
						$codeArr = $codeRule->createCodeByValues($ruleArr, $pcArr['pc_innum'],'',$pcArr['pc_outnum'],$pcArr['pc_seq']);
					}
					else
					{
						$codeArr = $codeRule->createCodeByValues($ruleArr, $pcArr['pc_innum'], $pcr_id,$pcArr['pc_outnum'],$pcArr['pc_seq']);
					}
				}
				if($codeArr['code']==1)
				{
					$opuser = getOpuser();
					$datetime = getNowTime();

					$rows = $this->db->select('p_code_number','*',['pcn_pc_id'=>$pc_id]);
					$has = [];
					foreach($rows as $cv)
					{
						$unikey = $cv['pcn_pf_id'].'@'.$cv['pcn_format'];
						$has[$unikey] = $cv['pcn_id'];
					}
					$newArr = [];
					foreach($codeArr['data'] as $fname=>$tarr)
					{
						if($fname == 'OUTNUM') continue;
						foreach($tarr as $cv)
						{
							if(empty($cv['num'])) continue;
							$add = [
								'pcn_pc_id'=>$pc_id,
								'pcn_pf_id'=>$cv['brandId'],
								'pcn_number'=>$cv['num'],
								'pcn_format'=>formatNum($cv['num']),
								'pcn_ma_id'=>$cv['areaId'],
							];
							$unikey = $add['pcn_pf_id'].'@'.$add['pcn_format'];
							$newArr[] = $unikey;
							if(!empty($has[$unikey]))
							{
								$this->db->update('p_code_number',$add, ['pcn_id'=>$has[$unikey]]);
							}
							else
							{
								if($this->db->has('p_code_number',[
									'pcn_pc_id'=>$pc_id,
									'pcn_pf_id'=>$cv['brandId'],
									'pcn_ma_id'=>$cv['areaId'],
								])){
									exitJson($pcArr['pc_outnum'].lg('已经存在').$cv['brandId'].lg('品牌记录'));
								}else{
									$this->db->insert('p_code_number',$add);
								}
							}
						}
					}
				}else{
					dump($codeArr['msg']);
				}
			}
			$this->db->end();
		}
		return [];
	}
	
	/**
	  * @method 检测编码规则
	  */
	public function check2($id,$data){
		$where = [
                //'pcr_am'=>$data['pcr_am'],
                //'pcr_type'=>$data['pcr_type'],
                'pcr_gsp_brand'=>$data['pcr_gsp_brand'],
                'pcr_cate'=>$data['pcr_cate'],
                'pcr_area'=>$data['pcr_area'],
                'pcr_ext'=>$data['pcr_ext'],
		];
		if($id){
			$where['pcr_id[!]'] = $id;
		}
        if($this->db->has('pro_code_rule',$where)){
            return [false,lg('此品类已有规则被定义'). ': ' . $value .' '];
        }
	    return [true,''];
	}
	/**
	  * @method 检测编码规则
	  */
	public function check($id,$field,$value){
	    if($field=='pcr_rule'){
	        if($this->db->has('pro_code_rule',['pcr_type'=>0,'pcr_rule'=>$value,'pcr_id[!]'=>$id])){
	            return [false,lg('根据内部编码规则中已存在'). ': ' . $value .' '];
	        }else{
    	        preg_match('/\[S:(.*?)\]/i', $value, $m);
    	        if(isset($m[1]) && $rows = $this->db->select('pro_code_rule','*',['pcr_type'=>0,'pcr_id[!]'=>$id])){
    	            list($start,$end) = explode('-',$m[1]);
	                $v_start = ltrim($start,'0') * 1;
	                $v_end = ltrim($end,'0') * 1;
	                $v_lter = str_replace('[S:'.$m[1].']','',strtoupper($value));
    	            foreach($rows as $row){
        	            $rule = $row['pcr_rule'];
        	            preg_match('/\[S:(.*?)\]/i', $rule, $m);
        	            if(isset($m[1]) && !empty($m[1])){
        	                list($start,$end) = explode('-',$m[1]);
        	                $start = ltrim($start,'0') * 1;
        	                $end = ltrim($end,'0') * 1;
        	                $lter = str_replace('[S:'.$m[1].']','',strtoupper($rule));
        	                if( $v_lter == $lter &&  
        	                    (($start <= $v_start && $end >= $v_start) || ($start <= $v_end && $end >= $v_end))
        	                ){
        	                    return [false,lg('根据内部编码规则中已存在重叠规则'). ': ' . $rule .' '];
        	                }
        	            }
    	            }
    	        }
	        }
	    }
	    return [true,''];
	}	
	
}