<?php
require_once __DIR__.'/common.php';
function pp_protect($phase,$newMeal=null){$plan=pp_input('fresh-plan.json');$base=pp_input('baseline.json');$out=[];foreach($plan['steps']as $s)if($s['role']==='protection'&&$s['phase']==='before'){$rec=pp_read($s['db'],$s['SQL'],$s['binds'],$phase.'.'.$s['surface'].'.'.$s['key']);$rows=$rec['rows'];if($s['surface']==='own16'&&$s['key']==='meal_order'&&$newMeal!==null){$new=array_values(array_filter($rows,static function($r)use($newMeal){return (string)$r['id']===(string)$newMeal;}));pp_need(count($new)===1,'Only actual generated new meal excluded from old-set comparison');$rows=array_values(array_filter($rows,static function($r)use($newMeal){return (string)$r['id']!==(string)$newMeal;}));}$expected=$base[$s['surface']][$s['key']];if($s['key']==='ZHCT.exact_config_hashes')pp_need(hash('sha256',pp_json(pp_sort($rows)))===$expected,'Original config full-row SHA protection');else pp_equal($rows,$expected,'Old13/own16 complete native rows '.$s['surface'].'.'.$s['key']);$out[$s['surface'].'.'.$s['key']]=$rec;}pp_need(count($out)===29,'Exactly29 old protection reads');pp_save($phase.'-protected.json',$out);}
function pp_clock(){return pp_read('ZHCT',getenv('PP_SIDE')==='C'?"SELECT TO_CHAR(CURRENT_TIMESTAMP(0),'YYYY-MM-DD HH24:MI:SS') clock0 FROM DUAL":"SELECT DATE_FORMAT(NOW(0),'%Y-%m-%d %H:%i:%s') clock0",[],'single-clock0')['rows'][0]['clock0'];}
function pp_prepaid($label,$id){$c=getenv('PP_SIDE')==='C';$dates=['expire_time','pay_time','ship_time','create_time','update_time'];$lobs=['raw_request_a','raw_request_c','raw_request_b','qrcode_payload'];$sql='SELECT p.*';foreach($dates as $n)$sql.=$c?",TO_CHAR(p.$n,'YYYY-MM-DD HH24:MI:SS.FF6') f_$n":",DATE_FORMAT(p.$n,'%Y-%m-%d %H:%i:%s.%f') f_$n";foreach($lobs as $n)$sql.=",CASE WHEN p.$n IS NULL THEN '1' ELSE '0' END n_$n";$sql.=$c?",TO_CHAR(CURRENT_TIMESTAMP(0),'YYYY-MM-DD HH24:MI:SS') observed_clock0":",DATE_FORMAT(NOW(0),'%Y-%m-%d %H:%i:%s') observed_clock0";$sql.=' FROM ydy_prepay_order p WHERE id=?';$r=pp_read('ZHCT',$sql,[(string)$id],$label);pp_need(count($r['rows'])===1,'Exactly own Prepay row');$row=$r['rows'][0];$fields=array_keys($row);pp_need(count($fields)===37,'Full27 plus5FF6/4NULLbits/clock');foreach($dates as $n)pp_need($row['f_'.$n]===$row[$n].'.000000','Source-aligned Prepay date0 '.$n);foreach($lobs as $n)pp_need($row['n_'.$n]===($row[$n]===null?'1':'0'),'Original complete4LOB null/empty distinction');return $r;}
function pp_defaults($short,$row,$written){$c=getenv('PP_SIDE')==='C';$records=pp_input('fresh-records.json');$table=$c?'YDY_'.$short:'ydy_'.strtolower($short);$cols=array_values(array_filter($records['schema.columns']['rows'],static function($r)use($table){return $r['table_name']===$table;}));pp_need(count($row)===count($cols),'Complete current actual schema row '.$short);$n=0;foreach($cols as $col){$k=strtolower($col['column_name']);pp_need(array_key_exists($k,$row),'Every actual column '.$k);if($k==='id'||in_array($k,$written,true))continue;$d=$col[$c?'data_default':'column_default'];if($c&&is_string($d)){$d=trim($d);if(strtoupper($d)==='NULL')$d=null;elseif(strlen($d)>=2&&$d[0]==="'"&&substr($d,-1)==="'")$d=str_replace("''","'",substr($d,1,-1));}pp_need($d===null?$row[$k]===null:((string)$row[$k]===(string)$d||(is_numeric($row[$k])&&is_numeric($d)&&pp_money($row[$k])===pp_money($d))),'Original actual omitted default/native NULL '.$short.'.'.$k);$n++;}return $n;}
function pp_money($v){$s=(string)$v;pp_need(preg_match('/^-?\d+(?:\.\d+)?$/D',$s),'Exact decimal not epsilon');return strpos($s,'.')===false?$s:rtrim(rtrim($s,'0'),'.');}
function pp_equipment(){$r=pp_read('ZHCT','SELECT * FROM ydy_equipment WHERE code=? OR sn=? ORDER BY id',['CDXPPFORM11_E1','CDXPPFORM11_M1'],'equipment-generated-full31');pp_need(count($r['rows'])===1,'Exact single marker equipment');$row=$r['rows'][0];$plan=json_decode(file_get_contents(pp_base().'/machine-plan.json'),true)['equipment'][getenv('PP_SIDE')];$names=['code','name','type','print_receipt','sn','restaurant_id','status','del_flag','mate_flag','hearttime','create_time','create_by','update_time','update_by'];foreach($names as $i=>$n)pp_need((string)$row[$n]===(string)$plan['binds'][$i],'Actual exact14 device binds '.$n);pp_need(pp_defaults('EQUIPMENT',$row,$names)===16,'AutoID1 and16 other defaults');$id=(int)$row['id'];pp_need($id>0&&$id===pp_saved('prepare-result.json')['generated_ID'],'Real generated equipmentID no guess');pp_save('equipment.json',['id'=>$id,'full'=>$r]);return $id;}
function pp_code_checkpoint(){pp_protect('after-code-real');$response=pp_saved('response-code.json');pp_need($response['status']===200,'Original Store HTTP200');$j=json_decode($response['body'],true);pp_need(is_array($j)&&array_keys($j)===['orderid','torderid','twocode','code','msg'],'Original five-key Store DTO');foreach($j as $v)pp_need(is_string($v),'Store DTO all original strings');pp_need($j['orderid']==='CDXPPFORM11_A1'&&ctype_digit($j['torderid'])&&$j['twocode']==='type=200&torderid='.$j['torderid']&&$j['code']==='1'&&$j['msg']==='成功','Original signed code success not paid');$rec=pp_prepaid('after-code-new-full27',$j['torderid']);$p=$rec['rows'][0];$f=pp_saved('DISPATCH_1.json')['ordered_fields'];$expected=['source'=>1,'device_order_no'=>$f['orderid'],'machid'=>$f['machid'],'equipment_id'=>pp_saved('equipment.json')['id'],'restaurant_id'=>pp_input('baseline.json')['ids']['STORE_R1'],'trackno'=>'P1','goods_name'=>'CDXPPFORM11_COFFEE','price'=>1,'channelid'=>'POC','prepay_status'=>2,'ship_status'=>0,'raw_request_a'=>json_encode($f,JSON_UNESCAPED_UNICODE),'qrcode_payload'=>$j['twocode'],'create_by'=>'api','update_by'=>'api'];foreach($expected as $k=>$v)pp_need((string)$p[$k]===(string)$v,'Original code full physical field '.$k);foreach(['meal_order_id','user_id']as $k)pp_need((int)$p[$k]===0,'Fresh unbound pending Prepay');$native=array_intersect_key($p,array_flip(array_map('strtolower',array_column(array_values(array_filter(pp_input('fresh-records.json')['schema.columns']['rows'],static function($r){return strtoupper($r['table_name'])==='YDY_PREPAY_ORDER';})),'column_name'))));$written=array_keys($expected);$written=array_merge($written,['expire_time','create_time','update_time']);pp_defaults('PREPAY_ORDER',$native,$written);pp_need(strtotime($p['expire_time'])-strtotime($p['create_time'])>=899&&strtotime($p['expire_time'])-strtotime($p['create_time'])<=901,'Original15minute expiry');pp_save('code-checkpoint.json',['id'=>(int)$j['torderid'],'full'=>$rec,'response'=>$response,'pending_unpaid'=>true]);}
function pp_scan_checkpoint(){ $response=pp_saved('response-scan.json');pp_need($response['status']===200,'Original AI HTTP200');$j=json_decode($response['body'],true);pp_need(is_array($j)&&($j['status']??null)===200&&($j['message']??null)==='订单创建成功'&&is_int($j['data']['orderId']??null)&&($j['data']['isPay']??null)===1&&is_string($j['trace_id']??null)&&$j['trace_id']!=='','Original scan envelope/typed pending DTO');$id=$j['data']['orderId'];pp_need($id>0,'Actual new meal ID');pp_protect('after-scan',$id);$code=pp_saved('code-checkpoint.json');$rec=pp_prepaid('after-scan-new-full27',$code['id']);$a=$code['full']['rows'][0];$b=$rec['rows'][0];$allowed=['meal_order_id','meal_order_no','user_id','update_by','update_time','f_update_time','observed_clock0'];foreach($a as $k=>$v)if(!in_array($k,$allowed,true))pp_equal($b[$k],$v,'Prepay full other22/native4LOB conservation '.$k);pp_need((int)$b['meal_order_id']===$id&&(int)$b['user_id']===pp_input('baseline.json')['ids']['STORE_U1']&&$b['update_by']==='miniapp'&&$b['update_time']>$a['update_time']&&$b['update_time']>=pp_saved('scan-clock.json')['clock0']&&$b['update_time']<=$b['observed_clock0'],'Real automatic update_time advance/CAS five deltas');$cols=pp_input('fresh-records.json')['schema.columns']['rows'];$money=[];foreach($cols as $c)if(strtoupper($c['table_name'])==='YDY_MEAL_ORDER'&&preg_match('/decimal|numeric|number/i',$c['data_type']))$money[]=strtolower($c['column_name']);$sql='SELECT m.*';foreach($money as $n)$sql.=',CAST(m.'.$n.' AS CHAR) cast_'.$n;$sql.=' FROM ydy_meal_order m WHERE id=?';$meal=pp_read('ZHCT',$sql,[(string)$id],'scan-new-meal112-and-all-decimal-CAST');pp_need(count($meal['rows'])===1,'Exact new complete meal row');$m=$meal['rows'][0];$physical=array_filter($m,static function($k){return strpos($k,'cast_')!==0;},ARRAY_FILTER_USE_KEY);pp_need(count($physical)===112&&$m['order_no']===$b['meal_order_no']&&(int)$m['source']===8&&(int)$m['pay_status']===10&&(int)$m['order_status']===10&&$m['equipment_code']==='CDXPPFORM11_E1'&&$m['bank_user_name']===''&&$m['remark']==='CDXPPFORM11_COFFEE','Actual112 pending coffee meal/bank default');foreach(['total_price','ori_total_price','order_price','pay_price']as $n)pp_need(pp_money($m['cast_'.$n])==='0.01','Exact positive one-cent server CAST');$written=['order_no','total_price','ori_total_price','order_price','pay_price','pay_method','pay_status','pay_time','meal_date','meal_times','meal_number','bind_id','bind_time','equipment_code','last_meal_time','source','user_id','restaurant_id','user_mobile','user_name','restaurant_method','remark','order_status','create_time','update_time'];pp_need(pp_defaults('MEAL_ORDER',$physical,$written)===86,'All86 nonID actual defaults/nullable conserved');$plan=pp_input('fresh-plan.json');$baseline=pp_input('baseline.json');foreach($plan['steps']as $s)if($s['role']==='money'){$r=pp_read($s['db'],$s['SQL'],$s['binds'],'final-'.$s['label'])['rows'];if($s['key']==='ZHCT.meal_order')$r=array_values(array_filter($r,static function($r)use($id){return (int)$r['id']!==$id;}));pp_equal($r,$baseline['money'][$s['key']]['rows'],'Old .01/.02 exact serverCAST financial chain');}pp_save('scan-checkpoint.json',['id'=>$id,'prepay'=>$rec,'meal'=>$meal,'all_other22_and_LOBs_unchanged'=>true,'old29_unchanged'=>true,'no_payment'=>true]);}
