拉卡拉商户入网api接口接入, 提供方便数据。 代码使用是yii2框架, 使用拉卡拉测试参数。
<?php
namespace common\libraries\lakala\merchant;
/**
* 商户入网
* Class MerchantNetForm
* @package common\libraries\lakala\merchant
*/
class MerchantNetForm
{
public $version = '1.0'; //接口版本号
public $orderNo; //订单编号
public $posType; //进件POS类型 —按接入系统做控制
public $orgCode; //机构代码 (合作方在拉卡拉的标识,请联系业务员
public $merRegName; //商户注册名称
public $merRegDistCode = '1'; //商户地区代码
public $merRegAddr; //商户详细地址(去除省,市,区后的详细地址,6-200字符)
public $mccCode; //商户MCC编号
public $merBlis; //营业执照号
public $merBlisStDt; //营业执照开始日期
public $merBlisExpDt; //营业执照有效期
public $merBusiContent; //商户经营内容
public $larName; //商户法人姓名
public $larIdType; //法人证件类型
public $larIdcard; //法人身份证号码
public $larIdcardStDt; //法人身份证开始日期 yyyy-MM-dd
public $larIdcardExpDt; //法人身份证有效期 yyyy-MM-dd
public $merContactMobile; //商户联系人手机号码
public $merContactName; //商户联系人
public $openningBankCode; //结算账户开户行号
public $openningBankName; //结算账户开户行名称
public $clearingBankCode; //结算账户清算行号
public $acctNo; //结算账户账号
public $acctName; //结算账户名称
public $acctTypeCode; //结算账户性质( 57 对公 58 对私)
public $settlePeriod; //结算周期
public $retUrl; //回调地址
public $feeData; //费率信息集合
public function setVersion($version) {
$this->version = $version;
}
public function getVersion($version) {
return $this->version;
}
/**
* @return mixed
*/
public function getMerBlis()
{
return $this->merBlis;
}
/**
* @param mixed $merBlis
* @return MerchantNetForm
*/
public function setMerBlis($merBlis)
{
$this->merBlis = $merBlis;
return $this;
}
/**
* @return mixed
*/
public function getOrderNo()
{
return $this->orderNo;
}
/**
* @param mixed $orderNo
* @return MerchantNetForm
*/
public function setOrderNo($orderNo)
{
$this->orderNo = $orderNo;
return $this;
}
/**
* @return mixed
*/
public function getPosType()
{
return $this->posType;
}
/**
* @param mixed $posType
* @return MerchantNetForm
*/
public function setPosType($posType)
{
$this->posType = $posType;
return $this;
}
/**
* @return mixed
*/
public function getOrgCode()
{
return $this->orgCode;
}
/**
* @param mixed $orgCode
* @return MerchantNetForm
*/
public function setOrgCode($orgCode)
{
$this->orgCode = $orgCode;
return $this;
}
/**
* @return mixed
*/
public function getMerRegName()
{
return $this->merRegName;
}
/**
* @param mixed $merRegName
* @return MerchantNetForm
*/
public function setMerRegName($merRegName)
{
$this->merRegName = $merRegName;
return $this;
}
/**
* @return string
*/
public function getMerRegDistCode()
{
return $this->merRegDistCode;
}
/**
* @param string $merRegDistCode
* @return MerchantNetForm
*/
public function setMerRegDistCode($merRegDistCode)
{
$this->merRegDistCode = $merRegDistCode;
return $this;
}
/**
* @return mixed
*/
public function getMerRegAddr()
{
return $this->merRegAddr;
}
/**
* @param mixed $merRegAddr
* @return MerchantNetForm
*/
public function setMerRegAddr($merRegAddr)
{
$this->merRegAddr = $merRegAddr;
return $this;
}
/**
* @return mixed
*/
public function getMccCode()
{
return $this->mccCode;
}
/**
* @param mixed $mccCode
* @return MerchantNetForm
*/
public function setMccCode($mccCode)
{
$this->mccCode = $mccCode;
return $this;
}
/**
* @return mixed
*/
public function getMerBlisStDt()
{
return $this->merBlisStDt;
}
/**
* @param mixed $merBlisStDt
* @return MerchantNetForm
*/
public function setMerBlisStDt($merBlisStDt)
{
$this->merBlisStDt = $merBlisStDt;
return $this;
}
/**
* @return mixed
*/
public function getMerBlisExpDt()
{
return $this->merBlisExpDt;
}
/**
* @param mixed $merBlisExpDt
* @return MerchantNetForm
*/
public function setMerBlisExpDt($merBlisExpDt)
{
$this->merBlisExpDt = $merBlisExpDt;
return $this;
}
/**
* @return mixed
*/
public function getMerBusiContent()
{
return $this->merBusiContent;
}
/**
* @param mixed $merBusiContent
* @return MerchantNetForm
*/
public function setMerBusiContent($merBusiContent)
{
$this->merBusiContent = $merBusiContent;
return $this;
}
/**
* @return mixed
*/
public function getLarName()
{
return $this->larName;
}
/**
* @param mixed $larName
* @return MerchantNetForm
*/
public function setLarName($larName)
{
$this->larName = $larName;
return $this;
}
/**
* @return mixed
*/
public function getLarIdType()
{
return $this->larIdType;
}
/**
* @param mixed $larIdType
* @return MerchantNetForm
*/
public function setLarIdType($larIdType)
{
$this->larIdType = $larIdType;
return $this;
}
/**
* @return mixed
*/
public function getLarIdcard()
{
return $this->larIdcard;
}
/**
* @param mixed $larIdcard
* @return MerchantNetForm
*/
public function setLarIdcard($larIdcard)
{
$this->larIdcard = $larIdcard;
return $this;
}
/**
* @return mixed
*/
public function getLarIdcardStDt()
{
return $this->larIdcardStDt;
}
/**
* @param mixed $larIdcardStDt
* @return MerchantNetForm
*/
public function setLarIdcardStDt($larIdcardStDt)
{
$this->larIdcardStDt = $larIdcardStDt;
return $this;
}
/**
* @return mixed
*/
public function getLarIdcardExpDt()
{
return $this->larIdcardExpDt;
}
/**
* @param mixed $larIdcardExpDt
* @return MerchantNetForm
*/
public function setLarIdcardExpDt($larIdcardExpDt)
{
$this->larIdcardExpDt = $larIdcardExpDt;
return $this;
}
/**
* @return mixed
*/
public function getMerContactMobile()
{
return $this->merContactMobile;
}
/**
* @param mixed $merContactMobile
* @return MerchantNetForm
*/
public function setMerContactMobile($merContactMobile)
{
$this->merContactMobile = $merContactMobile;
return $this;
}
/**
* @return mixed
*/
public function getMerContactName()
{
return $this->merContactName;
}
/**
* @param mixed $merContactName
* @return MerchantNetForm
*/
public function setMerContactName($merContactName)
{
$this->merContactName = $merContactName;
return $this;
}
/**
* @return mixed
*/
public function getOpenningBankCode()
{
return $this->openningBankCode;
}
/**
* @param mixed $openningBankCode
* @return MerchantNetForm
*/
public function setOpenningBankCode($openningBankCode)
{
$this->openningBankCode = $openningBankCode;
return $this;
}
/**
* @return mixed
*/
public function getOpenningBankName()
{
return $this->openningBankName;
}
/**
* @param mixed $openningBankName
* @return MerchantNetForm
*/
public function setOpenningBankName($openningBankName)
{
$this->openningBankName = $openningBankName;
return $this;
}
/**
* @return mixed
*/
public function getClearingBankCode()
{
return $this->clearingBankCode;
}
/**
* @param mixed $clearingBankCode
* @return MerchantNetForm
*/
public function setClearingBankCode($clearingBankCode)
{
$this->clearingBankCode = $clearingBankCode;
return $this;
}
/**
* @return mixed
*/
public function getAcctNo()
{
return $this->acctNo;
}
/**
* @param mixed $acctNo
* @return MerchantNetForm
*/
public function setAcctNo($acctNo)
{
$this->acctNo = $acctNo;
return $this;
}
/**
* @return mixed
*/
public function getAcctName()
{
return $this->acctName;
}
/**
* @param mixed $acctName
* @return MerchantNetForm
*/
public function setAcctName($acctName)
{
$this->acctName = $acctName;
return $this;
}
/**
* @return mixed
*/
public function getAcctTypeCode()
{
return $this->acctTypeCode;
}
/**
* @param mixed $acctTypeCode
* @return MerchantNetForm
*/
public function setAcctTypeCode($acctTypeCode)
{
$this->acctTypeCode = $acctTypeCode;
return $this;
}
/**
* @return mixed
*/
public function getSettlePeriod()
{
return $this->settlePeriod;
}
/**
* @param mixed $settlePeriod
* @return MerchantNetForm
*/
public function setSettlePeriod($settlePeriod)
{
$this->settlePeriod = $settlePeriod;
return $this;
}
/**
* @return mixed
*/
public function getRetUrl()
{
return $this->retUrl;
}
/**
* @param mixed $retUrl
* @return MerchantNetForm
*/
public function setRetUrl($retUrl)
{
$this->retUrl = $retUrl;
return $this;
}
/**
* @return mixed
*/
public function getFeeData()
{
return $this->feeData;
}
/**
* @param mixed $feeData
* @return MerchantNetForm
*/
public function setFeeData($feeData = [])
{
if (!empty($feeData)) {
$this->feeData = $feeData;
} else {
$this->feeData = [
[
"feeRateTypeCode" => "300",
"feeRatePct" => "0.38",
"feeUpperAmtPcnt" => "20",
"feeLowerAmtPcnt" => "10"
],
[
"feeRateTypeCode" => "301",
"feeRatePct" => "0.58"
],
[
"feeRateTypeCode" => "302",
"feeRatePct" => "0.48"
],
[
"feeRateTypeCode" => "303",
"feeRatePct" => "0.48"
]
];
}
return $this;
}
public function toArray() {
$array = (array) $this;
foreach ($array as $key => $value) {
if ($value === null || $value === '') {
unset($array[$key]);
}
}
return $array;
}
}
<?php
namespace common\libraries\lakala\merchant;
use common\libraries\lakala\RequestService;
use common\models\db\MerchantNetApply;
/**
* 拉卡拉商户入网
* Class MerchantNetService
*/
class MerchantNetService
{
public $reqId = '48066e7ce3551149cd9ebdaf924582794137feb6';
public $returnUrl = 'http://xxx/api/lakala/contract-notify';
/**
* @param $reqId
*/
public function setReqId($reqId) {
$this->reqId = $reqId;
}
/**
* @return string
*/
public function getReqId() {
return $this->reqId;
}
/**
* 构造商户入网请求参数
* @param MerchantNetApply $merchantNetApply
* @return array|MerchantNetForm
*/
public function merchantNetApplyToArray(MerchantNetApply $merchantNetApply) {
$merchantNetForm = new MerchantNetForm();
$merchantNetForm->setOrderNo($merchantNetApply->order_no);
$merchantNetForm->setPosType($merchantNetApply->post_type);
$merchantNetForm->setMerRegName($merchantNetApply->merchant_name);
$merchantNetForm->setMerRegDistCode($merchantNetApply->district_id);
$merchantNetForm->setMerRegAddr($merchantNetApply->business_address);
$merchantNetForm->setMccCode($merchantNetApply->mcc_code);
$merchantNetForm->setMerBlis($merchantNetApply->business_license_number);
$merchantNetForm->setMerBlisStDt($merchantNetApply->business_license_start_date);
$merchantNetForm->setMerBlisExpDt($merchantNetApply->business_license_end_date);
$merchantNetForm->setMerBusiContent($merchantNetApply->business_content);
$merchantNetForm->setLarName($merchantNetApply->legal_name);
$merchantNetForm->setLarIdType($merchantNetApply->legal_id_type);
$merchantNetForm->setLarIdcard($merchantNetApply->legal_id_number);
$merchantNetForm->setLarIdcardStDt($merchantNetApply->legal_id_start_date);
$merchantNetForm->setLarIdcardExpDt($merchantNetApply->legal_id_expire_date);
$merchantNetForm->setMerContactMobile($merchantNetApply->contract_mobile);
$merchantNetForm->setMerContactName($merchantNetApply->contract_name);
$merchantNetForm->setAcctName($merchantNetApply->account_name);
$merchantNetForm->setAcctNo($merchantNetApply->account_no);
$merchantNetForm->setAcctTypeCode($merchantNetApply->account_type_code);
$merchantNetForm->setOpenningBankCode($merchantNetApply->openning_bank_code);
$merchantNetForm->setOpenningBankName($merchantNetApply->openning_bank_name);
$merchantNetForm->setClearingBankCode($merchantNetApply->clearing_bank_code);
$merchantNetForm->setFeeData();
return $merchantNetForm;
}
/**
* 新填商户进件
* @param MerchantNetApply|\yii\db\ActiveRecord $merchantNetApply
*/
public function addMerchant(MerchantNetApply $merchantNetApply) {
$merchantNetForm = $this->merchantNetApplyToArray($merchantNetApply);
$merchantNetForm->setVersion('1.0');
$merchantNetForm->setOrgCode('1');
$merchantNetForm->setSettlePeriod('T+1');
$merchantNetApply->fee_data_json = json_encode($merchantNetForm->getFeeData());
$merchantNetApply->create_time = date('Y-m-d H:i:s');
$merchantNetForm = $merchantNetForm->toArray();
$merchantNetForm['retUrl'] = $this->returnUrl;
$requestService = new RequestService();
if($result = $requestService->send('api/v2/mms/openApi/addMer', $this->commonData($merchantNetForm))) {
$merchantNetApply->contract_id = $result['respData']['contractId'];
$merchantNetApply->update_time = date('Y-m-d H:i:s');
if (!$merchantNetApply->save()) {
throw new \RuntimeException('保存失败'.implode('', $merchantNetApply->getFirstErrors()));
}
} else {
throw new \RuntimeException($requestService->getErrorMessage(), '-1');
}
}
/**
* 商户信息变更
* @param MerchantNetApply|\yii\db\ActiveRecord $merchantNetApply
*/
public function changeMerchant(MerchantNetApply $merchantNetApply) {
$merchantNetForm = $this->merchantNetApplyToArray($merchantNetApply);
$merchantNetForm->setVersion('1.0');
$merchantNetForm->setOrgCode('1');
$merchantNetForm->setSettlePeriod('T+1');
$merchantNetForm = $merchantNetForm->toArray();
$merchantNetForm['retUrl'] = $this->returnUrl;
$merchantNetForm['merInnerNo'] = $merchantNetApply->merchant_inner_no;
$merchantNetForm['merCupNo'] = $merchantNetApply->unionpay_no;
$requestService = new RequestService();
if($result = $requestService->send('api/v2/mms/openApi/changeMer', $this->commonData($merchantNetForm))) {
$merchantNetApply->contract_id = $result['respData']['contractId'];
$merchantNetApply->update_time = date('Y-m-d H:i:s');
if (!$merchantNetApply->save()) {
throw new \RuntimeException('保存失败'.implode('', $merchantNetApply->getFirstErrors()));
}
} else {
throw new \RuntimeException($requestService->getErrorMessage(), '-1');
}
}
/**
* 入网进件检验
* @param MerchantNetApply $merchantNetApply
*/
public function verifyContractInfo(MerchantNetApply $merchantNetApply) {
$merchantNetForm = new MerchantNetForm();
$merchantNetForm->setMerRegName($merchantNetApply->merchant_name);
$merchantNetForm->setMerBlis($merchantNetApply->business_license_number);
$merchantNetForm->setLarIdcard($merchantNetApply->legal_id_number);
$merchantNetForm->setAcctNo($merchantNetApply->account_no);
$merchantNetForm->setVersion('1.0');
$merchantNetForm->setOrderNo(UtilsService::getOrderNumber());
$merchantNetForm->setOrgCode('1');
$merchantNetForm = $merchantNetForm->toArray();
$requestService = new RequestService();
if($result = $requestService->send('api/v2/mms/openApi/verifyContractInfo', $this->commonData($merchantNetForm))) {
if (!empty($result['retMsg'])) {
throw new \RuntimeException($result['retMsg'], '-1');
}
} else {
throw new \RuntimeException($requestService->getErrorMessage(), '-1');
}
}
/**
* 进件查询
* @param MerchantNetApply $merchantNetApply
*/
public function queryContract(MerchantNetApply $merchantNetApply) {
$data = [
"version" => "1.0",
"orderNo" => "{$merchantNetApply->order_no}",
"orgCode" => "1",
"contractId" => "{$merchantNetApply->contract_id}"
];
$requestService = new RequestService();
if ($result = $requestService->send('api/v2/mms/openApi/queryContract', $this->commonData($data))) {
if (isset($result['code']) && $result['code'] === '000000') {
$this->sychMerchantContractAuditInfo($result['data']);
} else {
throw new \RuntimeException('人工审核中');
}
} else {
throw new \RuntimeException($requestService->getErrorMessage(), '-1');
}
}
/**
* 结算信息变更
* @param MerchantNetApply $merchantNetApply
*/
public function changeSett(MerchantNetApply $merchantNetApply) {
}
/**
* 附件上传
* @param string $attType 拉卡拉附件类型枚举
* @param string $filePath 文件路径
* @param string $ext 文件后缀
* @return array|\RuntimeException
*/
public function uploadFile($attType, $filePath, $ext) {
$data = [
"version" => "1.0",
"orderNo" => UtilsService::getOrderNumber(),
"attType" => $attType,
"attExtName" => $ext,
"attContext" => base64_encode(file_get_contents($filePath)),
"orgCode" => 1
];
$requestService = new RequestService();
if($result = $requestService->send('api/v2/mms/openApi/uploadFile', $this->commonData($data))) {
return $result;
} else {
throw new \RuntimeException($requestService->getErrorMessage(), '-1');
}
}
/**
* 商户信息查询
* @param string $merInnerNo 拉卡拉内部商户号
* @return array|\RuntimeException
*/
public function queryMerchant($merInnerNo) {
$data = [
"version" => "1.0",
"orderNo" => UtilsService::getOrderNumber(),
"merInnerNo" => $merInnerNo,
"orgCode" => 1,
];
$requestService = new RequestService();
if ($result = $requestService->send('api/v2/mms/openApi/queryMerchant', $this->commonData($data))) {
return $result['data'];
} else {
throw new \RuntimeException($requestService->getErrorMessage(), '-1');
}
}
/**
* 商户信息查询
* @param string $cardNo 银行卡号
* @return array|\RuntimeException
*/
public function cardBin($cardNo) {
$data = [
"version" => "1.0",
"orderNo" => UtilsService::getOrderNumber(),
"cardNo" => $cardNo,
"orgCode" => 1,
];
$requestService = new RequestService();
if ($result = $requestService->send('api/v2/mms/openApi/cardBin', $this->commonData($data))) {
return $result['respData'];
} else {
throw new \RuntimeException($requestService->getErrorMessage(), '-1');
}
}
/**
* 商户公共请求参数
* @param $data
* @return array
*/
private function commonData($data) {
return [
"ver" => "1.0.0",
"timestamp" => time(),
"rnd" => UtilsService::uniqueStr(),
"reqId" => "baff59de4694438ca9089862253517a5",
"reqData" => $data
];
}
/**
* 进件审核状态列表
* @return string[]
*/
private static function contractStatusList() {
return [
'NO_COMMIT' => '未提交',
'COMMIT' => '已提交',
'COMMIT_FAIL' => '提交失败',
'MANUAL_AUDIT' => '转人工审核',
'REVIEW_ING' => '审核中',
'WAIT_FOR_CONTACT' => '审核通过',
'INNER_CHECK_REJECTED' => '审核驳回',
];
}
/**
* 获取进件审核状态名称
* @param $status
* @return string
*/
public static function getContractStatus($status) {
$list = self::contractStatusList();
return isset($list[$status]) ? $list[$status] : '';
}
/**
* 商户入网进件结果更新
* @param array $data 商户进件查询或进件回调成功返回参数
* @return \RuntimeException
*/
public function sychMerchantContractAuditInfo(array $data) {
$merchantNetApply = MerchantNetApply::find()->where(['order_no' => $data['orderNo'], 'contract_id' => $data['contractId']])->one();
if (!$merchantNetApply) {
throw new \RuntimeException('没有相关进件信息');
}
if ($merchantNetApply->status == 1) {
throw new \RuntimeException('已审核通过无需操作');
}
$merchantNetApply->contract_status = $data['contractStatus'];
if ($merchantNetApply->contract_status == 'WAIT_FOR_CONTACT') {
$merchantNetApply->status = 1;
$merchantNetApply->merchant_inner_no = $data['merInnerNo'];
$merchantNetApply->unionpay_no = $data['merCupNo'];
} else if($merchantNetApply->contract_status == 'INNER_CHECK_REJECTED') {
$merchantNetApply->status = 2;
$merchantNetApply->audit_message = $data['contractMemo'];
}
$merchantNetApply->update_time = date('Y-m-d H:i:s');
if (!$merchantNetApply->save()) {
throw new \RuntimeException(implode("", $merchantNetApply->getFirstErrors()), '-1');
}
}
}
<?php
namespace common\libraries\lakala\merchant;
/**
* 工具类 service
* Class UtilsService
* @package common\libraries\lakala\merchant
*/
class UtilsService
{
/**
* 获取随机订单号
* @return string
*/
public static function getOrderNumber() {
return time().rand(1000000, 9999999);
}
/**
* 获取随机字符
* @return string
*/
public static function uniqueStr() {
return uniqid().rand(10000, 99999).rand(50000, 89999);
}
/**
* 转utf8编码
* @param $str
* @return array|false|string|string[]|null
*/
function strToUtf8($str)
{
$encode = mb_detect_encoding($str, array("ASCII", 'UTF-8', "GB2312", "GBK", 'BIG5'));
if ($encode == 'UTF-8') {
return $str;
} else {
return mb_convert_encoding($str, 'UTF-8', $encode);
}
}
/**
* 商户地区代码
* @return int
*/
public function getMerRegDistCode() {
$list = [
"全国" => "1",
];
return '1';
}
/**
* 获取MCC 列表
* @return array[]
*/
public function getMCCList() {
return [
['label' => '餐娱类', 'value' => 0, 'children' => [
['value' => '5094', 'label' => '贵重珠宝、首饰,钟表零售'],
['value' => '5811', 'label' => '包办伙食,宴会承包商'],
['value' => 5812, 'label' => '就餐场所和餐馆'],
['value' => 5813, 'label' => '饮酒场所(酒吧、酒馆、夜总会、鸡尾酒大厅、迪斯科舞厅)'],
['value' => 5932, 'label' => '古玩店——出售、维修及还原'],
['value' => 5937, 'label' => '古玩复制店'],
['value' => 5944, 'label' => '银器店'],
['value' => 5950, 'label' => '玻璃器皿和水晶饰品店'],
['value' => 5970, 'label' => '工艺美术商店'],
['value' => 5971, 'label' => '艺术商和画廊'],
['value' => 7011, 'label' => '住宿服务(旅馆、酒店、汽车旅馆、度假村等)'],
['value' => 7012, 'label' => '分时使用的别墅或度假用房'],
['value' => 7032, 'label' => '运动和娱乐露营地'],
['value' => 7033, 'label' => '活动房车场及露营场所'],
['value' => 7297, 'label' => '按摩店'],
['value' => 7298, 'label' => '保健及美容SPA'],
['value' => 7631, 'label' => '手表、钟表和首饰维修店'],
['value' => 7829, 'label' => '电影和录像创作、发行'],
['value' => 7911, 'label' => '歌舞厅'],
['value' => 7922, 'label' => '戏剧制片(不含电影)、演出和票务'],
['value' => 7929, 'label' => '未列入其他代码的乐队、文艺表演'],
['value' => 7932, 'label' => '台球、撞球场所'],
['value' => 7933, 'label' => '保龄球馆'],
['value' => 7941, 'label' => '商业体育场馆、职业体育俱乐部、运动场和体育推广公司'],
['value' => 7992, 'label' => '公共高尔夫球场'],
['value' => 7994, 'label' => '大型游戏机和游戏场所'],
['value' => 7996, 'label' => '游乐园、马戏团、嘉年华、占卜'],
['value' => 7997, 'label' => '会员俱乐部(体育、娱乐、运动等)、乡村俱乐部以及私人高尔夫课程班'],
['value' => 7998, 'label' => '水族馆、海洋馆和海豚馆'],
['value' => 7999, 'label' => '未列入其他代码的娱乐服务'],
]
],
['label' => '餐娱类(房产汽车)', 'value' => 1, 'children' => [
['value' => 1520, 'label' => '一般承包商-住宅与商业楼'],
['value' => 5511, 'label' => '汽车货车经销商-新旧车的销售、服务、维修、零件及出租'],
['value' => 5521, 'label' => '汽车货车经销商-专门从事旧车的销售、服务、维修、零件及出租'],
['value' => 5551, 'label' => '船只销售商'],
['value' => 5561, 'label' => '旅行拖车、娱乐用车销售商'],
['value' => 5571, 'label' => '摩托车商店和经销商'],
['value' => 5592, 'label' => '露营、房车销售商'],
['value' => 5598, 'label' => '雪车商'],
['value' => 5599, 'label' => '汽车、飞行器、农用机车综合经营商'],
['value' => 5933, 'label' => '典当、拍卖、信托'],
['value' => 6012, 'label' => '金融机构-商品和服务'],
['value' => 5998, 'label' => '其他批发商'],
['value' => 7013, 'label' => '不动产代理——房地产经纪'],
]
],
['label' => '民生类', 'value' => 2, 'children' => [
['value' => 3998, 'label' => '中国人民共和国铁道部'],
['value' => 4111, 'label' => '本市和市郊通勤旅客运输(包括轮渡)'],
['value' => 4112, 'label' => '铁路客运'],
['value' => 4121, 'label' => '出租车服务'],
['value' => 4131, 'label' => '公路客运'],
['value' => 4511, 'label' => '航空公司'],
['value' => 4784, 'label' => '路桥通行费'],
['value' => 4814, 'label' => '电信服务,包括本地和长途电话、信用卡电话、磁卡电话和传真'],
['value' => 4899, 'label' => '有线和其他付费电视服务'],
['value' => 4900, 'label' => '公共事业(电力、煤气、自来水、清洁服务)'],
['value' => 5411, 'label' => '大型仓储式超级市场'],
['value' => 5541, 'label' => '加油站、服务站'],
['value' => 5542, 'label' => '自助加油站'],
['value' => 5722, 'label' => '家用电器商店'],
['value' => 5960, 'label' => '直销-保险直销'],
['value' => 5994, 'label' => '报亭、报摊'],
['value' => 7523, 'label' => '停车场'],
['value' => 8651, 'label' => '政治组织(政府机构)'],
['value' => 9211, 'label' => '法庭费用,包括赡养费和子女抚养费'],
['value' => 9222, 'label' => '罚款'],
['value' => 9223, 'label' => '保释金'],
['value' => 9311, 'label' => '纳税'],
['value' => 9399, 'label' => '未列入其他代码的政府服务(社会保障服务,国家强制)'],
['value' => 9400, 'label' => '使领馆收费'],
['value' => 9402, 'label' => '国家邮政服务']
]
],
['label' => '公益类', 'value' => 3, 'children' => [
['value' => 8062, 'label' => '公立医院'],
['value' => 8211, 'label' => '中小学校(公立)'],
['value' => 8220, 'label' => '普通高校(公立)'],
['value' => 8398, 'label' => '慈善和社会公益服务组织']
]
],
['label' => '一般类', 'value' => 4, 'children' => [
['value' => 0742, 'label' => '兽医服务'],
['value' => 0763, 'label' => '农业合作'],
['value' => '0780', 'label' => '景观美化及园艺服务'],
['value' => 4011, 'label' => '铁路运输'],
['value' => 4119, 'label' => '救护车服务'],
['value' => 4214, 'label' => '货物搬运和托运—当地和长途,移动和存储公司,以及当地递送服务'],
['value' => 4215, 'label' => '快递服务(空运、地面运输或海运)'],
['value' => 4225, 'label' => '公共仓储服务-农产品、冷冻品和家用产品'],
['value' => 4411, 'label' => '轮船及巡游航线服务'],
['value' => 4457, 'label' => '出租船只'],
['value' => 4468, 'label' => '船舶、海运服务提供商'],
['value' => 4582, 'label' => '机场服务'],
['value' => 4722, 'label' => '旅行社'],
['value' => 4733, 'label' => '大型景区售票'],
['value' => 4789, 'label' => '未列入其他代码的运输服务'],
['value' => 4812, 'label' => '通讯设备和电话销售'],
['value' => 4816, 'label' => '计算机网络/信息服务'],
['value' => 4821, 'label' => '电报服务'],
['value' => 5211, 'label' => '木材和各类建材卖场'],
['value' => 5231, 'label' => '玻璃、油漆涂料、墙纸零售'],
['value' => 5251, 'label' => '五金商店'],
['value' => 5261, 'label' => '草坪、花园用品商店'],
['value' => 5310, 'label' => '折扣商店'],
['value' => 5311, 'label' => '百货商店'],
['value' => 5331, 'label' => '各类杂货店、便利店'],
['value' => 5399, 'label' => '其他综合零售'],
['value' => 5422, 'label' => '各类肉类零售商'],
['value' => 5441, 'label' => '糖果及坚果商店'],
['value' => 5451, 'label' => '乳制品店、冷饮店'],
['value' => 5462, 'label' => '面包房、糕点商店'],
['value' => 5499, 'label' => '各类食品店及专门食品零售店'],
['value' => 5532, 'label' => '汽车轮胎经销商'],
['value' => 5533, 'label' => '汽车零配件商店'],
['value' => 5611, 'label' => '男子和男童服装及用品商店'],
['value' => 5621, 'label' => '妇女成衣商店'],
['value' => 5631, 'label' => '女性用品商店'],
['value' => 5641, 'label' => '婴儿、儿童服装店'],
['value' => 5651, 'label' => '家庭服装商店'],
['value' => 5655, 'label' => '运动服饰商店'],
['value' => 5661, 'label' => '鞋店'],
['value' => 5681, 'label' => '皮货店'],
['value' => 5691, 'label' => '成人成衣店'],
['value' => 5697, 'label' => '裁缝、修补、改衣店'],
['value' => 5698, 'label' => '假发商店'],
['value' => 5699, 'label' => '各类服装及饰物店'],
['value' => 5712, 'label' => '家具、家庭摆品、家用设备零售商'],
['value' => 5713, 'label' => '地板商店'],
['value' => 5714, 'label' => '帏帐、窗帘、室内装潢商店'],
['value' => 5718, 'label' => '壁炉、壁炉防护网及配件商店'],
['value' => 5719, 'label' => '各种家庭装饰专营店'],
['value' => 5732, 'label' => '电子设备商店'],
['value' => 5733, 'label' => '音乐商店-乐器、钢琴、乐谱'],
['value' => 5734, 'label' => '计算机软件商店'],
['value' => 5735, 'label' => '音像制品商店'],
['value' => 5814, 'label' => '快餐店'],
['value' => 5912, 'label' => '药房、药店'],
['value' => 5921, 'label' => '瓶装酒零售店'],
['value' => 5931, 'label' => '旧商品店、二手商品店'],
['value' => 5935, 'label' => '海上船只遇难救助'],
['value' => 5940, 'label' => '自行车商店'],
['value' => 5941, 'label' => '体育用品店'],
['value' => 5942, 'label' => '书店'],
['value' => 5943, 'label' => '文具用品商店、各类办公用品商店'],
['value' => 5945, 'label' => '玩具、游戏店'],
['value' => 5946, 'label' => '照相器材商店'],
['value' => 5947, 'label' => '礼品、卡片、装饰品、纪念品商店'],
['value' => 5948, 'label' => '箱包、皮具店'],
['value' => 5949, 'label' => '纺织品及针织品零售'],
['value' => 5962, 'label' => '旅游相关服务直销'],
['value' => 5963, 'label' => '门对门销售'],
['value' => 5964, 'label' => '目录销售商户'],
['value' => 5965, 'label' => '目录、零售兼营商户'],
['value' => 5966, 'label' => '电话呼出直销'],
['value' => 5967, 'label' => '电话呼入直销'],
['value' => 5968, 'label' => '订阅/订购直销服务'],
['value' => 5969, 'label' => '其他直销商户'],
['value' => 5972, 'label' => '邮票和纪念币商店'],
['value' => 5973, 'label' => '宗教品商店'],
['value' => 5975, 'label' => '助听器-销售、服务和用品'],
['value' => 5976, 'label' => '假肢店(整形外科用品、辅助设备)'],
['value' => 5977, 'label' => '化妆品商店'],
['value' => 5978, 'label' => '打字机商店—销售、服务和出租'],
['value' => 5983, 'label' => '燃料经销商-燃油、木材、煤炭和液化石油'],
['value' => 5992, 'label' => '花店'],
['value' => 5993, 'label' => '香烟、雪茄专卖店'],
['value' => 5995, 'label' => '宠物商店、宠物食品及用品'],
['value' => 5996, 'label' => '游泳池-销售、供应和服务'],
['value' => 5997, 'label' => '电动剃须刀商店-销售和服务'],
['value' => 5999, 'label' => '其他专门零售店'],
['value' => 6010, 'label' => '金融机构-人工现金支付'],
['value' => 6011, 'label' => '金融机构-自动现金支付'],
['value' => 6051, 'label' => '非金融机构-外币兑换、非电子转账的汇票、临时支付凭证和旅行支票'],
['value' => 6211, 'label' => '证券公司-经纪人和经销商'],
['value' => 6513, 'label' => '不动产管理-物业管理'],
['value' => 7210, 'label' => '洗衣店'],
['value' => 7211, 'label' => '洗熨服务(自助洗衣服务)'],
['value' => 7216, 'label' => '干洗店'],
['value' => 7217, 'label' => '室内清洁服务(地毯、沙发、家具表面的清洁服务)'],
['value' => 7221, 'label' => '摄影工作室'],
['value' => 7230, 'label' => '美容理发店'],
['value' => 7251, 'label' => '修鞋店、擦鞋店、帽子清洗店'],
['value' => 7261, 'label' => '殡葬服务'],
['value' => 7273, 'label' => '婚姻介绍及陪同服务'],
['value' => 7276, 'label' => '税收准备服务'],
['value' => 7277, 'label' => '咨询服务-债务、婚姻和私人事务'],
['value' => 7278, 'label' => '购物服务及会所(贸易、经纪服务)'],
['value' => 7295, 'label' => '家政服务'],
['value' => 7296, 'label' => '出租衣物-服装、制服和正式场合服装'],
['value' => 7299, 'label' => '未列入其他代码的其他个人服务'],
['value' => 7311, 'label' => '广告服务'],
['value' => 7321, 'label' => '消费者信用报告机构'],
['value' => 7333, 'label' => '商业摄影、工艺、绘图服务'],
['value' => 7338, 'label' => '复印及绘图服务'],
['value' => 7339, 'label' => '速记、秘书服务(包括各类办公服务)'],
['value' => 7342, 'label' => '灭虫及消毒服务'],
['value' => 7349, 'label' => '清洁、保养及门卫服务'],
['value' => 7361, 'label' => '职业中介、临时工'],
['value' => 7372, 'label' => '计算机编程、数据处理和系统集成设计服务'],
['value' => 7375, 'label' => '信息检索服务'],
['value' => 7379, 'label' => '未列入其他代码的计算机维护和修理服务'],
['value' => 7392, 'label' => '管理、咨询和公共关系服务'],
['value' => 7393, 'label' => '侦探、保安、安全服务'],
['value' => 7394, 'label' => '设备、工具、家具和电器出租'],
['value' => 7395, 'label' => '照相洗印服务'],
['value' => 7399, 'label' => '未列入其他代码的商业服务'],
['value' => 7512, 'label' => '汽车出租'],
['value' => 7513, 'label' => '卡车及拖车出租'],
['value' => 7519, 'label' => '房车和娱乐车辆出租'],
['value' => 7531, 'label' => '车体维修店'],
['value' => 7534, 'label' => '轮胎翻新、维修店'],
['value' => 7535, 'label' => '汽车喷漆店'],
['value' => 7538, 'label' => '汽车服务商店(非经销商)'],
['value' => 7542, 'label' => '洗车'],
['value' => 7549, 'label' => '拖车服务'],
['value' => 7622, 'label' => '电器设备维修'],
['value' => 7623, 'label' => '空调、制冷设备维修'],
['value' => 7629, 'label' => '电器设备、小家电维修'],
['value' => 7641, 'label' => '家具维修、翻新'],
['value' => 7692, 'label' => '焊接维修服务'],
['value' => 7699, 'label' => '各类维修店及相关服务'],
['value' => 7832, 'label' => '电影院'],
['value' => 7841, 'label' => '音像制品出租商店'],
['value' => 7991, 'label' => '旅游与展览'],
['value' => 7993, 'label' => '电子游戏供给'],
['value' => 7995, 'label' => '彩票销售'],
['value' => 8011, 'label' => '其他医疗卫生活动'],
['value' => 8021, 'label' => '牙科医生'],
['value' => 8031, 'label' => '正骨医生'],
['value' => 8041, 'label' => '按摩医生'],
['value' => 8042, 'label' => '眼科医生'],
['value' => 8043, 'label' => '光学产品、眼镜店'],
['value' => 8049, 'label' => '手足病医生'],
['value' => 8050, 'label' => '护理和照料服务'],
['value' => 8071, 'label' => '医学及牙科实验室'],
['value' => 8099, 'label' => '其他医疗保健服务'],
['value' => 8111, 'label' => '法律服务和律师事务所服务'],
['value' => 8241, 'label' => '函授学校(成人教育)'],
['value' => 8244, 'label' => '商业和文秘学校(中等专业学校)'],
['value' => 8249, 'label' => '贸易和职业学校(职业技能培训)'],
['value' => 8299, 'label' => '其他学校和教育服务'],
['value' => 8351, 'label' => '儿童保育服务(含学前教育)'],
['value' => 8641, 'label' => '市民、社会及友爱组织'],
['value' => 8661, 'label' => '宗教组织'],
['value' => 8675, 'label' => '汽车协会'],
['value' => 8699, 'label' => '其他会员组织'],
['value' => 8911, 'label' => '建筑、工程和测量服务'],
['value' => 8912, 'label' => '装修、装潢、园艺'],
['value' => 8931, 'label' => '会计、审计、财务服务'],
['value' => 8999, 'label' => '未列入其他代码的专业服务'],
]
],
['label' => '一般类(批发)', 'value' => 5, 'children' => [
['value' => 4458, 'label' => '烟草配送商户'],
['value' => 5013, 'label' => '机动车供应及零配件(批发商)'],
['value' => 5021, 'label' => '办公及商务家具(批发商)'],
['value' => 5039, 'label' => '未列入其他代码的建材批发(批发商)'],
['value' => 5044, 'label' => '办公、影印及微缩摄影器材(批发商)'],
['value' => 5045, 'label' => '计算机、计算机外围设备(批发商)'],
['value' => 5046, 'label' => '未列入其他代码的商用器材(批发商)'],
['value' => 5047, 'label' => '牙科/实验室/医疗/眼科医院器材和用品(批发商)'],
['value' => 5051, 'label' => '金属产品服务商和公司(批发商)'],
['value' => 5065, 'label' => '电器零件和设备(批发商)'],
['value' => 5072, 'label' => '三金器材及用品(批发商)'],
['value' => 5074, 'label' => '管道和供暖设备(批发商)'],
['value' => 5111, 'label' => '文具、办公用品、复印纸和书写纸(批发商)'],
['value' => 5122, 'label' => '药品、药品经营者(批发商)'],
['value' => 5131, 'label' => '布料、缝纫用品和其他纺织品(批发商)'],
['value' => 5137, 'label' => '男女及儿童制服和服装(批发商)'],
['value' => 5139, 'label' => '鞋类(批发商)'],
['value' => 5172, 'label' => '石油及石油产品(批发商)'],
['value' => 5192, 'label' => '书、期刊和报纸(批发商)'],
['value' => 5193, 'label' => '花木栽种用品、苗木和花卉(批发商)'],
['value' => 5198, 'label' => '油漆、清漆用品(批发商)'],
['value' => 5271, 'label' => '活动房车销售商'],
['value' => 5398, 'label' => '大型企业批发'],
]
],
['label' => '特殊类', 'value' => 6, 'children' => [
['value' => 9498, 'label' => '信用卡还款']
]
]
];
}
/**
* 商户经营内容
* @return \string[][]
*/
public function getBusinessContentList() {
return [
['value' => '642', 'label' => '百货、中介、培训、景区门票等'],
['value' => '645', 'label' => '交通运输售票'],
['value' => '646', 'label' => '电气缴费'],
['value' => '647', 'label' => '政府类'],
['value' => '648', 'label' => '便民类'],
['value' => '649', 'label' => '公立医院、公立学校、慈善'],
['value' => '650', 'label' => '宾馆餐饮娱乐类'],
['value' => '651', 'label' => '房产汽车类'],
['value' => '652', 'label' => '批发类'],
['value' => '653', 'label' => '超市加油类'],
['value' => '654', 'label' => '一般类商户'],
['value' => '655', 'label' => '三农商户'],
];
}
/**
* 法人证件类型
* @return \string[][]
*/
public function getLegalIDTypeList() {
return [
['value' => '01', 'label' => '身份证'],
['value' => '02', 'label' => '护照'],
['value' => '03', 'label' => '港澳通行证'],
['value' => '04', 'label' => '台胞证'],
['value' => '99', 'label' => '其它证件'],
];
}
}
<?php
namespace common\libraries\lakala;
use common\libraries\lakala\merchant\UtilsService;
use common\libraries\WriteLogSrv;
/**
* 拉卡拉API请求
* Class RequestService
*/
class RequestService
{
public $apiUrl = 'https://test.wsmsd.cn/sit/'; //测试环境入口
//public $apiUrl = 'https://s2.lakala.com/'; //正式环境入口
public $publicKey = '/data/lakala/OP00000003_cert.pem'; //拉卡拉公钥文件
public $privateKeyFile = '/data/lakala/OP00000003_private_key.pem'; //商户私钥
public $appId = 'your appId'; //拉卡拉appId
public $serialNo = 'your serialNo'; //证书序列号
public $password = '';
public $signAlgorithm = 'LKLAPI-SHA256withRSA'; //签名算法
public $nonceStr = '';
public $timestamp = '';
protected $errorMessage = '';
public $orgCode = '1';
public function __construct()
{
$this->setNonceStr();
$this->setTimestamp();
}
/**
* 设置错误信息
* @param string $message
*/
private function setErrorMessage($message) {
$this->errorMessage = $message;
}
/**
* 获取错误信息
* @return string
*/
public function getErrorMessage() {
return $this->errorMessage;
}
/**
* 设置当前时间戳
*/
public function setTimestamp() {
$this->timestamp = time();
}
/**
* 获取当前时间戳
*/
public function getTimestamp() {
return $this->timestamp;
}
/**
* 获取随机字符串
* @return string
*/
public function getNonceStr() {
return $this->nonceStr;
}
/**
* 获取随机12位字符串
* @param string $nonceStr
*/
public function setNonceStr($nonceStr = '') {
if (!empty($nonceStr) && strlen($nonceStr) == 12) {
$this->nonceStr = $nonceStr;
} else {
$chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
$nonceStr = '';
for ($i = 0; $i < 12; $i++) {
$nonceStr .= $chars[mt_rand(0, strlen($chars) - 1)];
}
$this->nonceStr = $nonceStr;
}
}
/**
* 签名 ${appid}\n+${serialNo}\n+${timeStamp}\n+${nonceStr}\n+${body}\n
* @param $strSignSrc
* @return string
*/
public function handleSign($strSignSrc) {
$sign = "{$this->appId}\n";
if (!empty($this->serialNo)) {
$sign .= "{$this->serialNo}\n";
}
$sign .= "{$this->timestamp}\n";
$sign .= $this->nonceStr."\n";
$sign .= $strSignSrc."\n";
WriteLogSrv::writeLog("===拉卡拉签名字符串===: \n".$sign);
return $sign;
}
/**
* 测试
*/
public function test() {
$data = $sign = "";
$data = json_decode($data, true);
$strSignSrc = json_encode($data, 320);
$strSignSrc = $this->handleSign($strSignSrc);
/*$privateKey = file_get_contents($this->privateKeyFile);
$pKeyId = openssl_pkey_get_private($privateKey);
openssl_sign($strSignSrc, $signature, $pKeyId, OPENSSL_ALGO_SHA256);
openssl_free_key($pKeyId);
var_dump(base64_encode($signature));die;*/
$pubKeyId = openssl_get_publickey(file_get_contents($this->publicKey));
$flag = (bool) openssl_verify($strSignSrc, base64_decode($sign), $pubKeyId, OPENSSL_ALGO_SHA256);
openssl_free_key($pubKeyId);
var_dump($flag);
}
/**
* 拼接签名字符串
* @param array $body
* @return string $signature
*/
public function signStr(array $body) {
$strSignSrc = json_encode($body, 320);
return $this->handleSign($strSignSrc);
}
/**
* 签名
* @param $strSignSrc
* @return string
*/
public function sign($strSignSrc) {
$privateKey = file_get_contents($this->privateKeyFile);
$pKeyId = openssl_pkey_get_private($privateKey);
openssl_sign($strSignSrc, $signature, $pKeyId, OPENSSL_ALGO_SHA256);
openssl_free_key($pKeyId);
WriteLogSrv::writeLog(' ===拉卡拉===签名:'.base64_encode($signature));
return base64_encode($signature);
}
/**
* 配置头部 authorization
* @param string $signature
* @return string $authorization
*/
public function setAuthorization($signature) {
$authorization = $this->signAlgorithm . " appid=\"{$this->appId}\",";
if (!empty($this->serialNo)) {
$authorization .= "serial_no=\"{$this->serialNo}\",";
}
$authorization .= "nonce_str=\"{$this->nonceStr}\",";
$authorization .= "timestamp=\"{$this->timestamp}\",";
$authorization .= "signature=\"{$signature}\"";
return $authorization;
}
/**
* 接入请求
* @param string $url
* @param array $data
* @return array|false
*/
public function send($url, array $data) {
$signStr = $this->signStr($data);
$signature = $this->sign($signStr);
$authorization = $this->setAuthorization($signature);
$response = $this->curlPost($url, $authorization, $data);
return $this->handleResponse($response);
}
/**
* 解析请求结果
* @param string $response
* @return array | false
*/
public function handleResponse($response) {
WriteLogSrv::writeLog('===拉卡拉=== 响应信息'.$response);
$response = json_decode($response, true);
if (empty($response)) {
$this->setErrorMessage('请求失败');
return false;
}
if ($response['retCode'] != '000000') {
$this->setErrorMessage($response['retMsg']);
return false;
}
return $response;
}
/**
* 验签
* @param string $responseSrc 拼接好的字符串
* @param string $signature
* @return boolean $flag
*/
public function verifySign($responseSrc, $signature) {
$pubKeyId = openssl_get_publickey(file_get_contents($this->publicKey));
$flag = (bool) openssl_verify($responseSrc, base64_decode($signature), $pubKeyId, OPENSSL_ALGO_SHA256);
openssl_free_key($pubKeyId);
return $flag;
}
/**
* 发送curl请求
* @param string $actUrl
* @param string $authorization
* @param array $data
* @return bool|string
*/
public function curlPost($actUrl, $authorization, $data = []) {
$url = $this->apiUrl.$actUrl;
WriteLogSrv::writeLog(' ===拉卡拉请求=== url:'.$url);
WriteLogSrv::writeLog(' ===拉卡拉请求=== authorization:'.$authorization);
WriteLogSrv::writeLog(' ===拉卡拉请求=== 内容:'.json_encode($data, 320));
$ch = curl_init();
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
'Accept: application/json',
'Content-Type: application/json',
'Authorization: ' . $authorization,
)
);
if (!empty($data)) {
@curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data, 320));
}
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
return $response;
}
}