config = $params; } /** * 配置信息 * @author Devil * @blog http://gong.gg/ * @version 1.0.0 * @date 2018-09-19 * @desc description */ public function Config() { // 基础信息 $base = [ 'name' => 'OceanPayment', // 插件名称 'version' => '1.0.0', // 插件版本 'apply_version' => '不限', // 适用系统版本描述 'apply_terminal'=> ['pc','h5'], // 适用终端 默认全部 ['pc', 'h5', 'ios', 'android', 'alipay', 'weixin', 'baidu', 'toutiao'] 'desc' => 'OceanPayment全球数字支付方案提供商,适用PC+H5,信用卡支付。 立即申请', // 插件描述(支持html) 'author' => 'Devil', // 开发者 'author_url' => 'http://shopxo.net/', // 开发者主页 ]; // 配置信息 $element = [ [ 'element' => 'input', 'type' => 'text', 'default' => '', 'name' => 'account', 'placeholder' => 'account账户号', 'title' => 'account账户号', 'is_required' => 0, 'message' => '请填写account账户号', ], [ 'element' => 'input', 'type' => 'text', 'default' => '', 'name' => 'terminal', 'placeholder' => 'terminal终端号', 'title' => 'terminal终端号', 'is_required' => 0, 'message' => '请填写terminal终端号', ], [ 'element' => 'input', 'type' => 'text', 'default' => '', 'name' => 'secure_code', 'placeholder' => 'secureCode', 'title' => 'secureCode', 'is_required' => 0, 'message' => '请填写secureCode', ], [ 'element' => 'textarea', 'name' => 'key', 'placeholder' => 'Oceanpayment公钥', 'title' => 'Oceanpayment公钥', 'is_required' => 0, 'rows' => 4, 'message' => '请填写Oceanpayment公钥', ], [ 'element' => 'input', 'type' => 'text', 'default' => 'en_US', 'name' => 'lang', 'placeholder' => '语言', 'title' => '语言', 'is_required' => 0, 'message' => '请填写语言', ], [ 'element' => 'input', 'type' => 'text', 'default' => 'USD', 'name' => 'order_currency', 'placeholder' => '交易币种', 'title' => '交易币种', 'is_required' => 0, 'message' => '请填写交易币种', ], [ 'element' => 'input', 'type' => 'text', 'default' => 'US', 'name' => 'billing_country', 'placeholder' => '消费者的账单国家', 'title' => '消费者的账单国家', 'is_required' => 0, 'message' => '请填写消费者的账单国家', ], [ 'element' => 'input', 'type' => 'text', 'default' => 'N/A', 'name' => 'billing_state', 'placeholder' => '消费者的州(省、郡)', 'title' => '消费者的州(省、郡)', 'is_required' => 0, 'message' => '请填写消费者的州(省、郡)', ], [ 'element' => 'select', 'title' => '是否测试环境', 'message' => '请选择是否测试环境', 'name' => 'is_dev_env', 'is_multiple' => 0, 'element_data' => [ ['value'=>0, 'name'=>'否'], ['value'=>1, 'name'=>'是'], ], ], [ 'element' => 'input', 'type' => 'text', 'default' => '', 'name' => 'show_images', 'placeholder' => '自定义展示图片地址', 'title' => '自定义展示图片地址', 'is_required' => 0, 'message' => '请填写自定义展示图片地址', ], [ 'element' => 'input', 'type' => 'text', 'default' => '进入我的订单', 'name' => 'button_order_name', 'placeholder' => '进入我的订单按钮名称', 'title' => '进入我的订单按钮名称', 'is_required' => 0, 'message' => '请填写进入我的订单按钮名称', ], [ 'element' => 'input', 'type' => 'text', 'default' => '立即支付', 'name' => 'button_pay_name', 'placeholder' => '支付按钮名称', 'title' => '支付按钮名称', 'is_required' => 0, 'message' => '请填写支付按钮名称', ], [ 'element' => 'input', 'type' => 'text', 'default' => '支付金额:', 'name' => 'pay_first_name', 'placeholder' => '价格提示名称', 'title' => '价格提示名称', 'is_required' => 0, 'message' => '请填写价格提示名称', ], ]; return [ 'base' => $base, 'element' => $element, ]; } /** * 支付入口 * @author Devil * @blog http://gong.gg/ * @version 1.0.0 * @date 2018-09-19 * @desc description * @param [array] $params [输入参数] */ public function Pay($params = []) { // 参数 if(empty($params)) { return DataReturn('参数不能为空', -1); } // 配置信息 if(empty($this->config) || empty($this->config['account']) || empty($this->config['terminal']) || empty($this->config['secure_code']) || empty($this->config['key'])) { return DataReturn('支付缺少配置', -1); } // 订单地址 $address_data = (!empty($params['business_data']) && !empty($params['business_data'][0]) && !empty($params['business_data'][0]['address_data'])) ? $params['business_data'][0]['address_data'] : []; $tel = empty($address_data) ? (empty($params['user']['mobile']) ? 'N/A' : $params['user']['mobile']) : $address_data['tel']; $city = empty($address_data['city_name']) ? 'N/A' : $address_data['city_name']; $address = empty($address_data['address']) ? 'N/A' : $address_data['address']; // 支付数据 $parameter = [ 'account' => $this->config['account'], 'terminal' => $this->config['terminal'], 'signValue' => '', 'key' => $this->config['key'], 'backUrl' => $params['call_back_url'], 'noticeUrl' => $params['notify_url'], 'methods' => 'Credit Card', 'order_number' => $params['order_no'], 'order_currency' => empty($this->config['order_currency']) ? 'USD' : $this->config['order_currency'], 'order_amount' => $params['total_price'], 'billing_firstName' => $params['user']['id'], 'billing_lastName' => $params['user']['user_name_view'], 'billing_email' => empty($params['user']['email']) ? $params['user']['id'].'@'.__MY_HOST__ : $params['user']['email'], 'billing_phone' => $tel, 'billing_country' => empty($this->config['billing_country']) ? 'US' : $this->config['billing_country'], 'billing_state' => empty($this->config['billing_state']) ? 'N/A' : $this->config['billing_state'], 'billing_city' => $city, 'billing_address' => $address, 'billing_zip' => 'N/A', 'billing_ip' => GetClientIP(), 'ship_firstName' => $params['user']['id'], 'ship_lastName' => $params['user']['user_name_view'], 'ship_email' => empty($params['user']['email']) ? $params['user']['id'].'@'.__MY_HOST__ : $params['user']['email'], 'ship_phone' => $tel, 'ship_country' => empty($this->config['billing_country']) ? 'US' : $this->config['billing_country'], 'ship_state' => empty($this->config['billing_state']) ? 'N/A' : $this->config['billing_state'], 'ship_city' => $city, 'ship_addr' => $address, 'ship_zip' => 'N/A', 'productSku' => $params['name'], 'productName' => $params['site_name'].'-'.$params['name'], 'productNum' => 1, 'productPrice' => $params['total_price'], ]; // 存储单号缓存 MyCache($this->cache_key.$params['user']['id'], $params['order_no'], 3600); // 签名(account+terminal+order_number+order_currency+order_amount+billing_firstName+billing_lastName+billing_email+secureCode) $parameter['signValue'] = hash('sha256', $parameter['account'].$parameter['terminal'].$parameter['order_number'].$parameter['order_currency'].$parameter['order_amount'].$parameter['billing_firstName'].$parameter['billing_lastName'].$parameter['billing_email'].$this->config['secure_code']); // 支付请求记录 PayLogService::PayLogRequestRecord($params['order_no'], ['request_params'=>$parameter]); die($this->PayHtml($parameter)); } /** * 支付代码 * @author Devil * @blog http://gong.gg/ * @version 1.0.0 * @datetime 2019-05-25T00:07:52+0800 * @param [array] $pay_data [支付信息] */ private function PayHtml($pay_data) { // 支付代码 $html = ' Oceanpayment Debit/Credit Card|One-Page Checkout
'.(empty($this->config['pay_first_name']) ? '支付金额:' : $this->config['pay_first_name']).' '.ResourcesService::CurrencyDataSymbol().$pay_data['order_amount'].'
'; foreach($pay_data as $k=>$v) { $html .= ''; } $html .= '
'.(empty($this->config['button_order_name']) ? '进入我的订单' : $this->config['button_order_name']).'
'; if(!empty($this->config['show_images'])) { $html .= '
'; } $html .= '
'; return $html; } /** * 支付回调处理 * @author Devil * @blog http://gong.gg/ * @version 1.0.0 * @date 2018-09-19 * @desc description * @param [array] $params [输入参数] */ public function Respond($params = []) { // 接收参数 if(empty($params)) { $params = MyInput(); } // 同步返回 if(empty($params['order_number'])) { // 用户信息 $user = UserService::LoginUserInfo(); if(empty($user)) { return DataReturn('用户未登录', -1); } $order_no = MyCache($this->cache_key.$user['id']); if(empty($order_no)) { return DataReturn('支付单号为空', -1); } // 轮训5秒查询结果 $count = 5; for($i=0; $i<$count; $i++) { // 暂停1秒钟,等待异步通知处理 sleep(1); // 查询订单状态 $ret = OrderService::OrderPayCheck(['order_no'=>$order_no, 'user'=>$user]); if($ret['code'] == 0) { return $ret; } } return DataReturn('支付失败,可能网络原因,请以订单状态为准', -1); } // 异步通知处理 $sign = strtoupper(hash('sha256', $this->config['account'].$this->config['terminal'].$params['order_number'].$params['order_currency'].$params['order_amount'].(empty($params['order_notes']) ? '' : $params['order_notes']).$params['card_number'].$params['payment_id'].$params['payment_authType'].$params['payment_status'].(empty($params['payment_details']) ? '' : $params['payment_details']).(empty($params['payment_risk']) ? '' : $params['payment_risk']).$this->config['secure_code'])); if($sign != strtoupper($params['signValue'])) { return DataReturn('签名校验失败', -1); } $ret = DataReturn('支付失败', -1); if(isset($params['payment_status']) && $params['payment_status'] == 1) { $ret = DataReturn('支付成功', 0, $this->ReturnData($params)); } return $ret; } /** * 返回数据统一格式 * @author Devil * @blog http://gong.gg/ * @version 1.0.0 * @datetime 2018-10-06T16:54:24+0800 * @param [array] $data [返回数据] */ private function ReturnData($data) { // 返回数据固定基础参数 $data['trade_no'] = $data['payment_id']; // 支付平台 - 订单号 $data['buyer_user'] = isset($data['pay_userId']) ? $data['pay_userId'] : ''; // 支付平台 - 用户 $data['out_trade_no'] = $data['order_number']; // 本系统发起支付的 - 订单号 $data['subject'] = isset($data['order_notes']) ? $data['order_notes'] : ''; // 本系统发起支付的 - 商品名称 $data['pay_price'] = $data['order_amount']; // 本系统发起支付的 - 总价 return $data; } /** * 退款处理 * @author Devil * @blog http://gong.gg/ * @version 1.0.0 * @date 2019-05-28 * @desc description * @param [array] $params [输入参数] */ public function Refund($params = []) { // 参数 $p = [ [ 'checked_type' => 'empty', 'key_name' => 'order_no', 'error_msg' => '订单号不能为空', ], [ 'checked_type' => 'empty', 'key_name' => 'trade_no', 'error_msg' => '交易平台订单号不能为空', ], [ 'checked_type' => 'empty', 'key_name' => 'refund_price', 'error_msg' => '退款金额不能为空', ], ]; $ret = ParamsChecked($params, $p); if($ret !== true) { return DataReturn($ret, -1); } // 退款原因 $refund_reason = empty($params['refund_reason']) ? $params['order_no'].'订单退款'.$params['refund_price'].'元' : $params['refund_reason']; // 退款参数 $parameter = [ 'account' => $this->config['account'], 'terminal' => $this->config['terminal'], 'refund_number' => $params['order_no'].GetNumberCode(), 'out_trade_no' => $params['order_no'], 'payment_id' => $params['trade_no'], 'refund_type' => ($params['refund_price'] < $params['pay_price']) ? 2 : 1, 'refund_amount' => $params['refund_price'], 'refund_description' => $refund_reason, ]; // 签名(account+terminal+payment_id+refund_number+refund_type+refund_amount+refund_description+secureCode) $parameter['signValue'] = hash('sha256', $parameter['account'].$parameter['terminal'].$parameter['payment_id'].$parameter['refund_number'].$parameter['refund_type'].$parameter['refund_amount'].$parameter['refund_description'].$this->config['secure_code']); // 请求接口 $ret = CurlPost($this->RequestUrl('service/applyRefund'), $parameter); if($ret['code'] != 0) { return $ret; } // xml处理 $data = $this->XmlToArray($ret['data']); if(isset($data['refund_results']) && $data['refund_results'] == '00') { // 统一返回格式 $data = [ 'out_trade_no' => isset($data['order_number']) ? $data['order_number'] : '', 'trade_no' => isset($data['refund_id']) ? $data['refund_id'] : '', 'buyer_user' => '', 'refund_price' => $params['refund_price'], 'return_params' => $data, 'request_params' => $parameter, ]; return DataReturn('退款成功', 0, $data); } $msg = empty($data['refund_description']) ? '退款失败' : $data['refund_description']; return DataReturn($msg, -1); } /** * 请求url * @author Devil * @blog http://gong.gg/ * @version 1.0.0 * @date 2023-07-03 * @desc description * @param [string] $path [接口路径] */ public function RequestUrl($path) { $url = 'https://query.oceanpayment.com/'; if(isset($this->config['is_dev_env']) && $this->config['is_dev_env'] == 1) { $url = 'https://test-query.oceanpayment.com/'; } return $url.$path; } /** * xml转数组 * @author Devil * @blog http://gong.gg/ * @version 1.0.0 * @date 2019-01-07 * @desc description * @param [string] $xml [xm数据] */ private function XmlToArray($xml) { if(!$this->XmlParser($xml)) { return is_string($xml) ? $xml : '接口返回数据有误'; } return json_decode(json_encode(simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA)), true); } /** * 判断字符串是否为xml格式 * @author Devil * @blog http://gong.gg/ * @version 1.0.0 * @date 2019-01-07 * @desc description * @param [string] $string [字符串] */ function XmlParser($string) { $xml_parser = xml_parser_create(); if(!xml_parse($xml_parser, $string, true)) { xml_parser_free($xml_parser); return false; } else { return (json_decode(json_encode(simplexml_load_string($string)),true)); } } /** * 自定义成功返回内容 * @author Devil * @blog http://gong.gg/ * @version 1.0.0 * @date 2020-07-01 * @desc description */ public function SuccessReturn() { return 'receive-ok'; } /** * 自定义失败返回内容 * @author Devil * @blog http://gong.gg/ * @version 1.0.0 * @date 2020-07-01 * @desc description */ public function ErrorReturn() { return 'receive-no'; } } ?>