|
|
|
@ -0,0 +1,236 @@
|
|
|
|
|
<?php
|
|
|
|
|
defined('BASEPATH') or exit('No direct script access allowed');
|
|
|
|
|
|
|
|
|
|
class LianlianService extends CI_Controller
|
|
|
|
|
{
|
|
|
|
|
protected $merchant_config;
|
|
|
|
|
protected $private_key;
|
|
|
|
|
|
|
|
|
|
public function __construct()
|
|
|
|
|
{
|
|
|
|
|
parent::__construct();
|
|
|
|
|
bcscale(2);
|
|
|
|
|
$this->load->helper('payment');
|
|
|
|
|
$this->config->load('lianlian', true);
|
|
|
|
|
$this->load->model('Online_payment_note_model', 'note_model');
|
|
|
|
|
$this->load->model('Online_payment_account_model', 'account_model');
|
|
|
|
|
|
|
|
|
|
$this->merchant_config = $this->config->item('test', 'lianlian');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function index() {}
|
|
|
|
|
|
|
|
|
|
public function query_status() {}
|
|
|
|
|
|
|
|
|
|
public function query_payment() {}
|
|
|
|
|
|
|
|
|
|
public function query_refund() {}
|
|
|
|
|
|
|
|
|
|
public function notify($site = 'cht')
|
|
|
|
|
{
|
|
|
|
|
// $this->merchant_config = $this->config->item($site, 'lianlian'); // test: 测试环境
|
|
|
|
|
|
|
|
|
|
error_reporting(0);
|
|
|
|
|
log_message('error', 'LianlianPay notify begin ----');
|
|
|
|
|
$response['code'] = 0;
|
|
|
|
|
$response['message'] = '';
|
|
|
|
|
$raw_post_data = file_get_contents('php://input');
|
|
|
|
|
if (empty($raw_post_data)) {
|
|
|
|
|
# 如果没有数据,直接返回失败
|
|
|
|
|
return $this->output->set_content_type('application/json')->set_output(json_encode($response));
|
|
|
|
|
}
|
|
|
|
|
log_message('error','test: ' . __METHOD__ . ': ' . __LINE__ . ' ' . PHP_EOL . var_export($raw_post_data, 1));
|
|
|
|
|
|
|
|
|
|
$signature = $this->input->server('HTTP_SIGNATURE');
|
|
|
|
|
$payment_result = json_decode($raw_post_data, true);
|
|
|
|
|
if ($this->check_sign($payment_result, $signature) !== true) {
|
|
|
|
|
$response['message'] = 'sign error';
|
|
|
|
|
// return $this->output->set_content_type('application/json')->set_output(json_encode($response));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$payment_data = $payment_result['payment_data'];
|
|
|
|
|
$payment_result['GAI_API'] = array(
|
|
|
|
|
'merchant' => $site,
|
|
|
|
|
'invoice' => $payment_result['merchant_transaction_id'],
|
|
|
|
|
'transaction_id' => $payment_result['ll_transaction_id'],
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
// todo: 计算手续费, 实收
|
|
|
|
|
$payment_fee = $payment_data['payment_amount'] - $payment_data['settlement_amount'];
|
|
|
|
|
$ssje = $this->account_model->get_ssje($payment_data['settlement_amount'], str_replace("CNY", "RMB", strtoupper($payment_data['settlement_currency_code'])), $this->merchant_config['method_code']);
|
|
|
|
|
$save_column = array();
|
|
|
|
|
$save_column['OPN_transactionId'] = $payment_result['ll_transaction_id'];
|
|
|
|
|
$save_column['OPN_orderId'] = $payment_result['merchant_transaction_id'];
|
|
|
|
|
$save_column['OPN_rawOrderId'] = $payment_result['merchant_transaction_id'];
|
|
|
|
|
$save_column['OPN_invoiceId'] = $payment_result['merchant_transaction_id'];
|
|
|
|
|
$save_column['OPN_subject'] = $payment_result['merchant_transaction_id'];
|
|
|
|
|
$save_column['OPN_currency'] = $payment_data['payment_currency_code'];
|
|
|
|
|
$save_column['OPN_orderAmount'] = $payment_data['payment_amount'];
|
|
|
|
|
$save_column['OPN_payAmount'] = $payment_data['payment_amount'];
|
|
|
|
|
// $save_column['OPN_payFee'] = $payment_fee; // todo: 计算手续费; 退款 1USD 原手续费不退
|
|
|
|
|
$save_column['OPN_netAmount'] = $payment_data['settlement_amount'];
|
|
|
|
|
$save_column['OPN_transactionResult'] = $payment_data['payment_status'] === 'PS' ? 'completed' : 'declined';
|
|
|
|
|
$save_column['OPN_resultCode'] = $payment_data['payment_status'];
|
|
|
|
|
// $save_column['OPN_resultMsg'] = isset($payment_result['return_msg']) ? $payment_result['return_msg'] : $payment_result['result_code'];
|
|
|
|
|
// $save_column['OPN_errCode'] = isset($payment_result['err_code']) ? $payment_result['err_code'] : NULL;
|
|
|
|
|
// $save_column['OPN_errMsg'] = isset($payment_result['err_code_des']) ? $payment_result['err_code_des'] : NULL;
|
|
|
|
|
$save_column['OPN_acquiringTime'] = date('Y-m-d H:i:s', strtotime($payment_data['payment_time']));
|
|
|
|
|
$save_column['OPN_completeTime'] = date('Y-m-d H:i:s', strtotime($payment_data['payment_time']));
|
|
|
|
|
// $save_column['OPN_remark'] = $payment_result['attach'] ? $payment_result['attach'] : $payment_result['out_trade_no'];
|
|
|
|
|
// $save_column['OPN_payerLogId'] = $payment_result['openid'];
|
|
|
|
|
// $save_column['OPN_payerStatus'] = $payment_result['is_subscribe']==='Y' ? "subscribed" : NULL;
|
|
|
|
|
$save_column['OPN_fundSource'] = $site;
|
|
|
|
|
$save_column['OPN_entryAmountCNY'] = floatval($ssje);
|
|
|
|
|
$save_column['OPN_rawContent'] = json_encode($payment_result);
|
|
|
|
|
$save_column['OPN_noticeTime'] = date('Y-m-d H:i:s');
|
|
|
|
|
// $save_column['OPN_noticeType'] = intval($payment_result['total_fee'])>0 ? 'pay' : 'refund';
|
|
|
|
|
$save_column['OPN_noticeType'] = 'pay';
|
|
|
|
|
$save_column['OPN_noticeSendStatus'] = $payment_data['payment_status'] === 'PS' ? 'unsend' : 'closed';
|
|
|
|
|
$save_column['OPN_noticeSendTime'] = NULL;
|
|
|
|
|
$save_column['OPN_accountMethod'] = $this->merchant_config['method_code'];
|
|
|
|
|
|
|
|
|
|
if ($this->note_model->insert_note($save_column)) {
|
|
|
|
|
$response['code'] = 200;
|
|
|
|
|
$response['message'] = 'success';
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$this->output->set_content_type('application/json')->set_output(json_encode($response));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function notify_refund($site = 'cht')
|
|
|
|
|
{
|
|
|
|
|
// $this->merchant_config = $this->config->item($site, 'lianlian'); // test: 测试环境
|
|
|
|
|
|
|
|
|
|
error_reporting(0);
|
|
|
|
|
log_message('error', 'LianlianPay notify refund begin ----');
|
|
|
|
|
$response['code'] = 0;
|
|
|
|
|
$response['message'] = '';
|
|
|
|
|
$raw_post_data = file_get_contents('php://input');
|
|
|
|
|
if (empty($raw_post_data)) {
|
|
|
|
|
# 如果没有数据,直接返回失败
|
|
|
|
|
return $this->output->set_content_type('application/json')->set_output(json_encode($response));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$signature = $this->input->server('HTTP_SIGNATURE');
|
|
|
|
|
$payment_result = json_decode($raw_post_data, true);
|
|
|
|
|
if ($this->check_sign($payment_result, $signature) !== true) {
|
|
|
|
|
log_message('error','debug: ' . __METHOD__ . ': ' . __LINE__ . ' signature' . PHP_EOL . var_export($signature, 1));
|
|
|
|
|
log_message('error','debug: ' . __METHOD__ . ': ' . __LINE__ . ' raw_post_data' . PHP_EOL . var_export($raw_post_data, 1));
|
|
|
|
|
$response['message'] = 'sign error';
|
|
|
|
|
// return $this->output->set_content_type('application/json')->set_output(json_encode($response)); // debug:
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$payment_data = $payment_result['refund_data'];
|
|
|
|
|
$find_related = $this->note_model->get_note_where(['OPN_invoiceId' => ['=', $payment_result['original_transaction_id']], 'OPN_transactionResult' => ['=', 'completed']]);
|
|
|
|
|
|
|
|
|
|
// ! 退款手续费 1USD, 原交易手续费不退
|
|
|
|
|
// $payment_fee = $payment_data['payment_amount'] - $payment_data['settlement_amount'];
|
|
|
|
|
// $ssje = $this->account_model->get_ssje('-' . $payment_data['actual_refund_amount'], str_replace("CNY", "RMB", strtoupper($payment_data['actual_refund_currency_code'])), $this->merchant_config['method_code']);
|
|
|
|
|
$ssje = $this->account_model->get_ssje('-' . $payment_data['settlement_amount'], str_replace("CNY", "RMB", strtoupper($payment_data['settlement_currency_code'])), $this->merchant_config['method_code']);
|
|
|
|
|
$save_column = array();
|
|
|
|
|
$save_column['OPN_transactionId'] = $payment_result['ll_transaction_id'];
|
|
|
|
|
$save_column['OPN_orderId'] = $payment_result['original_transaction_id'];
|
|
|
|
|
$save_column['OPN_rawOrderId'] = $payment_result['merchant_transaction_id'];
|
|
|
|
|
$save_column['OPN_invoiceId'] = $payment_result['merchant_transaction_id'];
|
|
|
|
|
$save_column['OPN_relatedId'] = isset($find_related[0]->OPN_transactionId) ? $find_related[0]->OPN_transactionId : null;
|
|
|
|
|
$save_column['OPN_subject'] = $payment_result['merchant_transaction_id'] . ' ' . $payment_data['reason'];
|
|
|
|
|
|
|
|
|
|
$save_column['OPN_currency'] = $payment_data['refund_currency_code'];
|
|
|
|
|
$save_column['OPN_orderAmount'] = '-'.$payment_data['refund_amount'];
|
|
|
|
|
$save_column['OPN_payAmount'] = '-'.$payment_data['refund_amount'];
|
|
|
|
|
$save_column['OPN_payFee'] = null; // 1; // ! todo: 计算手续费; 退款 1 USD 原手续费不退
|
|
|
|
|
$save_column['OPN_netAmount'] = '-'.$payment_data['settlement_amount']; // todo:
|
|
|
|
|
$save_column['OPN_transactionResult'] = refund_status($payment_data['refund_status']);
|
|
|
|
|
$save_column['OPN_resultCode'] = $payment_data['refund_status'];
|
|
|
|
|
// $save_column['OPN_resultMsg'] = isset($payment_result['return_msg']) ? $payment_result['return_msg'] : $payment_result['result_code'];
|
|
|
|
|
// $save_column['OPN_errCode'] = isset($payment_result['err_code']) ? $payment_result['err_code'] : NULL;
|
|
|
|
|
// $save_column['OPN_errMsg'] = isset($payment_result['err_code_des']) ? $payment_result['err_code_des'] : NULL;
|
|
|
|
|
$save_column['OPN_acquiringTime'] = date('Y-m-d H:i:s', strtotime($payment_data['refund_time']));
|
|
|
|
|
$save_column['OPN_completeTime'] = date('Y-m-d H:i:s', strtotime($payment_data['refund_time']));
|
|
|
|
|
$save_column['OPN_remark'] = $payment_data['reason'] ? $payment_data['reason'] : '';
|
|
|
|
|
// $save_column['OPN_payerLogId'] = $payment_result['openid'];
|
|
|
|
|
// $save_column['OPN_payerStatus'] = $payment_result['is_subscribe']==='Y' ? "subscribed" : NULL;
|
|
|
|
|
$save_column['OPN_fundSource'] = $site;
|
|
|
|
|
$save_column['OPN_entryAmountCNY'] = floatval($ssje);
|
|
|
|
|
$save_column['OPN_rawContent'] = json_encode($payment_result);
|
|
|
|
|
$save_column['OPN_noticeTime'] = date('Y-m-d H:i:s');
|
|
|
|
|
$save_column['OPN_noticeType'] = 'refund';
|
|
|
|
|
$save_column['OPN_noticeSendStatus'] = refund_status_send($payment_data['refund_status']);
|
|
|
|
|
$save_column['OPN_noticeSendTime'] = NULL;
|
|
|
|
|
$save_column['OPN_accountMethod'] = $this->merchant_config['method_code'];
|
|
|
|
|
// log_message('error','test: ' . __METHOD__ . ': ' . __LINE__ . ' to in' . PHP_EOL . var_export($save_column, 1));
|
|
|
|
|
// die; // test:0
|
|
|
|
|
if ($this->note_model->insert_note($save_column)) {
|
|
|
|
|
$response['code'] = 200;
|
|
|
|
|
$response['message'] = 'success';
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$this->output->set_content_type('application/json')->set_output(json_encode($response));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// protected function generateSignArray($params, $signType = "RSA")
|
|
|
|
|
// {
|
|
|
|
|
// return $this->sign(generateSignContent($params), $signType);
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
// protected function sign($data, $signType = "RSA")
|
|
|
|
|
// {
|
|
|
|
|
// $this->private_key = $this->merchant_config['merchant_private_key'];
|
|
|
|
|
// $priKey = $this->private_key;
|
|
|
|
|
// $res = "-----BEGIN RSA PRIVATE KEY-----\n" .
|
|
|
|
|
// wordwrap($priKey, 64, "\n", true) .
|
|
|
|
|
// "\n-----END RSA PRIVATE KEY-----";
|
|
|
|
|
|
|
|
|
|
// ($res) or die('您使用的私钥格式错误,请检查RSA私钥配置');
|
|
|
|
|
|
|
|
|
|
// if ("RSA2" == $signType) {
|
|
|
|
|
// openssl_sign($data, $sign, $res, OPENSSL_ALGO_SHA256);
|
|
|
|
|
// } else {
|
|
|
|
|
// openssl_sign($data, $sign, $res);
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
// $sign = base64_encode($sign);
|
|
|
|
|
// return $sign;
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
protected function check_sign($data, $signature)
|
|
|
|
|
{
|
|
|
|
|
if (empty($signature)) {
|
|
|
|
|
log_message('error', 'LianlianPay notify error: no sign.');
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
$verify_res = $this->verify_signature(generateSignContent($data), $signature);
|
|
|
|
|
if ( ! $verify_res) {
|
|
|
|
|
log_message('error', 'LianlianPay notify error: sign. ' . generateSignContent($data));
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
// return false; // test: 0
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected function verify_signature($data, $sign, $signType = "RSA")
|
|
|
|
|
{
|
|
|
|
|
// Load the public key
|
|
|
|
|
$pubKey = $this->merchant_config['lianlian_public_key'];
|
|
|
|
|
if (!$pubKey) {
|
|
|
|
|
return false; // Public key file not found or unreadable.
|
|
|
|
|
}
|
|
|
|
|
$res = "-----BEGIN PUBLIC KEY-----\n" .
|
|
|
|
|
wordwrap($pubKey, 64, "\n", true) .
|
|
|
|
|
"\n-----END PUBLIC KEY-----";
|
|
|
|
|
$res = openssl_get_publickey($res);
|
|
|
|
|
($res) or die('LianlianRSA公钥错误。请检查公钥文件格式是否正确');
|
|
|
|
|
//调用openssl内置方法验签,返回bool值
|
|
|
|
|
if ("RSA2" == $signType) {
|
|
|
|
|
$result = (bool)openssl_verify($data, base64_decode($sign), $res, OPENSSL_ALGO_SHA256); // sha256 OPENSSL_ALGO_SHA256
|
|
|
|
|
} else {
|
|
|
|
|
$result = (bool)openssl_verify($data, base64_decode($sign), $res);
|
|
|
|
|
}
|
|
|
|
|
// log_message('error', 'test: ' . __METHOD__ . ': ' . __LINE__ . ' result' . PHP_EOL . var_export($result, 1));
|
|
|
|
|
//释放资源
|
|
|
|
|
openssl_free_key($res);
|
|
|
|
|
return $result;
|
|
|
|
|
}
|
|
|
|
|
}
|