<?php
###################################################################################################
## 立吉富電子發票模組
## Design Time to Start : 2019/03/15
## Design By Baymax
## Ver 1.1
## 由於立吉富電子發票廠上更新伺服器, 於 2019 年度起，只能採用 TSL 1.2 SSL 連線至伺服端
## 注意事項：
## 伺服器端 - 直接更新 cURL 套件即可, yum update CURL
##     最少更新至 curl-7.19.7-53.el6_9.x86_64 版, 一般正常狀況下, NSS 一並自動更新至 3.27.1 版
##     可透過 rqm -qa | grep 'curl' 確認套件資訊
## 程式端 - 
## (1) 連結網址最未端需加上「?WSDL」, 否會出現 Mismatched tag(標記不匹配) 的錯誤訊息
## (2) 進行實體化連結時，還給於第二參數 true , 代表使用 WSDL 格式為主，若未定義即會造執行反傳值錯誤
## (3) 由於使用的連線為 TSL 1.2 版，如果為指定 cURL 連線，預設採用 TSL 1.0 版為主
##     需在初實化 nusoap 後, 給於定義 setCurlOption(CURLOPT_SSLVERSION, '6') 即可
###################################################################################################
class PayNow {
	## 定義物件模組內成員變數
	var $PMEM;

	## 基本建構式
	## V1.1 2019/03/15
	function __construct($PMEM='') {
		## 假設沒有任何實體化時，以立吉富測試環境為標準定義為主
		## 正式 URL \ https://invoice.paynow.com.tw/PayNowEInvoice.asmx
		if($PMEM == '') {
			## 測試環境定義
			$PMEM['SOAP']['PayNow'] = array('ID'=>'28229955', 'PWD'=>'28229955', 'SURL'=>'https://testinvoice.paynow.com.tw/PayNowEInvoice.asmx?WSDL');
			$PMEM['config']['SP']['LRP'] = '';
			$PMEM['RRA']['Type'] = '1';
		} 

		if($PMEM != '') {
			## 正式環境定義
			$this->PMEM = $PMEM;
			$PMEM['SOAP']['PayNow']['SURL'] = 'https://invoice.paynow.com.tw/PayNowEInvoice.asmx?WSDL';
			$this->PMEM['config']['SP']['LRP'] = '';
		}
		
		## 建立對伺服器連結
		if($this->PMEM != '')
			$this->ConnectionAPI();
	}## __construct($PMEM='') end

	## 連線方法
	## v1.1 2019/03/15
	function ConnectionAPI() {
		## 確認 SOAP 套件是否存在，並載入套件
		if(file_exists($this->PMEM['config']['SP']['LRP'].'nusoap/nusoap.php')) {
			require_once $this->PMEM['config']['SP']['LRP'].'nusoap/nusoap.php';
		} else {
			$this->RRAF('ConnectionAPI() : Nusoap 套件檔案不存在', '201903151019');
		}

		## 必須 Nusoap 套件 存在才可執行以下程序
		if($this->PMEM['RRA']['Type'] == '1') {
			$this->PMEM['OBJ']['SOAP'] = new nusoap_client($this->PMEM['SOAP']['PayNow']['SURL'], true);
			$this->PMEM['OBJ']['SOAP']->setCurlOption(CURLOPT_SSLVERSION, '6');
			$this->PMEM['OBJ']['SOAP']->soap_defencoding =  'UTF-8' ;
			$this->PMEM['OBJ']['SOAP']->decode_utf8      =  false ;
			$this->PMEM['OBJ']['SOAP']->xml_encoding     =  'UTF-8' ;
			if($this->PMEM['OBJ']['SOAP']->getError()) {
				$this->RRAF("__construct() : ".$this->PMEM['OBJ']['SOAP']->getDebug(), '201903291611');
			}
		}
	}## ConnectionAPI() end

	## 取得發表連線網址(發票號碼)
	## Invoice Get Receipt Link
	## V1.1 2019/03/29
	function IGRL($InvoiceNo='') {
		## 判斷是否在建立連線時正確, 並且提供要取得連線的發票號碼

		if($InvoiceNo != '' and $this->PMEM['RRA']['Type'] == '1') {
			$params = array('mem_cid' => $this->PMEM['SOAP']['PayNow']['ID'], 'InvoiceNo'=>$InvoiceNo);
			$result = $this->PMEM['OBJ']['SOAP']->call("Get_InvoiceURL_I", $params);
			if($this->PMEM['OBJ']['SOAP']->getError()) {
				$this->RRAF("IGRL() : ".$this->PMEM['OBJ']['SOAP']->getDebug(), '201903291610');
			} else {
				return $result['Get_InvoiceURL_IResult'];
			}
		} else {
			$this->RRAF("IGRL() : Connection Error and Parameter Or Construct error.", '201903291636');
		}
	}## IGRL($InvoiceNo='') end

	## 取得發表連線網址(商家自訂編號模式)
	## Get Receipt Link
	## V1.1 2019/03/29
	function GRL($Order='') {
		# 判斷是否有參數值及建構式暫存執行判斷碼為 '1'
		if($Order != '' and $this->PMEM['RRA']['Type'] == '1') {
			$params = array('mem_cid' =>$this->PMEM['SOAP']['PayNow']['ID'], 'OrderNo'=>$Order);
			$result = $this->PMEM['OBJ']['SOAP']->call("Get_InvoiceURL_O", $params);
			if($this->PMEM['OBJ']['SOAP']->getError()) {
				$this->RRAF("GRL() : ".$this->PMEM['OBJ']['SOAP']->getDebug(), '201903291610');
			} else {
				return $result['Get_InvoiceURL_OResult'];
			}
		} else {
			$this->RRAF("GRL() : Connection Error and Parameter Or Construct error.", '201903291637');
		}
	}## GRL($Order='') end

	## 取得發票號碼(商家自訂編號模式)
	## V1.1 2019/03/29
	function GRN($Order='') {
		# 判斷是否有參數值及建構式暫存執行判斷碼為 '1'
		if(!empty($Order) and $this->PMEM['RRA']['Type'] == '1') {
			$params = array('mem_cid' => $this->PMEM['SOAP']['PayNow']['ID'], 'orderno'=>$Order);
			$result = $this->PMEM['OBJ']['SOAP']->call("Check_invoiceOrder", $params);
			if($this->PMEM['OBJ']['SOAP']->getError()) {
				$this->RRAF("GRN() : ".$this->PMEM['OBJ']['SOAP']->getDebug(), '201903291649');
			} else {
				$invlink = explode(",",$result['Check_invoiceOrderResult']);
				return $invlink;
			}
		} else {
			$this->RRAF("GRN() : Connection Error and Parameter Or Construct error.", '201903291648');
		}
	} ## GRN($Order='') end

	## 作廢電子發票(For 字串串接)
	## V1.1 2019/04/01
	function DR($InvoiceNo='') {
		# 判斷是否有參數值及建構式暫存執行判斷碼為 '1'
		if(!empty($InvoiceNo) and $this->PMEM['RRA']['Type'] == '1') {
			$params = array('mem_cid' => $this->PMEM['SOAP']['PayNow']['ID'], 'InvoiceNo'=>"{$InvoiceNo}");
			$result = $this->PMEM['OBJ']['SOAP']->call("CancelInvoice_I", $params);
			if($this->PMEM['OBJ']['SOAP']->getError()) {
				$this->RRAF("GRN() : ".$this->PMEM['OBJ']['SOAP']->getDebug(), '201904010914');
			} else {
				if(preg_match("/S/i",$result['CancelInvoice_IResult'])) {
					echo 'Pass';
					return array(true, "發票號碼 ： {$InvoiceNo} 已完成作廢.");
				} else {
					echo 'Error';
					return array(false, "查詢不到 {$InvoiceNo} 發票，無法刪除，請重新確認.");
				}
			}
		} else {
			$this->RRAF("DR() : Connection Error and Parameter Or Construct error.", '201904010911');
		}
	}## DR($Order='') end

	## 批次發票上傳
	## V1.1 2019/03/29
	function BUPR($Source='') {
		$TmpVar['csvStr']='';
		if($Source != '' and is_array($Source) and $this->PMEM['RRA']['Type'] == '1') {
			foreach($Source as $Idx) {
				## 必須每個項次欄位總合為 17 的索引陣例值才可執行
				## 如果是異常的項目，另外存至 $this->PMEM['Error']['BURP'] 內，提供確認問題
				if(count($Idx) == 17) {
					for($i=0; $i<count($Idx); $i++) {
						if($i != 16) {
							$TmpVar['csvStr'] .= "'{$Idx[$i]},";
						} else {
							$TmpVar['csvStr'] .= "'{$Idx[$i]}";
						}
					}
					 $TmpVar['csvStr'] .= "\n";
				} else {
					$this->PMEM['Error']['BUPR'][] = $Idx;
				}
			}

			## 確定產生出批次上傳需要的資料後才進行後續程序
			if($TmpVar['csvStr'] != '') {
				$params = array(
								'mem_cid' => $this->PMEM['SOAP']['PayNow']['ID'],
								'mem_password' => $this->PMEM['SOAP']['PayNow']['PWD'],
								'csvStr' => urlencode(base64_encode($TmpVar['csvStr']))
							   );
				## 進行資料傳遞值伺服端，並將回傳值另存，透過回傳值進行後續判斷用.
				$result = $this->PMEM['OBJ']['SOAP']->call("UploadInvoice_Patch", $params);

				if(preg_match("/S/i",$result['UploadInvoice_PatchResult'])) {
					$this->PMEM['RRA']['InvoiceLink'] = $this->GRL($Source[0]['orderno']);
					$this->PMEM['RRA']['Code'] = '1';
					$this->PMEM['RRA']['Message'] = "新增發票完成.";			
				} elseif(preg_match("/F/i",$result['UploadInvoice_PatchResult'])) {
					$this->RRAF();
					$this->PMEM['RRA']['Message'] = $result['UploadInvoice_PatchResult'];
				}
			} else {
				$this->RRAF("BUPR() : CSV data is empty.", '201903291800');
			}
			
		} else {
			$this->RRAF("BUPR() : Connection Error and Parameter Or Construct error.", '201903291701');
		}
	}## BUPR($Source='') end

	## 取的發票總結明細
	## v1.1 2019/04/01
	function GII($Data='') {
		if(!empty($Data) and $this->PMEM['RRA']['Type'] == '1') {
			switch($Data['Type']) {
				case 'Order' :
					echo $ID=$Data['ID'];
					echo $Item='OrderNo';
				break;
				case 'INO' :
					$ID=$Data['ID'];
					$Item='InvoiceNo';
				break;
			}

			if($ID != '' and $Item != '') {
				$params = array('mem_cid' => $this->PMEM['SOAP']['PayNow']['ID'], $Item=>$ID);
				print_r($params);
				$result = $this->PMEM['OBJ']['SOAP']->call("Invoice_Info", $params);
				if($this->PMEM['OBJ']['SOAP']->getError()) {
					$this->RRAF("GRN() : ".$this->PMEM['OBJ']['SOAP']->getDebug(), '201904011013');
				} else {
					return $result;
				}
			} else {
				$this->RRAF("DR() : Parameter Or Construct error.", '201904011011');
			}
		} else {
			$this->RRAF("DR() : Connection Error and Parameter Or Construct error.", '201904011004');
		}
	}## GII() end

	## TLS 1.2 測試
	## v1.1 2019/04/01
	function TLS12Test() {
		echo 'Test if the TLS version is compatible with PayPal:<br/>';
		$ch = curl_init(); 
		curl_setopt ($ch, CURLOPT_SSLVERSION, 6); //Integer NOT string TLS v1.2
		curl_setopt($ch, CURLOPT_URL, "https://tlstest.paypal.com/"); 
		echo '&nbsp;curl_exec($ch): ';
		var_dump(curl_exec($ch));
		echo '<br/>&nbsp;curl_error($ch): ';
		var_dump(curl_error($ch));
		curl_close($ch);

		// Test from https://github.com/paypal/adaptivepayments-sdk-php/issues/64
		echo '<br/><br/>Another test, get TLS & SSL Version:<br/>';
		$ch = curl_init('https://www.howsmyssl.com/a/check');
		curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
		$data = curl_exec($ch);
		$json = json_decode($data);
		echo ' TLS Version: ';
		echo $json->tls_version;

		$curl_info = curl_version();
		echo '<br/> SSL Version: ';
		echo $curl_info['ssl_version'];
		curl_close($ch);		
	}## TLS12Test() end

	## 系統內部開發錯誤定義方法
	## V1.1 2019/03/15
	function RRAF($Message='', $Code='') {
		$reflector = new ReflectionClass('PayNow');
		$this->PMEM['RRA'] = array('Type'=>'2',
								   'File'=>$reflector->getFileName(),
								   'Message'=>$Message,
								   'Code'=>$Code
								  );
		unset($reflector);
	} ## RRAF($Message='', $Code='') end		
}## class PayNow end

###################################################################################################
## 實體運行程式演算如下
###################################################################################################
## 實體化物件模組
## 如未定義以下陣列值時，即會以測試環境為主
## 在模組中的建構裡，有著 UnSOAP 套件定義路徑，預設下為物件模組同層即可
## 如需因設計概念調整，需另外定義相關路徑。

#$INPara['SOAP']['PayNow'] = array('ID'=>'商家統編', 'PWD'=>'商家密碼');
$TmpVar['OBJ']['PayNow'] = new PayNow;

## 測試伺服器端的 TLS 1.2 狀態
## 如果可執行的狀況下，可看到以下相關訊息
#Test if the TLS version is compatible with PayPal:
#curl_exec($ch): PayPal_Connection_OKbool(true) 
#curl_error($ch): string(0) "" 
#$TmpVar['OBJ']['PayNow']->TLS12Test();

## (1) 查詢發票連結-以發票號碼方式
## 成功取得程序後回傳發票連結
#echo $TmpVar['OBJ']['PayNow']->IGRL('PD70067705');

## (2) 查詢發票連結-以商家自定編號方式
## 成功取得程序後回傳發票連結
#echo $TmpVar['OBJ']['PayNow']->GRL('1701196799185');

## (3) 查詢發票號碼-以商家自定編號方法
## 除錯誤外，程式端即會回傳索引陣例值
## [0] : S - 成功 | F - 失敗
## [1] : 發票號碼 (只有 [0] 為 S 才會呈現)
## print_r($TmpVar['OBJ']['PayNow']->GRN($Order='1701196799185'));

## (4) 批次發票上傳
## 每一陣例格式如右：商家訂單編號、買方統編、買方姓名、買方住址、買方手機、買方EMail、載具類型、載具明碼、載具隱碼、愛碼，明細描述、數量、單價、小計、備註、發票明細稅別、是否經海關
## 注意：同訂單編號將似為同一張發票
$Order= array(
			  array('202312281028', '70456827', '勁強科技', '桃園市蘆竹區吉林路130號6樓', '', 'service@houseweb.com.tw', '', '', '', '', '資訊應用軟體服務', '1', '1000', '1000', '1111', '1', '1') 
#			  array('202312281001', '70456827', '勁強科技分公司', '桃園市蘆竹區吉林路130號4樓', '', 'service@houseweb.com.tw', '', '', '', '', '資訊應用軟體服務', '1', '1000', '1000', '1111', '1', '1'),
#			  array('202312282001', '70456827', '中信房屋加盟店', '桃園市蘆竹區吉林路130號6樓', '', 'service@houseweb.com.tw', '', '', '', '', '資訊應用軟體服務', '1', '1000', '1000', '1111', '1', '1'),
#			  array('202312282002', '', '勁強科技', '桃園市蘆竹區吉林路130號6樓', '', 'service@houseweb.com.tw', '', '', '', '', '資訊應用軟體服務', '1', '1000', '1000', '1111', '1', '1'),
#			  array('202312282003', '', '勁強科技', '桃園市蘆竹區吉林路130號6樓', '', 'service@houseweb.com.tw', '', '', '', '', '資訊應用軟體服務', '1', '1000', '1000', '1111', '1', '1')
			  );
//$Order[0]['orderno']='1111111111';			  
$TmpVar['OBJ']['PayNow']->BUPR($Order);

## (5) 發票作廢
## 除錯誤外，有無作廢發票都會回傳索引陣例值
## [0] : true(作廢完成) | false(無可作廢發票)
## [1] : 提示文字訊息
## $RV = $TmpVar['OBJ']['PayNow']->DR('PD70067708');
## print_r($RV)


## (6) 取得發票明細
## 該明細不含消商品列表
## 引入參數為關連陣列模式
## Type : Order - 訂單編號 | INO - 發票編號
## ID : Type 對應的編號
## 成功取得後，依據官方回傳值直接再回傳給指定呼應程式應用
#$RV = $TmpVar['OBJ']['PayNow']->GII(array('Type'=>'INO', 'ID'=>'PD70069365'));
#$RV = $TmpVar['OBJ']['PayNow']->GII(array('Type'=>'Order', 'ID'=>'20190401093902'));

## 反傳錯誤時，直接導出錯誤訊息
if($TmpVar['OBJ']['PayNow']->PMEM['RRA']['Type'] == '2') {
	echo $TmpVar['OBJ']['PayNow']->PMEM['RRA']['Message'];
}

?>