mirror of
https://github.com/crmeb/CRMEB.git
synced 2026-10-29 05:50:50 +00:00
【程序目录】优化程序
This commit is contained in:
parent
6f9dc32e8a
commit
75174a99df
@ -111,7 +111,7 @@ class Common extends AuthController
|
||||
} catch (\Throwable $e) {
|
||||
return app('json')->fail(400330);
|
||||
}
|
||||
return app('json')->success(['status' => 1, 'copyright' => $this->copyright(), 'authCode' => $authCode, 'day' => 0, 'force_reminder' => $upgradeStatus['force_reminder'] ?? 0]);
|
||||
return app('json')->success(['status' => 1, 'copyright' => $res['data']['copyright'], 'authCode' => $authCode, 'day' => 0, 'force_reminder' => $upgradeStatus['force_reminder'] ?? 0]);
|
||||
default:
|
||||
return app('json')->success(['status' => -9, 'force_reminder' => $upgradeStatus['force_reminder'] ?? 0]);
|
||||
}
|
||||
|
||||
@ -216,7 +216,7 @@ class StoreIntegralOrder extends AuthController
|
||||
|
||||
$data['delivery_name'] = $orderInfo['delivery_name'];
|
||||
$data['delivery_id'] = $orderInfo['delivery_id'];
|
||||
$data['result'] = $services->query($cacheName, $orderInfo['delivery_id'], $orderInfo['delivery_code'] ?? null);
|
||||
$data['result'] = $services->query($cacheName, $orderInfo['delivery_id'], $orderInfo['delivery_code'] ?? null, $orderInfo['user_phone']);
|
||||
return app('json')->success($data);
|
||||
}
|
||||
|
||||
|
||||
@ -510,7 +510,7 @@ class StoreOrder extends AuthController
|
||||
|
||||
$data['delivery_name'] = $orderInfo['delivery_name'];
|
||||
$data['delivery_id'] = $orderInfo['delivery_id'];
|
||||
$data['result'] = $services->query($cacheName, $orderInfo['delivery_id'], $orderInfo['delivery_code'] ?? null);
|
||||
$data['result'] = $services->query($cacheName, $orderInfo['delivery_id'], $orderInfo['delivery_code'] ?? null, $orderInfo['user_phone']);
|
||||
return app('json')->success($data);
|
||||
}
|
||||
|
||||
|
||||
@ -359,6 +359,11 @@ class StoreProduct extends AuthController
|
||||
return app('json')->success(100002);
|
||||
}
|
||||
|
||||
/**
|
||||
* 导入卡密
|
||||
* @return mixed
|
||||
* @throws \PhpOffice\PhpSpreadsheet\Reader\Exception
|
||||
*/
|
||||
public function import_card()
|
||||
{
|
||||
$data = $this->request->getMore([
|
||||
@ -371,4 +376,27 @@ class StoreProduct extends AuthController
|
||||
$cardData = $readExcelService->readExcel($file);
|
||||
return app('json')->success($cardData);
|
||||
}
|
||||
|
||||
/**
|
||||
* 商品批量设置
|
||||
* @return mixed
|
||||
*/
|
||||
public function batchSetting()
|
||||
{
|
||||
$data = $this->request->postMore([
|
||||
['ids', []],
|
||||
['cate_id', []],
|
||||
['logistics', []],
|
||||
['freight', 2],
|
||||
['postage', 0],
|
||||
['temp_id', 1],
|
||||
['give_integral', 0],
|
||||
['coupon_ids', []],
|
||||
['label_id', []],
|
||||
['recommend', []],
|
||||
['type', 0]
|
||||
]);
|
||||
$this->service->batchSetting($data);
|
||||
return app('json')->success(100014);
|
||||
}
|
||||
}
|
||||
|
||||
@ -50,22 +50,29 @@ class LangCountry extends AuthController
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
*/
|
||||
public function langCountryTypeForm($id)
|
||||
public function langCountryForm($id)
|
||||
{
|
||||
return app('json')->success($this->services->LangCountryTypeForm($id));
|
||||
return app('json')->success($this->services->langCountryForm($id));
|
||||
}
|
||||
|
||||
/**
|
||||
* 国家语言修改
|
||||
* 地区语言修改
|
||||
* @param $id
|
||||
* @return mixed
|
||||
*/
|
||||
public function langCountrySave($id)
|
||||
{
|
||||
[$typeId] = $this->request->postMore([
|
||||
['type', 0],
|
||||
], true);
|
||||
$this->services->langCountrySave($id, $typeId);
|
||||
$data = $this->request->postMore([
|
||||
['name', ''],
|
||||
['code', ''],
|
||||
]);
|
||||
$this->services->langCountrySave($id, $data);
|
||||
return app('json')->success(100000);
|
||||
}
|
||||
|
||||
public function langCountryDel($id)
|
||||
{
|
||||
$this->services->langCountryDel($id);
|
||||
return app('json')->success(100002);
|
||||
}
|
||||
}
|
||||
@ -168,8 +168,6 @@ class SystemAdmin extends AuthController
|
||||
['pwd', ''],
|
||||
['new_pwd', ''],
|
||||
['conf_pwd', ''],
|
||||
['file_pwd', ''],
|
||||
['conf_file_pwd', ''],
|
||||
]);
|
||||
if(!preg_match('/^(?![^a-zA-Z]+$)(?!\D+$).{6,}$/',$data['new_pwd'])){
|
||||
return app('json')->fail(400183);
|
||||
@ -179,6 +177,24 @@ class SystemAdmin extends AuthController
|
||||
else
|
||||
return app('json')->fail(100007);
|
||||
}
|
||||
/**
|
||||
* 修改当前登陆admin的文件管理密码
|
||||
* @return mixed
|
||||
*/
|
||||
public function set_file_password()
|
||||
{
|
||||
$data = $this->request->postMore([
|
||||
['file_pwd', ''],
|
||||
['conf_file_pwd', ''],
|
||||
]);
|
||||
if(!preg_match('/^(?![^a-zA-Z]+$)(?!\D+$).{6,}$/',$data['file_pwd'])){
|
||||
return app('json')->fail(400183);
|
||||
}
|
||||
if ($this->services->setFilePassword($this->adminId, $data))
|
||||
return app('json')->success(100001);
|
||||
else
|
||||
return app('json')->fail(100007);
|
||||
}
|
||||
|
||||
/**
|
||||
* 退出登陆
|
||||
|
||||
@ -12,6 +12,7 @@ namespace app\adminapi\controller\v1\setting;
|
||||
|
||||
use app\adminapi\controller\AuthController;
|
||||
use app\Request;
|
||||
use app\services\order\StoreOrderServices;
|
||||
use app\services\system\config\SystemConfigServices;
|
||||
use app\services\system\config\SystemConfigTabServices;
|
||||
use think\facade\App;
|
||||
@ -301,13 +302,21 @@ class SystemConfig extends AuthController
|
||||
if (isset($post['day_brokerage_price_upper']) && $post['day_brokerage_price_upper'] < -1) {
|
||||
return app('json')->fail(400757);
|
||||
}
|
||||
if( isset($post['pay_new_weixin_open']) && (bool)$post['pay_new_weixin_open'])
|
||||
{
|
||||
if(empty($post['pay_new_weixin_mchid']))
|
||||
{
|
||||
return app('json')->fail(400763);
|
||||
if (isset($post['pay_new_weixin_open']) && (bool)$post['pay_new_weixin_open']) {
|
||||
if (empty($post['pay_new_weixin_mchid'])) {
|
||||
return app('json')->fail(400763);
|
||||
}
|
||||
}
|
||||
|
||||
//支付接口类型选择,如果有订单就不能再进行切换
|
||||
if (isset($post['pay_wechat_type'])) {
|
||||
/** @var StoreOrderServices $orderServices */
|
||||
$orderServices = app()->make(StoreOrderServices::class);
|
||||
if ($post['pay_wechat_type'] != -1 && $orderServices->count()) {
|
||||
return app('json')->fail('支付接口类型已经选择,不能再次进行切换,切换后会导致无法退款等问题。');
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($post['weixin_ckeck_file'])) {
|
||||
$from = public_path() . $post['weixin_ckeck_file'];
|
||||
$to = public_path() . array_reverse(explode('/', $post['weixin_ckeck_file']))[0];
|
||||
|
||||
@ -93,6 +93,11 @@ Route::group('product', function () {
|
||||
Route::get('product/check_activity/:id', 'v1.product.StoreProduct/check_activity')->option(['real_name' => '检测是商品否有活动开启']);
|
||||
//导入虚拟商品卡密
|
||||
Route::get('product/import_card', 'v1.product.StoreProduct/import_card')->option(['real_name' => '导入虚拟商品卡密']);
|
||||
|
||||
/** 商品批量操作 */
|
||||
Route::post('batch/setting', 'v1.product.StoreProduct/batchSetting')->option(['real_name' => '商品批量设置']);
|
||||
|
||||
|
||||
})->middleware([
|
||||
\app\http\middleware\AllowOriginMiddleware::class,
|
||||
\app\adminapi\middleware\AdminAuthTokenMiddleware::class,
|
||||
|
||||
@ -25,6 +25,8 @@ Route::group('setting', function () {
|
||||
Route::get('info', 'v1.setting.SystemAdmin/info')->name('SystemAdminInfo')->option(['real_name' => '获取当前管理员信息']);
|
||||
//修改当前管理员信息
|
||||
Route::put('update_admin', 'v1.setting.SystemAdmin/update_admin')->name('SystemAdminUpdateAdmin')->option(['real_name' => '修改当前管理员信息']);
|
||||
//设置文件管理密码
|
||||
Route::put('set_file_password', 'v1.setting.SystemAdmin/set_file_password')->name('SystemAdminSetFilePassword')->option(['real_name' => '设置当前文件管理密码']);
|
||||
//权限菜单资源路由
|
||||
Route::resource('menus', 'v1.setting.SystemMenus')->option(['real_name' => '权限菜单']);
|
||||
//未添加的权限规则列表
|
||||
@ -169,10 +171,12 @@ Route::group('setting', function () {
|
||||
/** 多语言 */
|
||||
//语言国家列表
|
||||
Route::get('lang_country/list', 'v1.setting.LangCountry/langCountryList')->option(['real_name' => '语言国家列表']);
|
||||
//设置国家语言类型表单
|
||||
Route::get('lang_country/type_form/:id', 'v1.setting.LangCountry/langCountryTypeForm')->option(['real_name' => '设置国家语言类型表单']);
|
||||
//语言类型列表
|
||||
Route::post('lang_country/save/:id', 'v1.setting.LangCountry/langCountrySave')->option(['real_name' => '语言国家修改']);
|
||||
//添加语言地区表单
|
||||
Route::get('lang_country/form/:id', 'v1.setting.LangCountry/langCountryForm')->option(['real_name' => '添加语言地区表单']);
|
||||
//保存语言地区
|
||||
Route::post('lang_country/save/:id', 'v1.setting.LangCountry/langCountrySave')->option(['real_name' => '保存语言地区']);
|
||||
//删除语言地区
|
||||
Route::delete('lang_country/del/:id', 'v1.setting.LangCountry/langCountryDel')->option(['real_name' => '删除语言地区']);
|
||||
//语言类型列表
|
||||
Route::get('lang_type/list', 'v1.setting.LangType/langTypeList')->option(['real_name' => '语言类型列表']);
|
||||
//新增修改语言类型表单
|
||||
|
||||
@ -94,7 +94,7 @@ Route::group('system', function () {
|
||||
Route::get('upgrade_log/list', 'UpgradeController/upgradeLogList')->option(['real_name' => '升级记录']);
|
||||
//导出备份项目
|
||||
Route::get('upgrade_export/:id/:type', 'UpgradeController/export')->option(['real_name' => '导出备份']);
|
||||
|
||||
//文件管理登录
|
||||
Route::post('file/login', 'v1.system.SystemFile/login')->option(['real_name' => '文件管理登录']);
|
||||
})->middleware([
|
||||
\app\http\middleware\AllowOriginMiddleware::class,
|
||||
@ -111,9 +111,13 @@ Route::group('system', function () {
|
||||
Route::get('file/openfile', 'v1.system.SystemFile/openfile')->option(['real_name' => '读取文件']);
|
||||
//保存文件
|
||||
Route::post('file/savefile', 'v1.system.SystemFile/savefile')->option(['real_name' => '保存文件']);
|
||||
//创建文件夹
|
||||
Route::get('file/createFolder', 'v1.system.SystemFile/createFolder')->option(['real_name' => '创建文件夹']);
|
||||
//创建文件
|
||||
Route::get('file/createFile', 'v1.system.SystemFile/createFile')->option(['real_name' => '创建文件']);
|
||||
//删除文件夹或者文件
|
||||
Route::get('file/delFolder', 'v1.system.SystemFile/delFolder')->option(['real_name' => '删除文件夹']);
|
||||
//重命名文件
|
||||
Route::get('file/rename', 'v1.system.SystemFile/rename')->option(['real_name' => '重命名文件夹']);
|
||||
})->middleware([
|
||||
\app\http\middleware\AllowOriginMiddleware::class,
|
||||
|
||||
@ -38,8 +38,13 @@ class PayController
|
||||
return $pay->handleNotify();
|
||||
case 'wechat':
|
||||
case 'routine':
|
||||
/** @var Pay $pay */
|
||||
$pay = app()->make(Pay::class);
|
||||
if (sys_config('pay_wechat_type')) {
|
||||
/** @var Pay $pay */
|
||||
$pay = app()->make(Pay::class, ['v3_wechat_pay']);
|
||||
} else {
|
||||
/** @var Pay $pay */
|
||||
$pay = app()->make(Pay::class);
|
||||
}
|
||||
return $pay->handleNotify()->getContent();
|
||||
}
|
||||
}
|
||||
|
||||
@ -142,7 +142,7 @@ class StoreIntegralOrderController
|
||||
return app('json')->success([
|
||||
'order' => $order,
|
||||
'express' => [
|
||||
'result' => ['list' => $expressServices->query($cacheName, $order['delivery_id'], $order['delivery_code'])
|
||||
'result' => ['list' => $expressServices->query($cacheName, $order['delivery_id'], $order['delivery_code'], $order['user_phone'])
|
||||
]
|
||||
]
|
||||
]);
|
||||
|
||||
@ -409,7 +409,7 @@ class StoreOrderController
|
||||
case 'routine':
|
||||
if ($type == 1 || in_array($order['is_channel'], [0, 2, 3, 4])) {
|
||||
$order['order_id'] = app()->make(StoreOrderCreateServices::class)->getNewOrderId('cp');
|
||||
$this->services->update($order['id'],['order_id'=>$order['order_id']],'id');
|
||||
$this->services->update($order['id'], ['order_id' => $order['order_id']], 'id');
|
||||
}
|
||||
break;
|
||||
case 'app':
|
||||
@ -690,7 +690,7 @@ class StoreOrderController
|
||||
return app('json')->success([
|
||||
'order' => $orderInfo,
|
||||
'express' => [
|
||||
'result' => ['list' => $expressServices->query($cacheName, $orderInfo['delivery_id'], $orderInfo['delivery_code'])
|
||||
'result' => ['list' => $expressServices->query($cacheName, $orderInfo['delivery_id'], $orderInfo['delivery_code'], $order['user_phone'])
|
||||
]
|
||||
]
|
||||
]);
|
||||
|
||||
@ -51,6 +51,11 @@ class WechatController
|
||||
return $this->services->notify();
|
||||
}
|
||||
|
||||
public function v3notify()
|
||||
{
|
||||
return $this->services->v3notify();
|
||||
}
|
||||
|
||||
/**
|
||||
* 公众号权限配置信息获取
|
||||
* @param Request $request
|
||||
|
||||
@ -15,6 +15,7 @@ use think\Response;
|
||||
|
||||
Route::any('wechat/serve', 'v1.wechat.WechatController/serve');//公众号服务
|
||||
Route::any('wechat/notify', 'v1.wechat.WechatController/notify');//公众号支付回调
|
||||
Route::any('wechat/v3notify', 'v1.wechat.WechatController/v3notify');//公众号支付回调
|
||||
Route::any('routine/notify', 'v1.wechat.AuthController/notify');//小程序支付回调
|
||||
Route::any('pay/notify/:type', 'v1.PayController/notify');//支付回调
|
||||
Route::get('get_script', 'v1.PublicController/getScript');//获取统计代码
|
||||
|
||||
@ -160,7 +160,7 @@ class StoreProductDao extends BaseDao
|
||||
}
|
||||
})->when(!$page && $limit, function ($query) use ($limit) {
|
||||
$query->limit($limit);
|
||||
})->field($field)->select()->toArray();
|
||||
})->order('sort desc')->field($field)->select()->toArray();
|
||||
}
|
||||
|
||||
/**商品列表
|
||||
@ -225,7 +225,7 @@ class StoreProductDao extends BaseDao
|
||||
->when($limit, function ($query) use ($limit) {
|
||||
$query->limit($limit);
|
||||
})
|
||||
->order((in_array($field, ['is_hot','is_best']) ? 'sales DESC' : 'sort DESC') . ', id DESC')->select()->toArray();
|
||||
->order(in_array($field, ['is_hot', 'is_best']) ? 'sales DESC,sort DESC, id desc' : 'sort DESC, id desc')->select()->toArray();
|
||||
|
||||
}
|
||||
|
||||
|
||||
@ -188,8 +188,13 @@ class StoreOrderRefundServices extends BaseServices
|
||||
$no = $refundOrder['trade_no'];
|
||||
$refundData['type'] = 'trade_no';
|
||||
}
|
||||
if (sys_config('pay_wechat_type')) {
|
||||
$drivers = 'v3_wechat_pay';
|
||||
} else {
|
||||
$drivers = 'wechat_pay';
|
||||
}
|
||||
/** @var Pay $pay */
|
||||
$pay = app()->make(Pay::class);
|
||||
$pay = app()->make(Pay::class, [$drivers]);
|
||||
if ($refundOrder['is_channel'] == 1) {
|
||||
$refundData['trade_no'] = $refundOrder['trade_no'];
|
||||
$refundData['pay_new_weixin_open'] = sys_config('pay_new_weixin_open');
|
||||
|
||||
@ -1581,6 +1581,7 @@ HTML;
|
||||
/** @var UserBillServices $userBillServices */
|
||||
$userBillServices = app()->make(UserBillServices::class);
|
||||
$data['usable_integral'] = bcsub((string)$user['integral'], (string)$userBillServices->getBillSum(['uid' => $user['uid'], 'is_frozen' => 1]), 0);
|
||||
$data['integral_open'] = sys_config('integral_ratio', 0) > 0;
|
||||
return $data;
|
||||
}
|
||||
|
||||
|
||||
@ -76,6 +76,10 @@ class PayServices
|
||||
//这些全都是微信支付
|
||||
if (in_array($payType, ['routine', 'weixinh5', 'weixin', 'pc', 'store'])) {
|
||||
$payType = 'wechat_pay';
|
||||
//判断是否使用v3
|
||||
if (sys_config('pay_wechat_type') == 1) {
|
||||
$payType = 'v3_wechat_pay';
|
||||
}
|
||||
}
|
||||
|
||||
if ($payType == 'alipay') {
|
||||
@ -85,7 +89,7 @@ class PayServices
|
||||
/** @var Pay $pay */
|
||||
$pay = app()->make(Pay::class, [$payType]);
|
||||
|
||||
return $pay->create($orderId, $price, $successAction, $body, '', ['openid' => $openid, 'isCode' => $isCode,'pay_new_weixin_open' => (bool)sys_config('pay_new_weixin_open')]);
|
||||
return $pay->create($orderId, $price, $successAction, $body, '', ['openid' => $openid, 'isCode' => $isCode, 'pay_new_weixin_open' => (bool)sys_config('pay_new_weixin_open')]);
|
||||
|
||||
} catch (\Exception $e) {
|
||||
throw new ApiException($e->getMessage());
|
||||
|
||||
@ -1954,4 +1954,99 @@ class StoreProductServices extends BaseServices
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 商品批量设置
|
||||
* @param $data
|
||||
* @return bool
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function batchSetting($data)
|
||||
{
|
||||
$ids = $data['ids'];
|
||||
$batchData = [];
|
||||
if (!count($ids)) throw new AdminException(400337);
|
||||
switch ($data['type']) {
|
||||
case 1: // 修改分类
|
||||
$cate_id = $data['cate_id'];
|
||||
if (!count($cate_id)) throw new AdminException(410107);
|
||||
/** @var StoreCategoryServices $storeCategoryServices */
|
||||
$storeCategoryServices = app()->make(StoreCategoryServices::class);
|
||||
$cateGory = $storeCategoryServices->getColumn([['id', 'IN', $cate_id]], 'id,pid', 'id');
|
||||
if (!$cateGory) throw new AdminException(410096);
|
||||
$time = time();
|
||||
$cateData = [];
|
||||
foreach ($cate_id as $cid) {
|
||||
if ($cid && isset($cateGory[$cid]['pid'])) {
|
||||
foreach ($ids as $product_id) {
|
||||
$cateData[$product_id][] = ['product_id' => $product_id, 'cate_id' => $cid, 'cate_pid' => $cateGory[$cid]['pid'], 'status' => 1, 'add_time' => $time];
|
||||
}
|
||||
}
|
||||
}
|
||||
/** @var StoreProductCateServices $storeProductCateServices */
|
||||
$storeProductCateServices = app()->make(StoreProductCateServices::class);
|
||||
foreach ($ids as $product_id) {
|
||||
$storeProductCateServices->change($product_id, $cateData[$product_id]);
|
||||
$this->dao->update($product_id, ['cate_id' => implode(',', $cate_id)]);
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
foreach ($ids as $product_id) {
|
||||
$batchData[] = [
|
||||
'id' => $product_id,
|
||||
'logistics' => implode(',', $data['logistics']),
|
||||
'freight' => $data['freight'],
|
||||
'postage' => $data['freight'] == 2 ? $data['postage'] : 0,
|
||||
'temp_id' => $data['freight'] == 3 ? $data['temp_id'] : 0
|
||||
];
|
||||
}
|
||||
if (count($batchData)) $this->dao->saveAll($batchData);
|
||||
break;
|
||||
case 3:
|
||||
foreach ($ids as $product_id) {
|
||||
$batchData[] = [
|
||||
'id' => $product_id,
|
||||
'give_integral' => $data['give_integral']
|
||||
];
|
||||
}
|
||||
if (count($batchData)) $this->dao->saveAll($batchData);
|
||||
break;
|
||||
case 4:
|
||||
/** @var StoreProductCouponServices $storeProductCouponServices */
|
||||
$storeProductCouponServices = app()->make(StoreProductCouponServices::class);
|
||||
foreach ($ids as $product_id) {
|
||||
if (!empty($data['coupon_ids'])) {
|
||||
$storeProductCouponServices->setCoupon($product_id, $data['coupon_ids']);
|
||||
} else {
|
||||
$storeProductCouponServices->delete(['product_id' => $product_id]);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 5:
|
||||
foreach ($ids as $product_id) {
|
||||
$batchData[] = [
|
||||
'id' => $product_id,
|
||||
'label_id' => implode(',', $data['label_id'])
|
||||
];
|
||||
}
|
||||
if (count($batchData)) $this->dao->saveAll($batchData);
|
||||
break;
|
||||
case 6:
|
||||
foreach ($ids as $product_id) {
|
||||
$batchData[] = [
|
||||
'id' => $product_id,
|
||||
'is_hot' => in_array('is_hot',$data['recommend']) ? 1 : 0,
|
||||
'is_benefit' => in_array('is_benefit',$data['recommend']) ? 1 : 0,
|
||||
'is_new' => in_array('is_new',$data['recommend']) ? 1 : 0,
|
||||
'is_good' => in_array('is_good',$data['recommend']) ? 1 : 0,
|
||||
'is_best' => in_array('is_best',$data['recommend']) ? 1 : 0
|
||||
];
|
||||
}
|
||||
if (count($batchData)) $this->dao->saveAll($batchData);
|
||||
break;
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@ -190,7 +190,7 @@ class ExpressServices extends BaseServices
|
||||
* @param string|null $com
|
||||
* @return array
|
||||
*/
|
||||
public function query(string $cacheName, string $expressNum, string $com = null)
|
||||
public function query(string $cacheName, string $expressNum, string $com = null, $phone = '')
|
||||
{
|
||||
$resultData = CacheService::get($cacheName, null);
|
||||
if ($resultData === null || !is_array($resultData)) {
|
||||
@ -200,7 +200,7 @@ class ExpressServices extends BaseServices
|
||||
case 1:
|
||||
/** @var ServeServices $services */
|
||||
$services = app()->make(ServeServices::class);
|
||||
$result = $services->express()->query($expressNum, $com);
|
||||
$result = $services->express()->query($expressNum, $com, $phone);
|
||||
if (isset($result['ischeck']) && $result['ischeck'] == 1) {
|
||||
$cacheTime = 0;
|
||||
} else {
|
||||
|
||||
@ -138,6 +138,7 @@ class SystemAdminServices extends BaseServices
|
||||
'id' => $adminInfo->getData('id'),
|
||||
'account' => $adminInfo->getData('account'),
|
||||
'head_pic' => $adminInfo->getData('head_pic'),
|
||||
'level' => $adminInfo->getData('level'),
|
||||
],
|
||||
'logo' => sys_config('site_logo'),
|
||||
'logo_square' => sys_config('site_logo_square'),
|
||||
@ -358,6 +359,28 @@ class SystemAdminServices extends BaseServices
|
||||
throw new AdminException(400264);
|
||||
$adminInfo->pwd = $this->passwordHash($data['new_pwd']);
|
||||
}
|
||||
|
||||
$adminInfo->real_name = $data['real_name'];
|
||||
$adminInfo->head_pic = $data['head_pic'];
|
||||
if ($adminInfo->save())
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
/**
|
||||
* 设置当前管理员文件管理密码
|
||||
* @param int $id
|
||||
* @param array $data
|
||||
* @return bool
|
||||
*/
|
||||
public function setFilePassword(int $id, array $data)
|
||||
{
|
||||
$adminInfo = $this->dao->get($id);
|
||||
if (!$adminInfo)
|
||||
throw new AdminException(400451);
|
||||
if ($adminInfo->is_del) {
|
||||
throw new AdminException(400452);
|
||||
}
|
||||
if ($data['file_pwd']) {
|
||||
if ($adminInfo->level != 0) throw new AdminException(400611);
|
||||
if (!$data['conf_file_pwd'])
|
||||
@ -366,9 +389,6 @@ class SystemAdminServices extends BaseServices
|
||||
throw new AdminException(400264);
|
||||
$adminInfo->file_pwd = $this->passwordHash($data['file_pwd']);
|
||||
}
|
||||
|
||||
$adminInfo->real_name = $data['real_name'];
|
||||
$adminInfo->head_pic = $data['head_pic'];
|
||||
if ($adminInfo->save())
|
||||
return true;
|
||||
else
|
||||
|
||||
@ -139,7 +139,19 @@ class SystemConfigServices extends BaseServices
|
||||
'pay_weixin_open' => [
|
||||
'son_type' => [
|
||||
'pay_weixin_mchid' => '',
|
||||
'pay_weixin_key' => '',
|
||||
'pay_wechat_type' => [
|
||||
'son_type' => [
|
||||
'pay_weixin_key' => '',
|
||||
],
|
||||
'show_value' => 0
|
||||
],
|
||||
'pay_wechat_type@' => [
|
||||
'son_type' => [
|
||||
'pay_weixin_serial_no' => '',
|
||||
'pay_weixin_key_v3' => ''
|
||||
],
|
||||
'show_value' => 1
|
||||
],
|
||||
'pay_weixin_client_cert' => '',
|
||||
'pay_weixin_client_key' => '',
|
||||
'paydir' => '',
|
||||
|
||||
@ -34,8 +34,8 @@ class LangCodeServices extends BaseServices
|
||||
$typeList = $langTypeServices->getColumn([['status', '=', 1], ['is_del', '=', 0]], 'language_name,file_name,id', 'id');
|
||||
$langType = [
|
||||
'isAdmin' => [
|
||||
['title' => '用户端', 'value' => 0],
|
||||
['title' => '管理端', 'value' => 1]
|
||||
['title' => '用户端页面', 'value' => 0],
|
||||
['title' => '后端接口', 'value' => 1]
|
||||
]
|
||||
];
|
||||
foreach ($typeList as $value) {
|
||||
|
||||
@ -19,7 +19,7 @@ class LangCountryServices extends BaseServices
|
||||
}
|
||||
|
||||
/**
|
||||
* 国家语言列表
|
||||
* 地区语言列表
|
||||
* @param array $where
|
||||
* @return array
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
@ -35,7 +35,7 @@ class LangCountryServices extends BaseServices
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置国家语言类型表单
|
||||
* 添加语言地区表单
|
||||
* @param $id
|
||||
* @return array
|
||||
* @throws \FormBuilder\Exception\FormBuilderException
|
||||
@ -43,32 +43,41 @@ class LangCountryServices extends BaseServices
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
*/
|
||||
public function LangCountryTypeForm($id)
|
||||
public function langCountryForm($id)
|
||||
{
|
||||
if (!$id) throw new AdminException(100100);
|
||||
$info = $this->dao->get($id);
|
||||
if (!$info) throw new AdminException(100026);
|
||||
/** @var LangTypeServices $typeServices */
|
||||
$typeServices = app()->make(LangTypeServices::class);
|
||||
$typeList = $typeServices->getColumn(['status' => 1, 'is_del' => 0], 'language_name,file_name', 'id');
|
||||
$options[] = ['value' => 0, 'label' => '未定义'];
|
||||
foreach ($typeList as $item) {
|
||||
$options[] = ['value' => $item['id'], 'label' => $item['language_name'] . '(' . $item['file_name'] . ')'];
|
||||
}
|
||||
$field[] = Form::select('type', '选择语言类型', $info->type_id)->setOptions($options)->filterable(1);
|
||||
return create_form('设置语言类型', $field, Url::buildUrl('/setting/lang_country/save/' . $id), 'POST');
|
||||
if ($id) $info = $this->dao->get($id);
|
||||
$field = [];
|
||||
$field[] = Form::input('name', '所属地区', $info['name'] ?? '')->required('请填写所属地区');
|
||||
$field[] = Form::input('code', '语言码', $info['code'] ?? '')->required('请填写语言码');
|
||||
return create_form($id ? '修改语言地区' : '新增语言地区', $field, Url::buildUrl('/setting/lang_country/save/' . $id), 'POST');
|
||||
}
|
||||
|
||||
/**
|
||||
* 国家语言修改
|
||||
* 保存语言地区
|
||||
* @param $id
|
||||
* @param $typeId
|
||||
* @return bool
|
||||
*/
|
||||
public function LangCountrySave($id, $typeId)
|
||||
public function LangCountrySave($id, $data)
|
||||
{
|
||||
$res = $this->dao->update(['id' => $id], ['type_id' => $typeId]);
|
||||
if ($id) {
|
||||
$res = $this->dao->update(['id' => $id], $data);
|
||||
} else {
|
||||
$res = $this->dao->save($data);
|
||||
}
|
||||
if (!$res) throw new AdminException(100007);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除语言地区
|
||||
* @param $id
|
||||
* @return bool
|
||||
*/
|
||||
public function langCountryDel($id)
|
||||
{
|
||||
$res = $this->dao->delete($id);
|
||||
if (!$res) throw new AdminException(100008);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@ -21,6 +21,7 @@ use crmeb\services\CacheService;
|
||||
use crmeb\services\CacheService as Cache;
|
||||
use crmeb\services\app\WechatService as WechatAuthService;
|
||||
use crmeb\services\oauth\OAuth;
|
||||
use crmeb\services\pay\Pay;
|
||||
use crmeb\utils\Canvas;
|
||||
|
||||
/**
|
||||
@ -60,6 +61,21 @@ class WechatServices extends BaseServices
|
||||
return WechatAuthService::handleNotify()->getContent();
|
||||
}
|
||||
|
||||
/**
|
||||
* v3支付回调
|
||||
* @return string
|
||||
* @throws \EasyWeChat\Core\Exceptions\FaultException
|
||||
* @author 等风来
|
||||
* @email 136327134@qq.com
|
||||
* @date 2022/9/22
|
||||
*/
|
||||
public function v3notify()
|
||||
{
|
||||
/** @var Pay $pay */
|
||||
$pay = app()->make(Pay::class, ['v3_wechat_pay']);
|
||||
return $pay->handleNotify()->getContent();
|
||||
}
|
||||
|
||||
/**
|
||||
* 公众号权限配置信息获取
|
||||
* @param $url
|
||||
|
||||
@ -146,9 +146,9 @@ class WechatService
|
||||
$response = $messageService->wechatEventView($message);
|
||||
break;
|
||||
case 'funds_order_pay':
|
||||
$prefix = substr($message['order_info']['trade_no'],0,2);
|
||||
$prefix = substr($message['order_info']['trade_no'], 0, 2);
|
||||
//处理一下参数
|
||||
switch ($prefix){
|
||||
switch ($prefix) {
|
||||
case 'cp':
|
||||
$data['attach'] = 'Product';
|
||||
break;
|
||||
@ -162,14 +162,12 @@ class WechatService
|
||||
$data['out_trade_no'] = $message['order_info']['trade_no'];
|
||||
$data['transaction_id'] = $message['order_info']['transaction_id'];
|
||||
$data['opneid'] = $message['FromUserName'];
|
||||
if(Event::until('pay.notify', [$data]))
|
||||
{
|
||||
if (Event::until('pay.notify', [$data])) {
|
||||
$response = 'success';
|
||||
}else
|
||||
{
|
||||
} else {
|
||||
$response = 'faild';
|
||||
}
|
||||
Log::error(['data'=>$data,'res'=>$response,'message'=>$message]);
|
||||
Log::error(['data' => $data, 'res' => $response, 'message' => $message]);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
@ -446,6 +444,7 @@ class WechatService
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获得下单ID 新小程序支付
|
||||
* @param $openid
|
||||
@ -500,6 +499,7 @@ class WechatService
|
||||
$paymentPrepare = self::paymentPrepare($openid, $out_trade_no, $total_fee, $attach, $body, $detail, $trade_type, $options);
|
||||
return self::paymentService()->configForJSSDKPayment($paymentPrepare->prepay_id);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获得jsSdk支付参数 新小程序支付
|
||||
* @param $openid
|
||||
|
||||
@ -14,7 +14,10 @@ namespace crmeb\services\easywechat;
|
||||
|
||||
use crmeb\services\easywechat\miniPayment\ServiceProvider;
|
||||
use crmeb\services\easywechat\oauth2\wechat\WechatOauth2Provider;
|
||||
use crmeb\services\easywechat\subscribe\ProgramProvider;
|
||||
use crmeb\services\easywechat\v3pay\PayClient;
|
||||
use crmeb\services\easywechat\wechatlive\ProgramProvider as LiveProgramProvider;
|
||||
use crmeb\services\easywechat\v3pay\ServiceProvider as V3PayServiceProvider;
|
||||
|
||||
|
||||
/**
|
||||
@ -22,6 +25,7 @@ use crmeb\services\easywechat\wechatlive\ProgramProvider as LiveProgramProvider;
|
||||
* @package crmeb\services\easywechat
|
||||
* @property LiveProgramProvider $wechat_live
|
||||
* @property WechatOauth2Provider $oauth2
|
||||
* @property PayClient $v3pay
|
||||
*/
|
||||
class Application extends \EasyWeChat\Foundation\Application
|
||||
{
|
||||
@ -32,7 +36,10 @@ class Application extends \EasyWeChat\Foundation\Application
|
||||
protected $providersNew = [
|
||||
LiveProgramProvider::class,
|
||||
WechatOauth2Provider::class,
|
||||
ServiceProvider::class
|
||||
ServiceProvider::class,
|
||||
ProgramProvider::class,
|
||||
V3PayServiceProvider::class,
|
||||
\crmeb\services\easywechat\Open3rd\ProgramProvider::class,
|
||||
];
|
||||
|
||||
/**
|
||||
|
||||
@ -49,7 +49,7 @@ class WeChatClient extends AbstractAPI
|
||||
|
||||
/**
|
||||
* 支付
|
||||
* @param array $params[
|
||||
* @param array $params [
|
||||
* 'openid'=>'支付者的openid',
|
||||
* 'out_trade_no'=>'商家合单支付总交易单号',
|
||||
* 'total_fee'=>'支付金额',
|
||||
@ -64,15 +64,15 @@ class WeChatClient extends AbstractAPI
|
||||
public function createorder($order)
|
||||
{
|
||||
$params = [
|
||||
'openid'=>$order['openid'], // 支付者的openid
|
||||
'combine_trade_no'=>$order['out_trade_no'], // 商家合单支付总交易单号
|
||||
'expire_time'=>time()+$this->expire_time,
|
||||
'sub_orders'=>[
|
||||
'openid' => $order['openid'], // 支付者的openid
|
||||
'combine_trade_no' => $order['out_trade_no'], // 商家合单支付总交易单号
|
||||
'expire_time' => time() + $this->expire_time,
|
||||
'sub_orders' => [
|
||||
[
|
||||
'mchid'=>$this->merchant->merchant_id,
|
||||
'amount'=>(int)$order['total_fee'],
|
||||
'trade_no'=>$order['out_trade_no'],
|
||||
'description'=>$order['body']
|
||||
'mchid' => $this->merchant->merchant_id,
|
||||
'amount' => (int)$order['total_fee'],
|
||||
'trade_no' => $order['out_trade_no'],
|
||||
'description' => $order['body']
|
||||
]
|
||||
]
|
||||
];
|
||||
@ -81,7 +81,7 @@ class WeChatClient extends AbstractAPI
|
||||
|
||||
/**
|
||||
* 退款
|
||||
* @param array $params[
|
||||
* @param array $params [
|
||||
* 'openid'=>'退款者的openid',
|
||||
* 'trade_no'=>'商家交易单号',
|
||||
* 'transaction_id'=>'支付单号',
|
||||
@ -95,13 +95,13 @@ class WeChatClient extends AbstractAPI
|
||||
public function refundorder(array $order)
|
||||
{
|
||||
$params = [
|
||||
'openid'=>$order['openid'],
|
||||
'mchid'=>$this->merchant->merchant_id,
|
||||
'trade_no'=>$order['trade_no'],
|
||||
'transaction_id'=>$order['transaction_id'],
|
||||
'refund_no'=>$order['refund_no'],
|
||||
'total_amount'=>$order['total_amount'],
|
||||
'refund_amount'=>$order['refund_amount'],
|
||||
'openid' => $order['openid'],
|
||||
'mchid' => $this->merchant->merchant_id,
|
||||
'trade_no' => $order['trade_no'],
|
||||
'transaction_id' => $order['transaction_id'],
|
||||
'refund_no' => $order['refund_no'],
|
||||
'total_amount' => $order['total_amount'],
|
||||
'refund_amount' => $order['refund_amount'],
|
||||
];
|
||||
return $this->parseJSON('post', [self::API_SET_REFUND_ORDER, json_encode($params)]);
|
||||
}
|
||||
|
||||
280
crmeb/crmeb/services/easywechat/v3pay/BaseClient.php
Normal file
280
crmeb/crmeb/services/easywechat/v3pay/BaseClient.php
Normal file
@ -0,0 +1,280 @@
|
||||
<?php
|
||||
/**
|
||||
* +----------------------------------------------------------------------
|
||||
* | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
|
||||
* +----------------------------------------------------------------------
|
||||
* | Copyright (c) 2016~2022 https://www.crmeb.com All rights reserved.
|
||||
* +----------------------------------------------------------------------
|
||||
* | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
|
||||
* +----------------------------------------------------------------------
|
||||
* | Author: CRMEB Team <admin@crmeb.com>
|
||||
* +----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
namespace crmeb\services\easywechat\v3pay;
|
||||
|
||||
|
||||
use crmeb\exceptions\PayException;
|
||||
use crmeb\services\easywechat\Application;
|
||||
use EasyWeChat\Core\AbstractAPI;
|
||||
use EasyWeChat\Core\AccessToken;
|
||||
use EasyWeChat\Core\Exceptions\HttpException;
|
||||
use EasyWeChat\Core\Exceptions\InvalidConfigException;
|
||||
use EasyWeChat\Core\Http;
|
||||
use EasyWeChat\Encryption\EncryptionException;
|
||||
use think\exception\InvalidArgumentException;
|
||||
|
||||
|
||||
class BaseClient extends AbstractAPI
|
||||
{
|
||||
|
||||
use Certficates;
|
||||
|
||||
/**
|
||||
* @var Application
|
||||
*/
|
||||
protected $app;
|
||||
|
||||
const BASE_URL = 'https://api.mch.weixin.qq.com/';
|
||||
|
||||
const KEY_LENGTH_BYTE = 32;
|
||||
|
||||
const AUTH_TAG_LENGTH_BYTE = 16;
|
||||
|
||||
/**
|
||||
* BaseClient constructor.
|
||||
* @param AccessToken $accessToken
|
||||
* @param $app
|
||||
*/
|
||||
public function __construct(AccessToken $accessToken, $app)
|
||||
{
|
||||
parent::__construct($accessToken);
|
||||
$this->app = $app;
|
||||
}
|
||||
|
||||
/**
|
||||
* request.
|
||||
*
|
||||
* @param string $endpoint
|
||||
* @param string $method
|
||||
* @param array $options
|
||||
* @param bool $returnResponse
|
||||
*/
|
||||
public function request(string $endpoint, string $method = 'POST', array $options = [], $serial = true)
|
||||
{
|
||||
$body = $options['body'] ?? '';
|
||||
|
||||
if (isset($options['json'])) {
|
||||
$body = json_encode($options['json']);
|
||||
$options['body'] = $body;
|
||||
unset($options['json']);
|
||||
}
|
||||
|
||||
$headers = [
|
||||
'Content-Type' => 'application/json',
|
||||
'User-Agent' => 'curl',
|
||||
'Accept' => 'application/json',
|
||||
'Authorization' => $this->getAuthorization($endpoint, $method, $body),
|
||||
];
|
||||
|
||||
$options['headers'] = array_merge($headers, ($options['headers'] ?? []));
|
||||
|
||||
if ($serial) {
|
||||
$options['headers']['Wechatpay-Serial'] = $this->getCertficatescAttr('serial_no');
|
||||
}
|
||||
|
||||
return $this->_doRequestCurl($method, self::BASE_URL . $endpoint, $options);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $method
|
||||
* @param $location
|
||||
* @param array $options
|
||||
* @return mixed
|
||||
*/
|
||||
private function _doRequestCurl($method, $location, $options = [])
|
||||
{
|
||||
$curl = curl_init();
|
||||
// POST数据设置
|
||||
if (strtolower($method) === 'post') {
|
||||
curl_setopt($curl, CURLOPT_POST, true);
|
||||
curl_setopt($curl, CURLOPT_POSTFIELDS, $options['data'] ?? $options['body'] ?? '');
|
||||
}
|
||||
// CURL头信息设置
|
||||
if (!empty($options['headers'])) {
|
||||
$headers = [];
|
||||
foreach ($options['headers'] as $k => $v) {
|
||||
$headers[] = "$k: $v";
|
||||
}
|
||||
curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
|
||||
}
|
||||
curl_setopt($curl, CURLOPT_URL, $location);
|
||||
curl_setopt($curl, CURLOPT_HEADER, true);
|
||||
curl_setopt($curl, CURLOPT_TIMEOUT, 60);
|
||||
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
|
||||
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
|
||||
curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, false);
|
||||
$content = curl_exec($curl);
|
||||
$headerSize = curl_getinfo($curl, CURLINFO_HEADER_SIZE);
|
||||
curl_close($curl);
|
||||
return json_decode(substr($content, $headerSize), true);
|
||||
}
|
||||
|
||||
/**
|
||||
* To id card, mobile phone number and other fields sensitive information encryption.
|
||||
*
|
||||
* @param string $string
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function encryptSensitiveInformation(string $string)
|
||||
{
|
||||
$certificates = $this->app->certficates->get()['certificates'];
|
||||
if (null === $certificates) {
|
||||
throw new InvalidConfigException('config certificate connot be empty.');
|
||||
}
|
||||
$encrypted = '';
|
||||
if (openssl_public_encrypt($string, $encrypted, $certificates, OPENSSL_PKCS1_OAEP_PADDING)) {
|
||||
//base64编码
|
||||
$sign = base64_encode($encrypted);
|
||||
} else {
|
||||
throw new EncryptionException('Encryption of sensitive information failed');
|
||||
}
|
||||
return $sign;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param string $url
|
||||
* @param string $method
|
||||
* @param string $body
|
||||
* @return string
|
||||
*/
|
||||
protected function getAuthorization(string $url, string $method, string $body)
|
||||
{
|
||||
$nonceStr = uniqid();
|
||||
$timestamp = time();
|
||||
$message = $method . "\n" .
|
||||
'/' . $url . "\n" .
|
||||
$timestamp . "\n" .
|
||||
$nonceStr . "\n" .
|
||||
$body . "\n";
|
||||
openssl_sign($message, $raw_sign, $this->getPrivateKey(), 'sha256WithRSAEncryption');
|
||||
$sign = base64_encode($raw_sign);
|
||||
$schema = 'WECHATPAY2-SHA256-RSA2048 ';
|
||||
$token = sprintf('mchid="%s",nonce_str="%s",timestamp="%d",serial_no="%s",signature="%s"',
|
||||
$this->app['config']['v3_payment']['mchid'], $nonceStr, $timestamp, $this->app['config']['v3_payment']['serial_no'], $sign);
|
||||
return $schema . $token;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取商户私钥
|
||||
* @return bool|resource
|
||||
*/
|
||||
protected function getPrivateKey()
|
||||
{
|
||||
$key_path = $this->app['config']['v3_payment']['key_path'];
|
||||
if (!file_exists($key_path)) {
|
||||
throw new \InvalidArgumentException(
|
||||
"SSL certificate not found: {$key_path}"
|
||||
);
|
||||
}
|
||||
return openssl_pkey_get_private(file_get_contents($key_path));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取商户公钥
|
||||
* @return bool|resource
|
||||
*/
|
||||
protected function getPublicKey()
|
||||
{
|
||||
$key_path = $this->app['config']['v3_payment']['cert_path'];
|
||||
if (!file_exists($key_path)) {
|
||||
throw new \InvalidArgumentException(
|
||||
"SSL certificate not found: {$key_path}"
|
||||
);
|
||||
}
|
||||
return openssl_pkey_get_public(file_get_contents($key_path));
|
||||
}
|
||||
|
||||
/**
|
||||
* 替换url
|
||||
* @param string $url
|
||||
* @param $search
|
||||
* @param $replace
|
||||
* @return array|string|string[]
|
||||
*/
|
||||
public function getApiUrl(string $url, $search, $replace)
|
||||
{
|
||||
$newSearch = [];
|
||||
foreach ($search as $key) {
|
||||
$newSearch[] = '{' . $key . '}';
|
||||
}
|
||||
return str_replace($newSearch, $replace, $url);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $padding
|
||||
*/
|
||||
private static function paddingModeLimitedCheck(int $padding): void
|
||||
{
|
||||
if (!($padding === OPENSSL_PKCS1_OAEP_PADDING || $padding === OPENSSL_PKCS1_PADDING)) {
|
||||
throw new PayException(sprintf("Doesn't supported padding mode(%d), here only support OPENSSL_PKCS1_OAEP_PADDING or OPENSSL_PKCS1_PADDING.", $padding));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 加密数据
|
||||
* @param string $plaintext
|
||||
* @param int $padding
|
||||
* @return string
|
||||
*/
|
||||
public function encryptor(string $plaintext, int $padding = OPENSSL_PKCS1_OAEP_PADDING)
|
||||
{
|
||||
self::paddingModeLimitedCheck($padding);
|
||||
|
||||
if (!openssl_public_encrypt($plaintext, $encrypted, $this->getPublicKey(), $padding)) {
|
||||
throw new PayException('Encrypting the input $plaintext failed, please checking your $publicKey whether or nor correct.');
|
||||
}
|
||||
|
||||
return base64_encode($encrypted);
|
||||
}
|
||||
|
||||
/**
|
||||
* decrypt ciphertext.
|
||||
*
|
||||
* @param array $encryptCertificate
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function decrypt(array $encryptCertificate)
|
||||
{
|
||||
$ciphertext = base64_decode($encryptCertificate['ciphertext'], true);
|
||||
$associatedData = $encryptCertificate['associated_data'];
|
||||
$nonceStr = $encryptCertificate['nonce'];
|
||||
$aesKey = $this->app['config']['v3_payment']['key'];
|
||||
|
||||
try {
|
||||
// ext-sodium (default installed on >= PHP 7.2)
|
||||
if (function_exists('\sodium_crypto_aead_aes256gcm_is_available') && \sodium_crypto_aead_aes256gcm_is_available()) {
|
||||
return \sodium_crypto_aead_aes256gcm_decrypt($ciphertext, $associatedData, $nonceStr, $aesKey);
|
||||
}
|
||||
// ext-libsodium (need install libsodium-php 1.x via pecl)
|
||||
if (function_exists('\Sodium\crypto_aead_aes256gcm_is_available') && \Sodium\crypto_aead_aes256gcm_is_available()) {
|
||||
return \Sodium\crypto_aead_aes256gcm_decrypt($ciphertext, $associatedData, $nonceStr, $aesKey);
|
||||
}
|
||||
// openssl (PHP >= 7.1 support AEAD)
|
||||
if (PHP_VERSION_ID >= 70100 && in_array('aes-256-gcm', \openssl_get_cipher_methods())) {
|
||||
$ctext = substr($ciphertext, 0, -self::AUTH_TAG_LENGTH_BYTE);
|
||||
$authTag = substr($ciphertext, -self::AUTH_TAG_LENGTH_BYTE);
|
||||
return \openssl_decrypt($ctext, 'aes-256-gcm', $aesKey, \OPENSSL_RAW_DATA, $nonceStr, $authTag, $associatedData);
|
||||
}
|
||||
} catch (\Exception $exception) {
|
||||
throw new InvalidArgumentException($exception->getMessage(), $exception->getCode());
|
||||
} catch (\SodiumException $exception) {
|
||||
throw new InvalidArgumentException($exception->getMessage(), $exception->getCode());
|
||||
}
|
||||
throw new InvalidArgumentException('AEAD_AES_256_GCM 需要 PHP 7.1 以上或者安装 libsodium-php');
|
||||
}
|
||||
}
|
||||
|
||||
68
crmeb/crmeb/services/easywechat/v3pay/Certficates.php
Normal file
68
crmeb/crmeb/services/easywechat/v3pay/Certficates.php
Normal file
@ -0,0 +1,68 @@
|
||||
<?php
|
||||
/**
|
||||
* +----------------------------------------------------------------------
|
||||
* | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
|
||||
* +----------------------------------------------------------------------
|
||||
* | Copyright (c) 2016~2022 https://www.crmeb.com All rights reserved.
|
||||
* +----------------------------------------------------------------------
|
||||
* | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
|
||||
* +----------------------------------------------------------------------
|
||||
* | Author: CRMEB Team <admin@crmeb.com>
|
||||
* +----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
namespace crmeb\services\easywechat\v3pay;
|
||||
|
||||
|
||||
use crmeb\exceptions\PayException;
|
||||
use think\facade\Cache;
|
||||
|
||||
/**
|
||||
* Class Certficates
|
||||
* @package crmeb\services\easywechat\v3pay
|
||||
*/
|
||||
trait Certficates
|
||||
{
|
||||
|
||||
/**
|
||||
* @param string|null $key
|
||||
* @return array|mixed|null
|
||||
* @throws \Psr\SimpleCache\InvalidArgumentException
|
||||
*/
|
||||
public function getCertficatescAttr(string $key = null)
|
||||
{
|
||||
$driver = Cache::store('file');
|
||||
$cacheKey = '_wx_v3' . $this->app['config']['v3_payment']['serial_no'];
|
||||
if ($driver->has($cacheKey)) {
|
||||
$res = $driver->get($cacheKey);
|
||||
if ($key && $res) {
|
||||
return $res[$key] ?? null;
|
||||
} else {
|
||||
return $res;
|
||||
}
|
||||
}
|
||||
$certficates = $this->getCertficates();
|
||||
$driver->set($cacheKey, $certficates, 3600 * 24 * 30);
|
||||
if ($key && $certficates) {
|
||||
return $certficates[$key] ?? null;
|
||||
}
|
||||
return $certficates;
|
||||
}
|
||||
|
||||
/**
|
||||
* get certficates.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getCertficates()
|
||||
{
|
||||
$response = $this->request('v3/certificates', 'GET', [], false);
|
||||
if (isset($response['code'])) {
|
||||
throw new PayException($response['message']);
|
||||
}
|
||||
$certificates = $response['data'][0];
|
||||
$certificates['certificates'] = $this->decrypt($certificates['encrypt_certificate']);
|
||||
unset($certificates['encrypt_certificate']);
|
||||
return $certificates;
|
||||
}
|
||||
}
|
||||
400
crmeb/crmeb/services/easywechat/v3pay/PayClient.php
Normal file
400
crmeb/crmeb/services/easywechat/v3pay/PayClient.php
Normal file
@ -0,0 +1,400 @@
|
||||
<?php
|
||||
/**
|
||||
* +----------------------------------------------------------------------
|
||||
* | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
|
||||
* +----------------------------------------------------------------------
|
||||
* | Copyright (c) 2016~2022 https://www.crmeb.com All rights reserved.
|
||||
* +----------------------------------------------------------------------
|
||||
* | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
|
||||
* +----------------------------------------------------------------------
|
||||
* | Author: CRMEB Team <admin@crmeb.com>
|
||||
* +----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
namespace crmeb\services\easywechat\v3pay;
|
||||
|
||||
|
||||
use crmeb\exceptions\PayException;
|
||||
|
||||
/**
|
||||
* v3支付
|
||||
* Class PayClient
|
||||
* @package crmeb\services\easywechat\v3pay
|
||||
*/
|
||||
class PayClient extends BaseClient
|
||||
{
|
||||
//app支付
|
||||
const API_APP_APY_URL = 'v3/pay/transactions/app';
|
||||
//二维码支付截图
|
||||
const API_NATIVE_URL = 'v3/pay/transactions/native';
|
||||
//h5支付接口
|
||||
const API_H5_URL = 'v3/pay/transactions/h5';
|
||||
//jsapi支付接口
|
||||
const API_JSAPI_URL = 'v3/pay/transactions/jsapi';
|
||||
//发起商家转账API
|
||||
const API_BATCHES_URL = 'v3/transfer/batches';
|
||||
//退款
|
||||
const API_REFUND_URL = 'v3/refund/domestic/refunds';
|
||||
//退款查询接口
|
||||
const API_REFUND_QUERY_URL = 'v3/refund/domestic/refunds/{out_refund_no}';
|
||||
|
||||
/**
|
||||
* 公众号jsapi支付下单
|
||||
* @param string $outTradeNo
|
||||
* @param string $total
|
||||
* @param string $description
|
||||
* @param string $attach
|
||||
* @return mixed
|
||||
*/
|
||||
public function jsapiPay(string $openid, string $outTradeNo, string $total, string $description, string $attach)
|
||||
{
|
||||
$appId = $this->app['config']['wechat']['appid'];
|
||||
$res = $this->pay('jsapi', $appId, $outTradeNo, $total, $description, $attach, ['openid' => $openid]);
|
||||
return $this->configForJSSDKPayment($appId, $res['prepay_id']);
|
||||
}
|
||||
|
||||
/**
|
||||
* 小程序支付
|
||||
* @param string $outTradeNo
|
||||
* @param string $total
|
||||
* @param string $description
|
||||
* @param string $attach
|
||||
* @return array|false|string
|
||||
*/
|
||||
public function miniprogPay(string $openid, string $outTradeNo, string $total, string $description, string $attach)
|
||||
{
|
||||
$appId = $this->app['config']['miniprog']['appid'];
|
||||
$res = $this->pay('jsapi', $appId, $outTradeNo, $total, $description, $attach, ['openid' => $openid]);
|
||||
return $this->configForJSSDKPayment($appId, $res['prepay_id']);
|
||||
}
|
||||
|
||||
/**
|
||||
* APP支付下单
|
||||
* @param string $outTradeNo
|
||||
* @param string $total
|
||||
* @param string $description
|
||||
* @param string $attach
|
||||
* @return mixed
|
||||
*/
|
||||
public function appPay(string $outTradeNo, string $total, string $description, string $attach)
|
||||
{
|
||||
$res = $this->pay('app', $this->app['config']['app']['appid'], $outTradeNo, $total, $description, $attach);
|
||||
return $this->configForAppPayment($res['prepay_id']);
|
||||
}
|
||||
|
||||
/**
|
||||
* native支付下单
|
||||
* @param string $outTradeNo
|
||||
* @param string $total
|
||||
* @param string $description
|
||||
* @param string $attach
|
||||
* @return mixed
|
||||
*/
|
||||
public function nativePay(string $outTradeNo, string $total, string $description, string $attach)
|
||||
{
|
||||
return $this->pay('native', $this->app['config']['web']['appid'], $outTradeNo, $total, $description, $attach);
|
||||
}
|
||||
|
||||
/**
|
||||
* h5支付下单
|
||||
* @param string $outTradeNo
|
||||
* @param string $total
|
||||
* @param string $description
|
||||
* @param string $attach
|
||||
* @return mixed
|
||||
*/
|
||||
public function h5Pay(string $outTradeNo, string $total, string $description, string $attach)
|
||||
{
|
||||
return $this->pay('h5', $this->app['config']['wechat']['appid'], $outTradeNo, $total, $description, $attach);
|
||||
}
|
||||
|
||||
/**
|
||||
* 下单
|
||||
* @param string $type
|
||||
* @param string $appid
|
||||
* @param string $outTradeNo
|
||||
* @param string $total
|
||||
* @param string $description
|
||||
* @param string $attach
|
||||
* @param array $payer
|
||||
* @return mixed
|
||||
*/
|
||||
public function pay(string $type, string $appid, string $outTradeNo, string $total, string $description, string $attach, array $payer = [])
|
||||
{
|
||||
$totalFee = (int)bcmul($total, '100');
|
||||
|
||||
$data = [
|
||||
'appid' => $appid,
|
||||
'mchid' => $this->app['config']['v3_payment']['mchid'],
|
||||
'out_trade_no' => $outTradeNo,
|
||||
'attach' => $attach,
|
||||
'description' => $description,
|
||||
'notify_url' => $this->app['config']['v3_payment']['notify_url'],
|
||||
'amount' => [
|
||||
'total' => $totalFee,
|
||||
'currency' => 'CNY'
|
||||
],
|
||||
];
|
||||
|
||||
if ($payer) {
|
||||
$data['payer'] = $payer;
|
||||
}
|
||||
|
||||
$url = '';
|
||||
switch ($type) {
|
||||
case 'h5':
|
||||
$url = self::API_H5_URL;
|
||||
$data['scene_info'] = [
|
||||
'payer_client_ip' => request()->ip(),
|
||||
'h5_info' => [
|
||||
'type' => 'Wap'
|
||||
]
|
||||
];
|
||||
break;
|
||||
case 'native':
|
||||
$url = self::API_NATIVE_URL;
|
||||
break;
|
||||
case 'app':
|
||||
$url = self::API_APP_APY_URL;
|
||||
break;
|
||||
case 'jsapi':
|
||||
$url = self::API_JSAPI_URL;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!$url) {
|
||||
throw new PayException('缺少请求地址');
|
||||
}
|
||||
|
||||
$res = $this->request($url, 'POST', ['json' => $data]);
|
||||
|
||||
if (!$res) {
|
||||
throw new PayException('微信支付:下单失败');
|
||||
}
|
||||
if (isset($res['code']) && isset($res['message'])) {
|
||||
throw new PayException($res['message']);
|
||||
}
|
||||
|
||||
return $res;
|
||||
}
|
||||
|
||||
/**
|
||||
* 发起商家转账API
|
||||
* @param string $outBatchNo
|
||||
* @param string $amount
|
||||
* @param string $batchName
|
||||
* @param string $remark
|
||||
* @param array $transferDetailList
|
||||
* @return mixed
|
||||
*/
|
||||
public function batches(string $outBatchNo, string $amount, string $batchName, string $remark, array $transferDetailList)
|
||||
{
|
||||
$totalFee = '0';
|
||||
|
||||
foreach ($transferDetailList as &$item) {
|
||||
if ($item['transfer_amount'] >= 2000 && !empty($item['user_name'])) {
|
||||
throw new PayException('明细金额大于等于2000时,收款人姓名必须填写');
|
||||
}
|
||||
$totalFee = bcadd($totalFee, $item['transfer_amount'], 2);
|
||||
$item['transfer_amount'] = (int)bcmul($item['transfer_amount'], 100, 0);
|
||||
if (isset($item['user_name'])) {
|
||||
$item['user_name'] = $this->encryptor($item['user_name']);
|
||||
}
|
||||
}
|
||||
|
||||
if ($totalFee !== $amount) {
|
||||
throw new PayException('转账明细金额总和和转账总金额不一致');
|
||||
}
|
||||
|
||||
$amount = (int)bcmul($amount, 100, 0);
|
||||
|
||||
$data = [
|
||||
'appid' => $this->app['config']['wechat']['appid'],
|
||||
'out_batch_no' => $outBatchNo,
|
||||
'batch_name' => $batchName,
|
||||
'batch_remark' => $remark,
|
||||
'total_amount' => $amount,
|
||||
'total_num' => count($transferDetailList),
|
||||
'transfer_detail_list' => $transferDetailList
|
||||
];
|
||||
|
||||
$res = $this->request(self::API_BATCHES_URL, 'POST', ['json' => $data]);
|
||||
|
||||
if (!$res) {
|
||||
throw new PayException('微信支付:发起商家转账失败');
|
||||
}
|
||||
|
||||
if (isset($res['code']) && isset($res['message'])) {
|
||||
throw new PayException($res['message']);
|
||||
}
|
||||
|
||||
return $res;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 退款
|
||||
* @param string $outTradeNo
|
||||
* @param array $options
|
||||
* @return mixed
|
||||
*/
|
||||
public function refund(string $outTradeNo, array $options = [])
|
||||
{
|
||||
if (!isset($options['pay_price'])) {
|
||||
throw new PayException(400730);
|
||||
}
|
||||
$totalFee = floatval(bcmul($options['pay_price'], 100, 0));
|
||||
$refundFee = isset($options['refund_price']) ? floatval(bcmul($options['refund_price'], 100, 0)) : null;
|
||||
$refundReason = $options['desc'] ?? '';
|
||||
$refundNo = $options['refund_id'] ?? $outTradeNo;
|
||||
/*仅针对老资金流商户使用
|
||||
REFUND_SOURCE_UNSETTLED_FUNDS---未结算资金退款(默认使用未结算资金退款)
|
||||
REFUND_SOURCE_RECHARGE_FUNDS---可用余额退款
|
||||
*/
|
||||
$refundAccount = $opt['refund_account'] ?? 'AVAILABLE';
|
||||
|
||||
$data = [
|
||||
'transaction_id' => $outTradeNo,
|
||||
'out_refund_no' => $refundNo,
|
||||
'amount' => [
|
||||
'refund' => (int)$refundFee,
|
||||
'currency' => 'CNY',
|
||||
'total' => (int)$totalFee
|
||||
],
|
||||
'funds_account' => $refundAccount
|
||||
];
|
||||
|
||||
if ($refundReason) {
|
||||
$data['reason'] = $refundReason;
|
||||
}
|
||||
|
||||
$res = $this->request(self::API_REFUND_URL, 'POST', ['json' => $data]);
|
||||
|
||||
if (!$res) {
|
||||
throw new PayException('微信支付:发起退款失败');
|
||||
}
|
||||
|
||||
if (isset($res['code']) && isset($res['message'])) {
|
||||
throw new PayException($res['message']);
|
||||
}
|
||||
|
||||
return $res;
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询退款
|
||||
* @param string $outRefundNo
|
||||
* @return mixed
|
||||
*/
|
||||
public function queryRefund(string $outRefundNo)
|
||||
{
|
||||
$res = $this->request($this->getApiUrl(self::API_REFUND_QUERY_URL, ['out_refund_no'], [$outRefundNo]), 'GET');
|
||||
|
||||
if (!$res) {
|
||||
throw new PayException(50001);
|
||||
}
|
||||
|
||||
if (isset($res['code']) && isset($res['message'])) {
|
||||
throw new PayException($res['message']);
|
||||
}
|
||||
|
||||
return $res;
|
||||
}
|
||||
|
||||
/**
|
||||
* jsapi支付
|
||||
* @param string $appid
|
||||
* @param string $prepayId
|
||||
* @param bool $json
|
||||
* @return array|false|string
|
||||
*/
|
||||
public function configForPayment(string $appid, string $prepayId, bool $json = true)
|
||||
{
|
||||
$params = [
|
||||
'appId' => $appid,
|
||||
'timeStamp' => strval(time()),
|
||||
'nonceStr' => uniqid(),
|
||||
'package' => "prepay_id=$prepayId",
|
||||
'signType' => 'RSA',
|
||||
];
|
||||
$message = $params['appId'] . "\n" .
|
||||
$params['timeStamp'] . "\n" .
|
||||
$params['nonceStr'] . "\n" .
|
||||
$params['package'] . "\n";
|
||||
openssl_sign($message, $raw_sign, $this->getPrivateKey(), 'sha256WithRSAEncryption');
|
||||
$sign = base64_encode($raw_sign);
|
||||
|
||||
$params['paySign'] = $sign;
|
||||
|
||||
return $json ? json_encode($params) : $params;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate app payment parameters.
|
||||
* @param string $prepayId
|
||||
* @return array
|
||||
*/
|
||||
public function configForAppPayment(string $prepayId): array
|
||||
{
|
||||
$params = [
|
||||
'appid' => $this->app['config']['app']['appid'],
|
||||
'partnerid' => $this->app['config']['v3_payment']['mchid'],
|
||||
'prepayid' => $prepayId,
|
||||
'noncestr' => uniqid(),
|
||||
'timestamp' => time(),
|
||||
'package' => 'Sign=WXPay',
|
||||
];
|
||||
$message = $params['appid'] . "\n" .
|
||||
$params['timestamp'] . "\n" .
|
||||
$params['noncestr'] . "\n" .
|
||||
$params['prepayid'] . "\n";
|
||||
openssl_sign($message, $raw_sign, $this->getPrivateKey(), 'sha256WithRSAEncryption');
|
||||
$sign = base64_encode($raw_sign);
|
||||
|
||||
$params['sign'] = $sign;
|
||||
|
||||
return $params;
|
||||
}
|
||||
|
||||
/**
|
||||
* 小程序支付
|
||||
* @param string $appid
|
||||
* @param string $prepayId
|
||||
* @return array|false|string
|
||||
*/
|
||||
public function configForJSSDKPayment(string $appid, string $prepayId)
|
||||
{
|
||||
$config = $this->configForPayment($appid, $prepayId, false);
|
||||
|
||||
$config['timestamp'] = $config['timeStamp'];
|
||||
unset($config['timeStamp']);
|
||||
|
||||
return $config;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $callback
|
||||
* @return \think\Response
|
||||
*/
|
||||
public function handleNotify($callback)
|
||||
{
|
||||
$request = request();
|
||||
$success = $request->post('event_type') === 'TRANSACTION.SUCCESS';
|
||||
$data = $this->decrypt($request->post('resource', []));
|
||||
|
||||
$handleResult = call_user_func_array($callback, [json_decode($data), $success]);
|
||||
if (is_bool($handleResult) && $handleResult) {
|
||||
$response = [
|
||||
'code' => 'SUCCESS',
|
||||
'message' => 'OK',
|
||||
];
|
||||
} else {
|
||||
$response = [
|
||||
'code' => 'FAIL',
|
||||
'message' => $handleResult,
|
||||
];
|
||||
}
|
||||
|
||||
return response($response, 200, [], 'json');
|
||||
}
|
||||
}
|
||||
36
crmeb/crmeb/services/easywechat/v3pay/ServiceProvider.php
Normal file
36
crmeb/crmeb/services/easywechat/v3pay/ServiceProvider.php
Normal file
@ -0,0 +1,36 @@
|
||||
<?php
|
||||
/**
|
||||
* +----------------------------------------------------------------------
|
||||
* | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
|
||||
* +----------------------------------------------------------------------
|
||||
* | Copyright (c) 2016~2022 https://www.crmeb.com All rights reserved.
|
||||
* +----------------------------------------------------------------------
|
||||
* | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
|
||||
* +----------------------------------------------------------------------
|
||||
* | Author: CRMEB Team <admin@crmeb.com>
|
||||
* +----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
namespace crmeb\services\easywechat\v3pay;
|
||||
|
||||
|
||||
use Pimple\Container;
|
||||
use Pimple\ServiceProviderInterface;
|
||||
|
||||
/**
|
||||
* Class ServiceProvider
|
||||
* @package crmeb\services\easywechat\v3pay
|
||||
*/
|
||||
class ServiceProvider implements ServiceProviderInterface
|
||||
{
|
||||
|
||||
/**
|
||||
* @param Container $pimple
|
||||
*/
|
||||
public function register(Container $pimple)
|
||||
{
|
||||
$pimple['v3pay'] = function ($pimple) {
|
||||
return new PayClient($pimple['access_token'], $pimple);
|
||||
};
|
||||
}
|
||||
}
|
||||
@ -110,11 +110,12 @@ class Express extends BaseExpress
|
||||
* @return 物流状态:status 0在途,1揽收,2疑难,3签收,4退签,5派件,6退回,7转单,10待清关,11清关中,12已清关,13清关异常,14收件人拒签
|
||||
* @return 物流详情 content
|
||||
*/
|
||||
public function query(string $num, string $com = '')
|
||||
public function query(string $num, string $com = '', $phone = '')
|
||||
{
|
||||
$param = [
|
||||
'com' => $com,
|
||||
'num' => $num
|
||||
'num' => $num,
|
||||
'phone' => $phone
|
||||
];
|
||||
if ($com === null) {
|
||||
unset($param['com']);
|
||||
@ -156,7 +157,7 @@ class Express extends BaseExpress
|
||||
}
|
||||
/** @var ExpressServices $expressServices */
|
||||
$expressServices = app()->make(ExpressServices::class);
|
||||
$expressData = $expressServices->getOneByWhere(['code'=>$param['com']])->toArray();
|
||||
$expressData = $expressServices->getOneByWhere(['code' => $param['com']])->toArray();
|
||||
if (isset($data['cargo'])) $param['cargo'] = $data['cargo'];
|
||||
if ($expressData['partner_id'] == 1) $param['partner_id'] = $expressData['account'];
|
||||
if ($expressData['partner_key'] == 1) $param['partner_key'] = $expressData['key'];
|
||||
|
||||
@ -14,6 +14,7 @@ namespace crmeb\services\pay;
|
||||
|
||||
use crmeb\basic\BaseManager;
|
||||
use crmeb\services\pay\storage\AliPay;
|
||||
use crmeb\services\pay\storage\V3WechatPay;
|
||||
use crmeb\services\pay\storage\WechatPay;
|
||||
use think\facade\Config;
|
||||
|
||||
@ -23,6 +24,7 @@ use think\facade\Config;
|
||||
* @package crmeb\services\pay
|
||||
* @mixin AliPay
|
||||
* @mixin WechatPay
|
||||
* @mixin V3WechatPay
|
||||
*/
|
||||
class Pay extends BaseManager
|
||||
{
|
||||
|
||||
@ -72,6 +72,6 @@ interface PayInterface
|
||||
* 支付回调
|
||||
* @return mixed
|
||||
*/
|
||||
public static function handleNotify();
|
||||
public function handleNotify();
|
||||
|
||||
}
|
||||
|
||||
216
crmeb/crmeb/services/pay/storage/V3WechatPay.php
Normal file
216
crmeb/crmeb/services/pay/storage/V3WechatPay.php
Normal file
@ -0,0 +1,216 @@
|
||||
<?php
|
||||
/**
|
||||
* +----------------------------------------------------------------------
|
||||
* | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
|
||||
* +----------------------------------------------------------------------
|
||||
* | Copyright (c) 2016~2022 https://www.crmeb.com All rights reserved.
|
||||
* +----------------------------------------------------------------------
|
||||
* | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
|
||||
* +----------------------------------------------------------------------
|
||||
* | Author: CRMEB Team <admin@crmeb.com>
|
||||
* +----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
namespace crmeb\services\pay\storage;
|
||||
|
||||
use app\services\pay\PayNotifyServices;
|
||||
use app\services\wechat\WechatMessageServices;
|
||||
use crmeb\exceptions\PayException;
|
||||
use crmeb\services\app\MiniProgramService;
|
||||
use crmeb\services\easywechat\Application;
|
||||
use crmeb\services\pay\BasePay;
|
||||
use crmeb\services\pay\PayInterface;
|
||||
use crmeb\utils\Hook;
|
||||
use EasyWeChat\Payment\Order;
|
||||
use think\facade\Log;
|
||||
|
||||
/**
|
||||
* Class 微信支付v3
|
||||
* @author 等风来
|
||||
* @email 136327134@qq.com
|
||||
* @date 2022/9/22
|
||||
* @package crmeb\services\pay\storage
|
||||
*/
|
||||
class V3WechatPay extends BasePay implements PayInterface
|
||||
{
|
||||
|
||||
/**
|
||||
* @var Application
|
||||
*/
|
||||
protected $instance;
|
||||
|
||||
/**
|
||||
* @param array $config
|
||||
* @return mixed|void
|
||||
* @author 等风来
|
||||
* @email 136327134@qq.com
|
||||
* @date 2022/9/22
|
||||
*/
|
||||
protected function initialize(array $config = [])
|
||||
{
|
||||
$wechatAppid = sys_config('wechat_appid');
|
||||
$config = [
|
||||
'app' => [
|
||||
'appid' => sys_config('wechat_app_appid'),
|
||||
],
|
||||
'wechat' => [
|
||||
'appid' => $wechatAppid,
|
||||
],
|
||||
'miniprog' => [
|
||||
'appid' => sys_config('routine_appId'),
|
||||
],
|
||||
'web' => [
|
||||
'appid' => sys_config('wechat_open_app_id', $wechatAppid),
|
||||
],
|
||||
'v3_payment' => [
|
||||
'mchid' => sys_config('pay_weixin_mchid'),
|
||||
'key' => sys_config('pay_weixin_key_v3'),
|
||||
'serial_no' => sys_config('pay_weixin_serial_no'),
|
||||
'cert_path' => public_path() . $this->getPemPath(sys_config('pay_weixin_client_cert')),
|
||||
'key_path' => public_path() . $this->getPemPath(sys_config('pay_weixin_client_key')),
|
||||
'notify_url' => trim(sys_config('site_url')) . '/api/wechat/v3notify',
|
||||
]
|
||||
];
|
||||
$this->instance = new Application($config);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取证书不带域名的路径
|
||||
* @param string $path
|
||||
* @return mixed|string
|
||||
* @author 等风来
|
||||
* @email 136327134@qq.com
|
||||
* @date 2022/9/22
|
||||
*/
|
||||
public function getPemPath(string $path)
|
||||
{
|
||||
if (strstr($path, 'http://') === false && strstr($path, 'https://') === false) {
|
||||
return $path;
|
||||
} else {
|
||||
$res = parse_url($path);
|
||||
return $res['path'] ?? '';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建订单返回支付参数
|
||||
* @param string $orderId
|
||||
* @param string $totalFee
|
||||
* @param string $attach
|
||||
* @param string $body
|
||||
* @param string $detail
|
||||
* @param array $options
|
||||
* @return array|false|mixed|string
|
||||
* @author 等风来
|
||||
* @email 136327134@qq.com
|
||||
* @date 2022/9/22
|
||||
*/
|
||||
public function create(string $orderId, string $totalFee, string $attach, string $body, string $detail, array $options = [])
|
||||
{
|
||||
$this->authSetPayType();
|
||||
|
||||
switch ($this->payType) {
|
||||
case Order::NATIVE:
|
||||
$res = $this->instance->v3pay->nativePay($orderId, $totalFee, $body, $attach);
|
||||
$res['invalid'] = time() + 60;
|
||||
$res['logo'] = sys_config('wap_login_logo');
|
||||
return $res;
|
||||
case Order::APP:
|
||||
return $this->instance->v3pay->appPay($orderId, $totalFee, $body, $attach);
|
||||
case Order::JSAPI:
|
||||
if (empty($options['openid'])) {
|
||||
throw new PayException('缺少openid');
|
||||
}
|
||||
if (request()->isRoutine()) {
|
||||
// 获取配置 判断是否为新支付
|
||||
if ($options['pay_new_weixin_open']) {
|
||||
return MiniProgramService::newJsPay($options['openid'], $orderId, $totalFee, $attach, $body, $detail, $options);
|
||||
}
|
||||
return $this->instance->v3pay->miniprogPay($options['openid'], $orderId, $totalFee, $body, $attach);
|
||||
}
|
||||
return $this->instance->v3pay->jsapiPay($options['openid'], $orderId, $totalFee, $body, $attach);
|
||||
case 'h5':
|
||||
return $this->instance->v3pay->h5Pay($orderId, $totalFee, $body, $attach);
|
||||
default:
|
||||
throw new PayException('微信支付:支付类型错误');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $openid
|
||||
* @param string $orderId
|
||||
* @param string $amount
|
||||
* @param array $options
|
||||
* @return mixed
|
||||
* @author 等风来
|
||||
* @email 136327134@qq.com
|
||||
* @date 2022/9/22
|
||||
*/
|
||||
public function merchantPay(string $openid, string $orderId, string $amount, array $options = [])
|
||||
{
|
||||
$res = $this->instance->v3pay->batches(
|
||||
$orderId,
|
||||
$amount,
|
||||
$options['batch_name'],
|
||||
$options['batch_remark'],
|
||||
[
|
||||
[
|
||||
'out_detail_no' => $orderId,
|
||||
'transfer_amount' => $amount,
|
||||
'transfer_remark' => $options['batch_remark'],
|
||||
'openid' => $openid
|
||||
]
|
||||
]
|
||||
);
|
||||
|
||||
return $res;
|
||||
}
|
||||
|
||||
/**
|
||||
* 发起退款
|
||||
* @param string $outTradeNo
|
||||
* @param array $options
|
||||
* @return mixed
|
||||
*/
|
||||
public function refund(string $outTradeNo, array $options = [])
|
||||
{
|
||||
return $this->instance->v3pay->refund($outTradeNo, $options);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询退款
|
||||
* @param string $outTradeNo
|
||||
* @param string|null $outRequestNo
|
||||
* @param array $other
|
||||
* @return mixed
|
||||
*/
|
||||
public function queryRefund(string $outTradeNo, string $outRequestNo = null, array $other = [])
|
||||
{
|
||||
return $this->instance->v3pay->queryRefund($outTradeNo);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed|\think\Response
|
||||
* @author 等风来
|
||||
* @email 136327134@qq.com
|
||||
* @date 2022/9/22
|
||||
*/
|
||||
public function handleNotify()
|
||||
{
|
||||
return $this->instance->v3pay->handleNotify(function ($notify, $successful) {
|
||||
Log::error('支付回调:' . json_encode($notify));
|
||||
if ($successful && isset($notify->out_trade_no)) {
|
||||
if (isset($notify->attach) && $notify->attach) {
|
||||
if (($count = strpos($notify->out_trade_no, '_')) !== false) {
|
||||
$notify->out_trade_no = substr($notify->out_trade_no, $count + 1);
|
||||
}
|
||||
return (new Hook(PayNotifyServices::class, 'wechat'))->listen($notify->attach, $notify->out_trade_no, $notify->transaction_id);
|
||||
}
|
||||
/** @var WechatMessageServices $wechatMessageService */
|
||||
$wechatMessageService = app()->make(WechatMessageServices::class);
|
||||
$wechatMessageService->setOnceMessage($notify, $notify->openid, 'payment_success', $notify->out_trade_no);
|
||||
return false;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -64,9 +64,8 @@ class WechatPay extends BasePay implements PayInterface
|
||||
}
|
||||
if (request()->isRoutine()) {
|
||||
// 获取配置 判断是否为新支付
|
||||
if($options['pay_new_weixin_open'])
|
||||
{
|
||||
return MiniProgramService::newJsPay($options['openid'], $orderId, $totalFee, $attach, $body, $detail,$options);
|
||||
if ($options['pay_new_weixin_open']) {
|
||||
return MiniProgramService::newJsPay($options['openid'], $orderId, $totalFee, $attach, $body, $detail, $options);
|
||||
}
|
||||
return MiniProgramService::jsPay($options['openid'], $orderId, $totalFee, $attach, $body, $detail);
|
||||
}
|
||||
@ -114,10 +113,9 @@ class WechatPay extends BasePay implements PayInterface
|
||||
if (isset($opt['wechat'])) {
|
||||
return WechatService::refund($outTradeNo, $refundNo, $totalFee, $refundFee, $opUserId, $refundReason, $type, $refundAccount);
|
||||
} else {
|
||||
if($opt['pay_new_weixin_open'])
|
||||
{
|
||||
if ($opt['pay_new_weixin_open']) {
|
||||
return MiniProgramService::miniRefund($outTradeNo, $totalFee, $refundFee, $opt);
|
||||
}else{
|
||||
} else {
|
||||
return MiniProgramService::refund($outTradeNo, $refundNo, $totalFee, $refundFee, $opUserId, $refundReason, $type, $refundAccount);
|
||||
}
|
||||
}
|
||||
@ -140,7 +138,7 @@ class WechatPay extends BasePay implements PayInterface
|
||||
* @return mixed|\Symfony\Component\HttpFoundation\Response
|
||||
* @throws \EasyWeChat\Core\Exceptions\FaultException
|
||||
*/
|
||||
public static function handleNotify()
|
||||
public function handleNotify()
|
||||
{
|
||||
return WechatService::handleNotify();
|
||||
}
|
||||
|
||||
@ -15057,7 +15057,7 @@ INSERT INTO `eb_lang_code` (`id`, `type_id`, `code`, `remarks`, `lang_explain`,
|
||||
(13530, 1, '账户充值', '账户充值', '账户充值', 0),
|
||||
(13531, 1, '佣金转入', '佣金转入', '佣金转入', 0),
|
||||
(13532, 1, '周榜', '周榜', '周榜', 0),
|
||||
(13533, 1, '月榜', '月榜', '周榜', 0),
|
||||
(13533, 1, '月榜', '月榜', '月榜', 0),
|
||||
(13534, 1, '周排行', '周排行', '周排行', 0),
|
||||
(13535, 1, '月排行', '月排行', '月排行', 0),
|
||||
(13536, 1, '语言切换', '语言切换', '语言切换', 0),
|
||||
@ -17418,7 +17418,7 @@ INSERT INTO `eb_lang_code` (`id`, `type_id`, `code`, `remarks`, `lang_explain`,
|
||||
(15888, 3, '账户充值', '账户充值', '賬戶充值', 0),
|
||||
(15889, 3, '佣金转入', '佣金转入', '佣金轉入', 0),
|
||||
(15890, 3, '周榜', '周榜', '周榜', 0),
|
||||
(15891, 3, '月榜', '月榜', '周榜', 0),
|
||||
(15891, 3, '月榜', '月榜', '月榜', 0),
|
||||
(15892, 3, '周排行', '周排行', '週排行', 0),
|
||||
(15893, 3, '月排行', '月排行', '月排行', 0),
|
||||
(15894, 3, '语言切换', '语言切换', '語言切換', 0),
|
||||
@ -25755,7 +25755,27 @@ INSERT INTO `eb_lang_code` (`id`, `type_id`, `code`, `remarks`, `lang_explain`,
|
||||
(24217, 10, '提醒付款通知', '提醒付款通知', 'Ghi nhớ thông báo thanh toán', 0),
|
||||
(24218, 10, '短信验证码', '短信验证码', 'Mã kiểm tra SMS', 0),
|
||||
(24219, 10, '到店自提', '到店自提', 'Tự rút lui', 0),
|
||||
(24220, 10, '快递配送', '快递配送', 'Name', 0);
|
||||
(24220, 10, '快递配送', '快递配送', 'Name', 0),
|
||||
(24221, 1, '退款发起查询失败', '退款发起失败', '微信支付:发起退款查询失败', 0),
|
||||
(24222, 2, '退款发起查询失败', '退款发起失败', 'WeChat payment: Failed to launch refund query', 0),
|
||||
(24223, 3, '退款发起查询失败', '退款发起失败', '微信支付:發起退款査詢失敗', 0),
|
||||
(24224, 4, '退款发起查询失败', '退款发起失败', 'Paiement Wechat: impossible dinitier la requête de remboursement', 0),
|
||||
(24225, 5, '退款发起查询失败', '退款发起失败', 'Pagamento WeChat: avvio della richiesta di rimborso non riuscito', 0),
|
||||
(24226, 6, '退款发起查询失败', '退款发起失败', 'WeChat Pay:返金照会の開始に失敗しました', 0),
|
||||
(24227, 7, '退款发起查询失败', '退款发起失败', '위챗페이: 환불 조회 실패', 0),
|
||||
(24228, 8, '退款发起查询失败', '退款发起失败', '', 0),
|
||||
(24229, 9, '退款发起查询失败', '退款发起失败', 'ล้มเหลวในการเริ่มต้นการสอบถามเกี่ยวกับการคืนเงิน', 0),
|
||||
(24230, 10, '退款发起查询失败', '退款发起失败', 'Dịch vụ WeChat: không thể khởi chạy yêu cầu hoàn to àn', 0),
|
||||
(24231, 1, '500000', '发起退款查询失败', '微信支付:发起退款查询失败', 1),
|
||||
(24232, 2, '500000', '发起退款查询失败', 'WeChat payment: Failed to launch refund query', 1),
|
||||
(24233, 3, '500000', '发起退款查询失败', '微信支付:發起退款査詢失敗', 1),
|
||||
(24234, 4, '500000', '发起退款查询失败', 'Paiement Wechat: impossible dinitier la requête de remboursement', 1),
|
||||
(24235, 5, '500000', '发起退款查询失败', 'Pagamento WeChat: avvio della richiesta di rimborso non riuscito', 1),
|
||||
(24236, 6, '500000', '发起退款查询失败', 'WeChat Pay:返金照会の開始に失敗しました', 1),
|
||||
(24237, 7, '500000', '发起退款查询失败', '위챗페이: 환불 조회 실패', 1),
|
||||
(24238, 8, '500000', '发起退款查询失败', '', 1),
|
||||
(24239, 9, '500000', '发起退款查询失败', 'ล้มเหลวในการเริ่มต้นการสอบถามเกี่ยวกับการคืนเงิน', 1),
|
||||
(24240, 10, '500000', '发起退款查询失败', 'Dịch vụ WeChat: không thể khởi chạy yêu cầu hoàn to àn', 1);
|
||||
|
||||
-- --------------------------------------------------------
|
||||
|
||||
@ -26140,24 +26160,25 @@ CREATE TABLE IF NOT EXISTS `eb_lang_type` (
|
||||
`status` tinyint(1) NOT NULL DEFAULT '0' COMMENT '1启用0禁用',
|
||||
`is_default` tinyint(1) NOT NULL DEFAULT '0' COMMENT '是否默认语言',
|
||||
`is_del` tinyint(1) NOT NULL DEFAULT '0' COMMENT '是否删除',
|
||||
PRIMARY KEY (`id`)
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `id` (`id`)
|
||||
) ENGINE=InnoDB AUTO_INCREMENT=11 DEFAULT CHARSET=utf8 COMMENT='语言类型';
|
||||
|
||||
--
|
||||
-- 转存表中的数据 `eb_lang_type`
|
||||
--
|
||||
|
||||
INSERT INTO `eb_lang_type` (`id`, `language_name`, `file_name`, `status`, `is_default`) VALUES
|
||||
(1, '中文', 'zh-CN', 1, 1),
|
||||
(2, '英文', 'en-US', 1, 0),
|
||||
(3, '繁体中文', 'zh-Hant', 1, 0),
|
||||
(4, '法语', 'fr-FR', 1, 0),
|
||||
(5, '意大利语', 'it-IT', 1, 0),
|
||||
(6, '日语', 'ja-JP', 1, 0),
|
||||
(7, '韩语', 'ko-KR', 1, 0),
|
||||
(8, '蒙古语', 'mn-MN', 1, 0),
|
||||
(9, '泰语', 'th-TH', 1, 0),
|
||||
(10, '越南语', 'vi-VN', 1, 0);
|
||||
INSERT INTO `eb_lang_type` (`id`, `language_name`, `file_name`, `status`, `is_default`, `is_del`) VALUES
|
||||
(1, '中文', 'zh-CN', 1, 1, 0),
|
||||
(2, '英文', 'en-US', 1, 0, 0),
|
||||
(3, '繁体中文', 'zh-Hant', 1, 0, 0),
|
||||
(4, '法语', 'fr-FR', 1, 0, 0),
|
||||
(5, '意大利语', 'it-IT', 1, 0, 0),
|
||||
(6, '日语', 'ja-JP', 1, 0, 0),
|
||||
(7, '韩语', 'ko-KR', 1, 0, 0),
|
||||
(8, '蒙古语', 'mn-MN', 1, 0, 0),
|
||||
(9, '泰语', 'th-TH', 1, 0, 0),
|
||||
(10, '越南语', 'vi-VN', 1, 0, 0);
|
||||
|
||||
-- --------------------------------------------------------
|
||||
|
||||
@ -32353,7 +32374,10 @@ INSERT INTO `eb_system_config` (`id`, `menu_name`, `type`, `input_type`, `config
|
||||
(409, 'pay_new_weixin_open', 'radio', 'input', 4, '0=>关闭\n1=>打开', 1, '', 0, 0, '0', '小程序支付管理', '小程序开发后台有支付管理的请打开此开关', 0, 1),
|
||||
(410, 'pay_new_weixin_mchid', 'text', 'input', 4, '', 1, '', 0, 0, '\"\"', '小程序支付商户号', '小程序开通支付管理生成的商户号', 0, 1),
|
||||
(411, 'system_comment_time', 'text', 'number', 27, '', 1, '', 100, 0, '\"0\"', '自动评价时间', '自动评价时间(天),0为不开启自动评价', 0, 1),
|
||||
(412, 'comment_content', 'text', 'input', 27, '', 1, '', 100, 0, '\"\\u6b64\\u7528\\u6237\\u672a\\u505a\\u8bc4\\u4ef7\"', '自动评价文字', '自动评价显示的评价文字', 0, 1);
|
||||
(412, 'comment_content', 'text', 'input', 27, '', 1, '', 100, 0, '\"\\u6b64\\u7528\\u6237\\u672a\\u505a\\u8bc4\\u4ef7\"', '自动评价文字', '自动评价显示的评价文字', 0, 1),
|
||||
(413, 'pay_wechat_type', 'radio', 'input', 4, '0=>v2\n1=>v3', 1, '', 0, 0, '0', '支付接口类型', '支付接口类型v2对应微信支付旧版v2支付。v3对应微信支付v3支付接口。支付证书可以通用一个。支付秘钥和v2旧版支付有区别', 10, 1),
|
||||
(414, 'pay_weixin_serial_no', 'text', 'input', 4, '', 1, '', 100, 0, '\"\"', '证书序列号', '「商户API证书」的「证书序列号」,可以在证书管理里面查看', 0, 1),
|
||||
(415, 'pay_weixin_key_v3', 'text', 'input', 4, '', 1, '', 100, 0, '\"\"', 'V3支付Key', 'V3支付秘钥', 0, 1);
|
||||
|
||||
-- --------------------------------------------------------
|
||||
|
||||
|
||||
12
crmeb/vendor/composer/installed.php
vendored
12
crmeb/vendor/composer/installed.php
vendored
@ -1,9 +1,9 @@
|
||||
<?php return array(
|
||||
'root' => array(
|
||||
'name' => 'topthink/think',
|
||||
'pretty_version' => 'dev-master',
|
||||
'version' => 'dev-master',
|
||||
'reference' => '13adf9a931c339ffb7910da803bf28c4ed4d1d9b',
|
||||
'pretty_version' => '4.6.0.x-dev',
|
||||
'version' => '4.6.0.9999999-dev',
|
||||
'reference' => '7894ca3eaf91b7c54ffb20443b7b0d51541546d3',
|
||||
'type' => 'project',
|
||||
'install_path' => __DIR__ . '/../../',
|
||||
'aliases' => array(),
|
||||
@ -764,9 +764,9 @@
|
||||
'dev_requirement' => false,
|
||||
),
|
||||
'topthink/think' => array(
|
||||
'pretty_version' => 'dev-master',
|
||||
'version' => 'dev-master',
|
||||
'reference' => '13adf9a931c339ffb7910da803bf28c4ed4d1d9b',
|
||||
'pretty_version' => '4.6.0.x-dev',
|
||||
'version' => '4.6.0.9999999-dev',
|
||||
'reference' => '7894ca3eaf91b7c54ffb20443b7b0d51541546d3',
|
||||
'type' => 'project',
|
||||
'install_path' => __DIR__ . '/../../',
|
||||
'aliases' => array(),
|
||||
|
||||
@ -105,11 +105,7 @@ class Application extends Container
|
||||
ServiceProviders\ShakeAroundServiceProvider::class,
|
||||
ServiceProviders\OpenPlatformServiceProvider::class,
|
||||
ServiceProviders\MiniProgramServiceProvider::class,
|
||||
ServiceProviders\CommentServiceProvider::class,
|
||||
\crmeb\services\easywechat\subscribe\ProgramProvider::class,
|
||||
\crmeb\services\easywechat\wechatlive\ProgramProvider::class,
|
||||
\crmeb\services\easywechat\Open3rd\ProgramProvider::class,
|
||||
\crmeb\services\easywechat\miniPayment\ServiceProvider::class
|
||||
ServiceProviders\CommentServiceProvider::class
|
||||
];
|
||||
|
||||
/**
|
||||
|
||||
2
crmeb/vendor/services.php
vendored
2
crmeb/vendor/services.php
vendored
@ -1,5 +1,5 @@
|
||||
<?php
|
||||
// This file is automatically generated at:2022-09-15 10:07:34
|
||||
// This file is automatically generated at:2022-09-20 16:14:20
|
||||
declare (strict_types = 1);
|
||||
return array (
|
||||
0 => 'think\\captcha\\CaptchaService',
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user